Scrollable Table

Horizontal and vertical scrolling for a table. Note: does not yet work in IE.

by fwait

HTML

<div class="scrollable-table-wrapper">
    <table id="TestTable">
        <thead></thead>
        <tbody></tbody>
        <tfoot></tfoot>
    </table>
</div>

SCSS

$hicolor: #fff;
$fgcolor: #000;
$bgcolor: #268;
$oddbg: #f3f3f3;
$evenbg: #ddd;

$cellPadding: 3px;
$cellWidth: 45px;
$rowHeight: 20px;
$height: 285px;
$width: 750px;

/* Coloration & Display Styles */
#TestTable {
    border-collapse: separate;
    
    thead, tfoot { z-index: 1 }
    tbody { z-index: 0; }
    
    tr {
        height: 20px;
    
        >th, >td {
            border-width: 1px;
            border-style: outset;
            height: $rowHeight; max-height: $rowHeight;

            width: $cellWidth; min-width: $cellWidth; max-width: $cellWidth;
            white-space: nowrap; overflow: hidden;
            padding: $cellPadding;
        }
        >th {
            background-color: $bgcolor;
            border-color: lighten($bgcolor, 10%) darken($bgcolor, 10%) darken($bgcolor, 10%) lighten($bgcolor, 10%);
            color: $hicolor;
            font-weight: bold;
        }
        >td { background-color: $hicolor; }
        &:nth-child(odd)>td {
            background-color: $oddbg;
            border-color: lighten($oddbg, 5%) darken($oddbg, 5%) darken($oddbg, 5%) lighten($oddbg, 5%);
        }
        &:nth-child(even)>td {
            background-color: $evenbg;
            border-color: lighten($evenbg, 5%) darken($evenbg, 5%) darken($evenbg, 5%) lighten($evenbg, 5%);
        }
    }
}

div.scrollable-table-wrapper {
    background: $bgcolor;
    border: 1px solid $bgcolor;
    display: inline-block;
    height: $height; min-height: $height; max-height: $height;
    width: $width;
    position: relative;
    overflow: hidden;
    padding: ($rowHeight + ($cellPadding * 2)) 0;
    
    table { position: static; }
    thead, tfoot { position: absolute;    }
    thead { left: 0; top: 0; }
    tfoot { left: 0; bottom: 0; }
    tbody { 
        display: block;
        position: relative; overflow-y: scroll;
        height: $height - 2;
        width: $width;
    }
}

JavaScript

$(function() {
    var $table = $('#TestTable');
    var $thead = $table.find('thead');
    var $tbody = $table.find('tbody');
    var $tfoot = $table.find('tfoot');
    
    if (!$thead.length)
        $thead = $('<thead />').prependTo($table);
    if (!$tbody.length)
        $tbody = $('<tbody />').insertAfter($thead);
    if (!$tfoot.length)
        $tfoot = $('<tfoot />').insertAfter($tbody);

    var $hrow = $('<tr />').appendTo($thead);
    var $frow = $('<tr />').appendTo($tfoot);
    
    for (var row = 0; row < 2; row++)
        $tbody.append($('<tr />'));
    
    var $brow = $tbody.find('tr');
    
    for (var col = 0; col < 2; col++) {
        $('<th />').html('Hdr'+col)
            .appendTo($hrow);
        $('<td />').html('Val'+col)
            .appendTo($brow);
        $('<th />').html('Ftr'+col)
            .appendTo($frow);
    }
    
    $brow.each(function(ix, el) {
        $(el).children().first().html('R:'+ix);
    });
    
    $tbody.bind('scroll', function(ev) {
        var $css = { 'left': -ev.target.scrollLeft };
        $thead.css($css);
        $tfoot.css($css);
    });
});