52

I need to display a large table on a web page and need to prevent the first column and first row from scrolling. I'd like to dynamically set the vertical size of this table (between some static size header/footer page content) to make it as tall as possible without forcing the browser window to have a vertical scrollbar.

   browser window\/
+--------------------------------------------------------------+  /\
|   /\     /\  /\         /\       /\      /\     /\ /\        |  fixed static
|    web page header fields and text                           |  |  size
|   \/    \/   \/         \/       \/     \/     \/   \/       |__\/__
|               +----<<<table-scrollbar>>>>>----------------+  |  /\
|+--------------+--------+--------+--------+--------+-------+  |   |
||              |        |colspan |        |        | fixed |  |   |
||  fixed       |  fixed |  fixed | fixed  |  fixed | more> |  |   |
|+--------------+--+--+--+---+----+--+--+--+--------+-------++ |   |
||  fixed       |  |  |  |   |    |  |  |  |        |       || |   |
|+--------------+--+--+--+---+----+--+--+--+--------+-------+t |   |
||  fixed       |  |  |  |   |    |  |  |  |        |       |a |   |
|+--------------+--+--+--+---+----+--+--+--+--------+-------+b |   |
||  fixed       |  |  |  |   |    |  |  |  |        |       |l |   |
|+--------------+--+--+--+---+----+--+--+--+--------+-------+e |   set
||  fixed       |  |  |  |   |    |  |  |  |        |       || |   dynamic
||  multi-line  |  |  |  |   |    |  |  |  |        |       |s |   size at
|+--------------+--+--+--+---+----+--+--+--+--------+-------+c |   runtime
||  fixed       |  |  |  |   |    |  |  |  |        |       |r |   |
|+--------------+--+--+--+---+----+--+--+--+--------+-------+o |   |
||  fixed       |  |  |  |   |    |  |  |  |        |       |l |   |
|+--------------+--+--+--+---+----+--+--+--+--------+-------+l |   |
||  fixed       |  |  |  |   |    |  |  |  |        |       |b |   |
||              |  |  |  |   |    |  |  |  |        |       |a 
|+--------------+--+--+--+---+----+--+--+--+--------+-------+r |   |
|| fixed, moreV |  |  |  |   |    |  |  |  |        |       || |   |
|+--------------+--+--+--+---+----+--+--+--+--------+-------++ |__\/__
|   /\     /\  /\         /\       /\      /\     /\ /\        |  /\
|    web page footer fields and text                           |  fixed static
|   \/    \/   \/         \/       \/     \/     \/   \/       |  |  size
+--------------------------------------------------------------+  \/

this only needs to work in modern browsers, using all/any: html, css, javascript, jquery

order of importance:

  • complex table with many form fields, hidden values, javascript collapsing of rows, etc. which I'll add later
  • 1st row will have colspans
  • rows will have variable height
  • 1st row: fixed from vertical scroll, but can scroll horizontally
  • 1st column: fixed from horizontal scroll, but can scroll vertical
  • dynamically size this "table" to fill the screen between the static size header/footer html
  • location of the scroll bars (as depicted in my awesome ascii art above) isn't critical.

here is a very basic html sample of the screen, without any of the scroll/sizing features:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>big scrolling table example</TITLE>
</HEAD>

<BODY>
  <form name="MyForm" method="POST" action="">
    <!-- static size header junk--><!-- static size header junk--><!-- static size header junk-->
    <table border="1" width="100%" cellspacing="1" cellpadding="0" align="center">
    <tr>
    <td width="35%" align="left">header junk left</td>
    <td >- HEADER JUNK MIDDLE -</td>
    <td width="35%" align="right">header junk right</td>
    </tr>
    </table>
    <br>
    <table border="0" width="95%" cellspacing="1" cellpadding="0" align="center">
    <tr>
    <td width="60%" align="left">header junk left</td>
    <td width="40%" align="right">check it out! <input type="checkbox" onchange="alert('your javascript here');" value="Y" name="checkitout"></td>
    </tr>


    <!-- big table here!!--><!-- big table here!!--><!-- big table here!!--><!-- big table here!!-->

    <table border="1" width="95%" cellspacing="1" cellpadding="0" align="center">
    <tr>
    <td>fixed can be long<br>or short</td>
    <td colspan="4">scroll A</td>
    <td colspan="2">scroll B</td>
    <td >scroll C</td>
    <td colspan="4">scroll D</td>
    <td colspan="2">scroll E</td>
    <td >scroll F</td>
    <td colspan="4">scroll G</td>
    <td colspan="2">scroll H</td>
    <td >scroll I</td>
    <td colspan="4">scroll J</td>
    <td colspan="2">scroll K</td>
    <td >scroll L</td>
    <td colspan="4">scroll M</td>
    <td colspan="2">scroll N</td>
    <td >scroll O</td>
    </tr>

    <tr>
        <td>fixed 2</td>
        <td>1 1 1 1 1 A</td><td>2 2 2 2 2 A</td><td>3 3 3 3 3 A</td><td>4 4 4 4 4 A</td>
        <td>1 B</td><td>2 B</td>
        <td >1 C</td>
        <td>1 D</td><td>2 D</td><td>3 D</td><td>4 D<br>more...</td>
        <td>1 E</td><td>2 E</td>
        <td >1 F</td>
        <td>1 1 1 G</td><td>2 2 G</td><td>3 G</td><td>4 4 4 4 G</td>
        <td>1 H</td><td>222 H</td>
        <td >1 I</td>
        <td>1 J</td><td>2 J</td><td>3 J</td><td>4 J</td>
        <td>1 K</td><td>2 2 K<br>more..<br>more..</td>
        <td >1 L</td>
        <td>1 M</td><td>22 M</td><td>333 M</td><td>4444 M</td>
        <td>1 N</td><td>2 N</td>
        <td >1 1 1 1 1 1 1 O</td>
    </tr>
    <tr>
        <td>fixed 3</td>
        <td>1 1 1 1 1 A</td><td>2 2 2 2 2 A</td><td>3 3 3 3 3 A</td><td>4 4 4 4 4 A</td>
        <td>1 B</td><td>2 B</td>
        <td >1 C</td>
        <td>1 D</td><td>2 D</td><td>3 D</td><td>4 D<br>more...</td>
        <td>1 E</td><td>2 E</td>
        <td >1 F</td>
        <td>1 1 1 G</td><td>2 2 G</td><td>3 G</td><td>4 4 4 4 G</td>
        <td>1 H</td><td>222 H</td>
        <td >1 I</td>
        <td>1 J</td><td>2 J</td><td>3 J</td><td>4 J</td>
        <td>1 K</td><td>2 2 K<br>more..<br>more..</td>
        <td >1 L</td>
        <td>1 M</td><td>22 M</td><td>333 M</td><td>4444 M</td>
        <td>1 N</td><td>2 N</td>
        <td >1 1 1 1 1 1 1 O</td>
    </tr>
    <tr>
        <td>fixed 4</td>
        <td>1 1 1 1 1 A</td><td>2 2 2 2 2 A</td><td>3 3 3 3 3 A</td><td>4 4 4 4 4 A</td>
        <td>1 B</td><td>2 B</td>
        <td >1 C</td>
        <td>1 D</td><td>2 D</td><td>3 D</td><td>4 D<br>more...<br>more...<br>more...<br>more...</td>
        <td>1 E</td><td>2 E</td>
        <td >1 F</td>
        <td>1 1 1 G</td><td>2 2 G</td><td>3 G</td><td>4 4 4 4 G</td>
        <td>1 H</td><td>222 H</td>
        <td >1 I</td>
        <td>1 J</td><td>2 J</td><td>3 J</td><td>4 J</td>
        <td>1 K</td><td>2 2 K<br>more..<br>more..</td>
        <td >1 L</td>
        <td>1 M</td><td>22 M</td><td>333 M</td><td>4444 M</td>
        <td>1 N</td><td>2 N</td>
        <td >1 1 1 1 1 1 1 O</td>
    </tr>
    <tr>
        <td>fixed 5</td>
        <td>1 1 1 1 1 A</td><td>2 2 2 2 2 A</td><td>3 3 3 3 3 A</td><td>4 4 4 4 4 A</td>
        <td>1 B</td><td>2 B</td>
        <td >1 C</td>
        <td>1 D</td><td>2 D</td><td>3 D</td><td>4 D<br>more...</td>
        <td>1 E</td><td>2 E</td>
        <td >1 F</td>
        <td>1 1 1 G</td><td>2 2 G</td><td>3 G</td><td>4 4 4 4 G</td>
        <td>1 H</td><td>222 H<br>H<br>H<br>H<br>H</td>
        <td >1 I</td>
        <td>1 J</td><td>2 J</td><td>3 J</td><td>4 J</td>
        <td>1 K</td><td>2 2 K<br>more..<br>more..</td>
        <td >1 L</td>
        <td>1 M</td><td>22 M</td><td>333 M</td><td>4444 M</td>
        <td>1 N</td><td>2 N</td>
        <td >1 1 1 1 1 1 1 O</td>
    </tr>
    <tr>
        <td>fixed 6<br>6<br>6<br>6</td>
        <td>1 1 1 1 1 A</td><td>2 2 2 2 2 A</td><td>3 3 3 3 3 A</td><td>4 4 4 4 4 A</td>
        <td>1 B</td><td>2 B</td>
        <td >1 C</td>
        <td>1 D</td><td>2 D</td><td>3 D</td><td>4 D<br>more...</td>
        <td>1 E</td><td>2 E</td>
        <td >1 F</td>
        <td>1 1 1 G</td><td>2 2 G</td><td>3 G</td><td>4 4 4 4 G</td>
        <td>1 H</td><td>222 H</td>
        <td >1 I</td>
        <td>1 J</td><td>2 J</td><td>3 J</td><td>4 J</td>
        <td>1 K</td><td>2 2 K<br>more..<br>more..</td>
        <td >1 L</td>
        <td>1 M</td><td>22 M</td><td>333 M</td><td>4444 M</td>
        <td>1 N</td><td>2 N</td>
        <td >1 1 1 1 1 1 1 O</td>
    </tr>

    </table>


    <!-- static size footer junk--><!-- static size footer junk--><!-- static size footer junk--><!-- static size footer junk-->
    <table border="1" width="100%" cellspacing="1" cellpadding="0" align="center">
    <tr>
    <td width="35%" align="left">footer junk left</td>
    <td >- FOOTER JUNK MIDDLE -</td>
    <td width="35%" align="right">footer junk right</td>
    </tr>

  </form>
</BODY>
</HTML>
C R
  • 2,182
  • 5
  • 32
  • 41
KM.
  • 101,727
  • 34
  • 178
  • 212
  • It is either fixed column or fixed row. Having both seems to have drawbacks and it simply doesn't look good. – Selvakumar Arumugam Jun 05 '12 at 20:11
  • @vega, it is both fixed first column and fixed first row. What are the drawbacks? Looks aren't the primary focus here, this is a internal corporate application with many pages full of ugly tables, it must be functional. I have a large database driven application, where I need to display lots of form fields for many (variable number) rows and columns. breaking the screen up so there is less data shown results in to many page hops/clicks/wasted time/etc. The [jsfiddle](http://jsfiddle.net/J53ax/) example from eggyal looks very promising. Try it out, the screen scrolls very intuitively for me. – KM. Jun 05 '12 at 20:54
  • My code is kinda final now, please check it out and give feedback of wether it fulfills your needs and how it can be improved. – oxygen Jun 06 '12 at 22:02
  • Here, I applied it to your test code (btw u are missing a for "header junk left"): http://kakao.ro/public/Tables/KM.fullpage.html and http://kakao.ro/public/Tables/KM.overflow_scroll.html – oxygen Jun 06 '12 at 22:38
  • @KM. Created a DEMO >> http://jsfiddle.net/rKjk3/21/embedded/result/ << Check it out and let me know how it looks. [Orig Post](http://stackoverflow.com/a/10922732/297641) – Selvakumar Arumugam Jun 07 '12 at 17:07

6 Answers6

35

Edit 5: - Added configurable fixed Rows and Columns. - Fixed column width and height issues - Reduced usage of complex selectors

Usage:

    $('#cTable').cTable({
        width: 1300,  
        height: 500,  
        fCols: 2,
        fRows: 2
    });

DEMO: http://jsfiddle.net/rCuPf/7/embedded/result/ (updated demo)

Edit 4: Updated for colSpan on column 1. Demo: http://jsfiddle.net/skram/rKjk3/26/

Edit 3: Did some cleanup and some fixes: http://jsfiddle.net/rKjk3/22 Tested in IE9, FF and Chrome. (I don't have latest IE to test it now)

Edit 2: Fix for IE: http://jsfiddle.net/rKjk3/15/embedded/result/ (See latest above)

Edit 1: Fix for resize window http://jsfiddle.net/rKjk3/11/ (See latest above)

  • Added window.resize event handler to set the width of the rightContainer so the width of actual table will be increased as you resize.
  • Removed fixed width on SBWrapper so that it can fully utilize the available space inside the container.

I have created 2 demo for your requirement.

  1. Sample to show how the rendered html will look like with a simple markup structure. This will allow you to look at the structure that is being rendered and how it is working :)
    DEMO: http://jsfiddle.net/GmJ22/7/

  2. Actual demo with the markup that you have posted. The code is just a rough version and may require some cleanup. Right now you can configure the width and height of the table. I am posting it so that you can take a look and give me some feedback.
    DEMO: http://jsfiddle.net/rKjk3/10/embedded/result/ (see below fixed versions)

Full code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<HTML>
<HEAD>
<TITLE>big scrolling table example</TITLE>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
    $(function() {
        $.fn.cTable = function(o) {        

            this.wrap('<div class="cTContainer" />');
            this.wrap('<div class="relativeContainer" />');    
            //Update below template as how you have it in orig table
            var origTableTmpl = '<table border="1" cellspacing="1" cellpadding="0" align="center" width="95%" ></table>';            
            //get row 1 and clone it for creating sub tables
            var row1 = this.find('tr').slice(0, o.fRows).clone();

            var r1c1ColSpan = 0;
            for (var i = 0; i < o.fCols; i++ ) {
                r1c1ColSpan += this[0].rows[0].cells[i].colSpan;
            }

            //create table with just r1c1 which is fixed for both scrolls
            var tr1c1 = $(origTableTmpl);
            row1.each(function () {            
                var tdct = 0;
                $(this).find('td').filter( function () {
                    tdct += this.colSpan;
                    return tdct > r1c1ColSpan;
                }).remove();                
            });
            row1.appendTo(tr1c1);
            tr1c1.wrap('<div class="fixedTB" />');
            tr1c1.parent().prependTo(this.closest('.relativeContainer'));

            //create a table with just c1        
            var c1= this.clone().prop({'id': ''});
            c1.find('tr').slice(0, o.fRows).remove();
            c1.find('tr').each(function (idx) {
                var c = 0;
                $(this).find('td').filter(function () {
                    c += this.colSpan;
                    return c > r1c1ColSpan;
                }).remove();           
            });

            var prependRow = row1.first().clone();
            prependRow.find('td').empty();
            c1.prepend(prependRow).wrap('<div class="leftSBWrapper" />')
            c1.parent().wrap('<div class="leftContainer" />');            
            c1.closest('.leftContainer').insertAfter('.fixedTB');

            //create table with just row 1 without col 1
            var r1 = $(origTableTmpl);
            row1 = this.find('tr').slice(0, o.fRows).clone();
            row1.each(function () {
                var tds = $(this).find('td'), tdct = 0;
                tds.filter (function () {
                    tdct += this.colSpan;
                    return tdct <= r1c1ColSpan;
                }).remove();
            });
            row1.appendTo(r1);
            r1.wrap('<div class="topSBWrapper" />')
            r1.parent().wrap('<div class="rightContainer" />')  
            r1.closest('.rightContainer').appendTo('.relativeContainer');

            $('.relativeContainer').css({'width': 'auto', 'height': o.height});

            this.wrap('<div class="SBWrapper"> /')        
            this.parent().appendTo('.rightContainer');    
            this.prop({'width': o.width});    

            var tw = 0;
            //set width and height of rendered tables
            for (var i = 0; i < o.fCols; i++) {
                tw += $(this[0].rows[0].cells[i]).outerWidth(true);
            }
            tr1c1.width(tw);
            c1.width(tw);

            $('.rightContainer').css('left', tr1c1.outerWidth(true));

            for (var i = 0; i < o.fRows; i++) {
                var tr1c1Ht = $(c1[0].rows[i]).outerHeight(true);
                var thisHt = $(this[0].rows[i]).outerHeight(true);
                var finHt = (tr1c1Ht > thisHt)?tr1c1Ht:thisHt;
                $(tr1c1[0].rows[i]).height(finHt);
                $(r1[0].rows[i]).height(finHt);
            }
            $('.leftContainer').css({'top': tr1c1.outerHeight(true), 'width': tr1c1.outerWidth(true)});

            var rtw = $('.relativeContainer').width() - tw;
            $('.rightContainer').css({'width' : rtw, 'height': o.height, 'max-width': o.width - tw});    

            var trs = this.find('tr');
            trs.slice(1, o.fRows).remove();
            trs.slice(0, 1).find('td').empty();
            trs.each(function () {
                var c = 0;
                $(this).find('td').filter(function () {
                    c += this.colSpan;
                    return c <= r1c1ColSpan;
                }).remove();
            });

            r1.width(this.outerWidth(true));

            for (var i = 1; i < c1[0].rows.length; i++) {
                var c1Ht = $(c1[0].rows[i]).outerHeight(true);
                var thisHt = $(this[0].rows[i]).outerHeight(true);
                var finHt = (c1Ht > thisHt)?c1Ht:thisHt;
                $(c1[0].rows[i]).height(finHt);
                $(this[0].rows[i]).height(finHt);
            }

            $('.SBWrapper').css({'height': $('.relativeContainer').height() - $('.topSBWrapper').height()});            

            $('.SBWrapper').scroll(function () {
                var rc = $(this).closest('.relativeContainer');
                var lfW = rc.find('.leftSBWrapper');
                var tpW = rc.find('.topSBWrapper');

                lfW.css('top', ($(this).scrollTop()*-1));
                tpW.css('left', ($(this).scrollLeft()*-1));        
            });

            $(window).resize(function () {
                $('.rightContainer').width(function () {
                    return $(this).closest('.relativeContainer').outerWidth() - $(this).siblings('.leftContainer').outerWidth();
                });

            });
        }

        $('#cTable').cTable({
            width: 1300,
            height: 500,
            fCols: 2,
            fRows: 2
        });
    });
</script>
<style>
    .cTContainer { overflow: hidden; padding: 2px; }
    .cTContainer table { table-layout: fixed; }
    .relativeContainer { position: relative; overflow: hidden;}    
    .fixedTB { position: absolute; z-index: 11;  }
    .leftContainer { position: absolute; overflow: hidden;  }
    .rightContainer { position: absolute; overflow: hidden;  }
    .leftSBWrapper { position: relative; z-index: 10; }
    .topSBWrapper { position: relative; z-index: 10; width: 100%; }
    .SBWrapper { width: 100%; overflow: auto; }

    td { background-color: white; overflow: hidden; padding: 1px; }    
</style>
</HEAD>
<BODY>
  <form name="MyForm" method="POST" action="">
    <table border="1" width="100%" cellspacing="1" cellpadding="0" align="center">
        <tr>
        <td width="35%" align="left">header junk left</td>
        <td >- HEADER JUNK MIDDLE -</td>
        <td width="35%" align="right">header junk right</td>
        </tr>
    </table>
    <br />
    <table border="0" width="95%" cellspacing="1" cellpadding="0" align="center">
        <tr>
        <td width="60%" align="left">header junk left</td>
        <td width="40%" align="right">check it out! <input type="checkbox" onchange="alert('your javascript here');" value="Y" name="checkitout"></td>
        </tr>
    </table>

    <!-- big table here!!--><!-- big table here!!--><!-- big table here!!--><!-- big table here!!-->
    <table border="1" width="95%" cellspacing="1" cellpadding="0" align="center" id="cTable" >
        <tr>
            <td width="5%" colspan="3">fixed can be long<br>or short</td>
            <td width="9%" colspan="4">scroll A</td>
            <td width="7%" colspan="2">scroll B</td>
            <td width="3%">scroll C</td>
            <td width="9%" colspan="4">scroll D</td>
            <td width="7%" colspan="2">scroll E</td>
            <td width="3%">scroll F</td>
            <td width="9%" colspan="4">scroll G</td>
            <td width="7%" colspan="2">scroll H</td>
            <td width="3%">scroll I</td>
            <td width="9%" colspan="4">scroll J</td>
            <td width="7%" colspan="2">scroll K</td>
            <td width="3%">scroll L</td>
            <td width="9%" colspan="4">scroll M</td>
            <td width="7%" colspan="2">scroll N</td>
            <td width="3%">scroll O</td>
        </tr>
        <tr>
            <td width="5%" colspan="3">2nd fixed header</td>
            <td width="9%" colspan="4">scroll 2A</td>
            <td width="7%">scroll 2B-1</td>
            <td width="7%">scroll 2B-2 </td>
            <td width="3%">scroll 2C</td>
            <td width="9%" colspan="4">scroll 2D</td>
            <td width="7%" colspan="2">scroll 2E</td>
            <td width="3%">scroll 2F</td>
            <td width="9%" colspan="4">scroll 2G</td>
            <td width="7%" colspan="2">scroll 2H</td>
            <td width="3%">scroll 2I</td>
            <td width="9%" colspan="4">scroll 2J</td>
            <td width="7%" colspan="2">scroll 2K</td>
            <td width="3%">scroll 2L</td>
            <td width="9%" colspan="4">scroll 2M</td>
            <td width="7%" colspan="2">scroll 2N</td>
            <td width="3%">scroll 2O</td>
        </tr>
        <tr>
            <td>2</td>
            <td>2</td>
            <td>2</td>
            <td>1 1 1 1 1 A</td>
            <td>2 2 2 2 2 A</td>
            <td>3 3 3 3 3 A</td>
            <td>4 4 4 4 4 A</td>
            <td>1 B</td>
            <td>2 B</td>
            <td >1 C</td>
            <td>1 D</td>
            <td>2 D</td>
            <td>3 D</td>
            <td>4 D<br>more...</td>
            <td>1 E</td>
            <td>2 E</td>
            <td >1 F</td>
            <td>1 1 1 G</td>
            <td>2 2 G</td>
            <td>3 G</td>
            <td>4 4 4 4 G</td>
            <td>1 H</td>
            <td>222 H</td>
            <td >1 I</td>
            <td>1 J</td>
            <td>2 J</td>
            <td>3 J</td>
            <td>4 J</td>
            <td>1 K</td>
            <td>2 2 K<br>more..<br>more..</td>
            <td >1 L</td>
            <td>1 M</td>
            <td>22 M</td>
            <td>333 M</td>
            <td>4444 M</td>
            <td>1 N</td>
            <td>2 N</td>
            <td >1 1 1 1 1 1 1 O</td>
        </tr>
        <tr>
            <td colspan="2">fixed 3</td>
            <td>3</td>
            <td>1 1 1 1 1 A</td><td>2 2 2 2 2 A</td><td>3 3 3 3 3 A</td><td>4 4 4 4 4 A</td>
            <td>1 B</td><td>2 B</td>
            <td >1 C</td>
            <td>1 D</td><td>2 D</td><td>3 D</td><td>4 D<br>more...</td>
            <td>1 E</td><td>2 E</td>
            <td >1 F</td>
            <td>1 1 1 G</td><td>2 2 G</td><td>3 G</td><td>4 4 4 4 G</td>
            <td>1 H</td><td>222 H</td>
            <td >1 I</td>
            <td>1 J</td><td>2 J</td><td>3 J</td><td>4 J</td>
            <td>1 K</td><td>2 2 K<br>more..<br>more..</td>
            <td >1 L</td>
            <td>1 M</td><td>22 M</td><td>333 M</td><td>4444 M</td>
            <td>1 N</td><td>2 N</td>
            <td >1 1 1 1 1 1 1 O</td>
        </tr>
        <tr>
            <td colspan="3">fixed 4</td>
            <td>1 1 1 1 1 A</td><td>2 2 2 2 2 A</td><td>3 3 3 3 3 A</td><td>4 4 4 4 4 A</td>
            <td>1 B</td><td>2 B</td>
            <td >1 C</td>
            <td>1 D</td><td>2 D</td><td>3 D</td><td>4 D<br>more...<br>more...<br>more...<br>more...</td>
            <td>1 E</td><td>2 E</td>
            <td >1 F</td>
            <td>1 1 1 G</td><td>2 2 G</td><td>3 G</td><td>4 4 4 4 G</td>
            <td>1 H</td><td>222 H</td>
            <td >1 I</td>
            <td>1 J</td><td>2 J</td><td>3 J</td><td>4 J</td>
            <td>1 K</td><td>2 2 K<br>more..<br>more..</td>
            <td >1 L</td>
            <td>1 M</td><td>22 M</td><td>333 M</td><td>4444 M</td>
            <td>1 N</td><td>2 N</td>
            <td >1 1 1 1 1 1 1 O</td>
        </tr>
        <tr>
            <td colspan="3">fixed 5</td>
            <td>1 1 1 1 1 A</td><td>2 2 2 2 2 A</td><td>3 3 3 3 3 A</td><td>4 4 4 4 4 A</td>
            <td>1 B</td><td>2 B</td>
            <td >1 C</td>
            <td>1 D</td><td>2 D</td><td>3 D</td><td>4 D<br>more...</td>
            <td>1 E</td><td>2 E</td>
            <td >1 F</td>
            <td>1 1 1 G</td><td>2 2 G</td><td>3 G</td><td>4 4 4 4 G</td>
            <td>1 H</td><td>222 H<br>H<br>H<br>H<br>H</td>
            <td >1 I</td>
            <td>1 J</td><td>2 J</td><td>3 J</td><td>4 J</td>
            <td>1 K</td><td>2 2 K<br>more..<br>more..</td>
            <td >1 L</td>
            <td>1 M</td><td>22 M</td><td>333 M</td><td>4444 M</td>
            <td>1 N</td><td>2 N</td>
            <td >1 1 1 1 1 1 1 O</td>
        </tr>
        <tr>
            <td>6</td>
            <td>6</td>
            <td>6</td>
            <td>1 1 1 1 1 A</td><td>2 2 2 2 2 A</td><td>3 3 3 3 3 A</td><td>4 4 4 4 4 A</td>
            <td>1 B</td><td>2 B</td>
            <td >1 C</td>
            <td>1 D</td><td>2 D</td><td>3 D</td><td>4 D<br>more...</td>
            <td>1 E</td><td>2 E</td>
            <td >1 F</td>
            <td>1 1 1 G</td><td>2 2 G</td><td>3 G</td><td>4 4 4 4 G</td>
            <td>1 H</td><td>222 H</td>
            <td >1 I</td>
            <td>1 J</td><td>2 J</td><td>3 J</td><td>4 J</td>
            <td>1 K</td><td>2 2 K<br>more..<br>more..</td>
            <td >1 L</td>
            <td>1 M</td><td>22 M</td><td>333 M</td><td>4444 M</td>
            <td>1 N</td><td>2 N</td>
            <td >1 1 1 1 1 1 1 O</td>
        </tr>
    </table>
    <br />
    <!-- static size footer junk--><!-- static size footer junk--><!-- static size footer junk--><!-- static size footer junk-->
    <table border="1" width="100%" cellspacing="1" cellpadding="0" align="center">
        <tr>
        <td width="35%" align="left">footer junk left</td>
        <td >- FOOTER JUNK MIDDLE -</td>
        <td width="35%" align="right">footer junk right</td>
        </tr>
    </table>
</form>
</BODY>
</HTML>
Selvakumar Arumugam
  • 79,297
  • 15
  • 120
  • 134
  • when I go to jsfiddle.net I can see the demo, but how do I cut/paste that code into a local file? also which one should I look at "1. demo" or "edit 3"? – KM. Jun 08 '12 at 21:10
  • @KM. Copying the whole HTML so you can just copy/paste in your local. Let me know what you think.. – Selvakumar Arumugam Jun 08 '12 at 21:20
  • @KM., when you right mouse-click the jsFiddle **HTML Results Section** on the white background, click **This Frame** then **View Frame Source** in Firefox to then have a ready to use HTML file that includes the jsFiddle HTML, CSS, and JavaScript within that file. For **Chrome**, you will automatically see **View Frame Source** that you can then save and use locally/on server. – arttronics Jun 09 '12 at 21:32
  • thanks. I will need to customize this more, but this is a good starting point! – KM. Jun 11 '12 at 12:38
  • @KM. Thanks and let me know if you need any customization. – Selvakumar Arumugam Jun 11 '12 at 14:18
  • @vega, I'm trying to merge this with my code, but I'm running into a problem, my 1st column (the fixed column) has a colspan="3" any way to incorporate this? – KM. Jun 11 '12 at 15:52
  • @KM. Can you post that html.. there are 2 ways I can work on this.. 1. Work on your specific HTML to fix the problem (can be solved quickly, but may end up changing code for different scenario) 2. Work on my code to identify such case and handle.. (which may take sometime). – Selvakumar Arumugam Jun 11 '12 at 16:14
  • @KM. Updated code, post and the DEMO links for the colSpan on column 1. – Selvakumar Arumugam Jun 11 '12 at 16:38
  • is it possible to fix scroll the first two rows? – KM. Jun 12 '12 at 20:46
  • @KM. I have fixed scroll for n rows and n cols.. works fine in FF and Chrome.. having some height issues in IE 8. >> http://jsfiddle.net/skram/rKjk3/27/ << Also had made bunch of updates to fix the width and height.. Let me know how it looks.. the rows and cols can be configured. `$('#cTable').cTable({ width: 1300, height: 500, fCols: 2, fRows: 2 });`. I was thinking of updating the post after testing in IE 9. – Selvakumar Arumugam Jun 12 '12 at 20:49
  • it work great in FF, but in IE 9, I get `Message: 'console' is undefined Line: 51 Char: 21 Code: 0` this is the view source line: `console.log(tdct + ' ' + r1c1ColSpan);` – KM. Jun 13 '12 at 19:47
  • @KM. Kill that line plz.. it was just debug.. See updated post for latest code. – Selvakumar Arumugam Jun 13 '12 at 20:36
  • I'm trying to control the width of the columns but its not always working. The table has a `width="GGGpx"` and I'm putting `width="NNNpx"` in each TD in the first row, NNN is calculated based on the colspans and other things and GGGpx is the sum of all NNN values. Only each TD in the first row has a width, they are all in PX. When there are just a few columns, I'm seeing all the columns wider than the NNNpx, it seems proportional where everything is greatly stretched wider than the desired PX which forces scrolling when not needed. any ideas? When there are lots of columns it works great. – KM. Jun 29 '12 at 15:24
  • @KM. Were you able to tally each column width with the total width? Can you post a sample in fiddle, where I can take a look. – Selvakumar Arumugam Jun 29 '12 at 17:21
  • @Selvakumar Arumugam Hello, I know that this is an old thread, I was wondering how this would work if I needed to apply it to 2 or more tables? – CK1 Jan 31 '18 at 20:08
15

I agree with @FedericoGiust's answer; but since you asked for more detail...

<script type="text/javascript"
        src="http://code.jquery.com/jquery-1.7.2.min.js">
</script>
<script type="text/javascript"
        src="http://datatables.net/download/build/jquery.dataTables.min.js">
</script>
<script type="text/javascript"
        src="http://datatables.net/download/build/FixedColumns.min.js">
</script>
<script type="text/javascript">
  $(document).ready(function() {
    var oTable = $('#bigtable').dataTable({
        "sScrollY": "300px",  // set vertical size dynamically here
        "sScrollX": "100%",
        "bPaginate": false,
        "bFilter": false
    });
    new FixedColumns(oTable);
  });​
</script>

You need to add a row of dummy column headers so that Datatables will cope with the colspans.

See it on jsfiddle.

Community
  • 1
  • 1
eggyal
  • 122,705
  • 18
  • 212
  • 237
  • I'm attempting to try out your solution, however I can't get it to work with my table. The difference that I'm having problems with is that I now have 3 fixed columns on the left and not just one. I have various rows where I colspan these 3 fixed columns like: .. or .... or just ....... any ideas how to get this to work? – KM. Jul 31 '12 at 20:36
11

You can use DataTables

DataTables

It's an amazing jquery plugin for tables, and it also has an interesting number of extras and plugins including fixed header and footer, column sorting, variable width, fixed width, ajax and lots more.

Federico Giust
  • 1,803
  • 4
  • 20
  • 45
  • Apparently it can't do multiline, when using a left fixed header, and relies on a style of fixed height per row to match rows. And it alters the document a lot. – oxygen Jun 06 '12 at 21:50
  • 1
    @Tiberiu-IonuțStan: Have you looked at the fiddle in my answer? I'm not sure what you mean by either of those two criticisms? – eggyal Jun 08 '12 at 05:37
  • Yes I have, I didn't invent my criticism. – oxygen Jun 08 '12 at 09:13
  • @Tiberiu-IonuțStan The way to do multilines is with the expand row [Expand Row Example](http://datatables.net/release-datatables/examples/api/row_details.html) – Federico Giust Jun 08 '12 at 09:25
  • 1
    Well that is consistent with my "alters the document a lot" regard, and close enough to "it can't do multiline" since that is not what the question's author asked for (the author also stated he wants form elements in cells - who knows, maybe he will even have validation errors under them, or textareas - a normal HTML table handles all of the question requirements much better). – oxygen Jun 08 '12 at 09:28
9

Works with normal tables and it only alters the header cells, in place (no removing, copying, or outside of table element injection). This has the advantage to allow any content, in any cell, of any dimensions (+allows dynamic modification of that content).

See it in action: fullpage.html, overflow_scroll.html, fullpage_untouched.html.

Vertical and horizontal th cells should remain visible and aligned while scrolling.

This solution does not use any frameworks. Feel free to replace existing helpers (scroll offsets) using jquery or prototype (or any other framework).

You should add code hooks to call _table_make_fixed_header_reposition when making dynamic changes to the table's contents.

I didn't test this on Windows XP (where accelerated rendering is absent in all browsers).

The blue background, drop shadow, borders, etc. are just CSS cool stuff. You can make this however you want, and you just have to create a normal table (just add cell styles on .DivWrapper instead of TH).

<!DOCTYPE html>
<body>
    <head>
        <style>
            .TableLarge td, .TableLarge th{
                border-style: solid;
                border-width: 1px;

                border-color: #CAE3EF;

                padding: 7px;
                white-space: nowrap;
                font-family: Verdana;
                font-size: 10px;
            }

            .TableLarge{
                border-style: none;
                border-collapse: collapse;
            }

            #padding_for_test{
                height: 3000px;
                width: 9000px;
            }

        </style>
        <script type="text/javascript">
            function table_make_fixed_header(elTable, bHorizontal, bVertical, nRepositionIntervalMilliseconds, bWrappedByScrollableDiv)
            {
                if(!bHorizontal && !bVertical)
                    return;

                if(!elTable.id)
                    elTable.id="FixedVH_Headers_"+(new Date().getTime())+Math.floor(Math.random()*10000000);

                var zIndex=1;
                if(window.getComputedStyle)
                    zIndex=parseInt(window.getComputedStyle(elTable))?parseInt(window.getComputedStyle(elTable))+1:1;

                var fnSetupHeaderCell=function(elCell, zIndex)
                {
                    var elDivWrapper=document.createElement("div");

                    elDivWrapper.setAttribute("style", "-moz-box-shadow: 3px 3px 4px #aaaaaa; -webkit-box-shadow: 3px 3px 4px #aaaaaa; box-shadow: 3px 3px 4px #aaaaaa;");
                    elDivWrapper.style.zIndex=zIndex;
                    elDivWrapper.style.backgroundColor="#0000ee";
                    elDivWrapper.style.color="white";
                    elDivWrapper.style.padding="3px";

                    elDivWrapper.className="DivWrapper";
                    elDivWrapper.style.position="relative";

                    while(elCell.childNodes.length)
                        elDivWrapper.appendChild(elCell.childNodes[0]);
                    elCell.appendChild(elDivWrapper);
                };

                if(bVertical)
                    for(var r=bHorizontal?1:0; r<elTable.rows.length; r++)
                        fnSetupHeaderCell(elTable.rows[r].cells[0], zIndex);
                if(bHorizontal)
                    for(var c=bVertical?1:0; c<elTable.rows[0].cells.length; c++)
                        fnSetupHeaderCell(elTable.rows[0].cells[c], zIndex);

                _table_make_fixed_header_reposition(elTable.id, bHorizontal, bVertical, bWrappedByScrollableDiv);

                //this could be CPU intensive, depending on the number of events fired and size of the table.
                var onScrollEventHandler=function(ev){
                    _table_make_fixed_header_reposition(elTable.id, bHorizontal, bVertical, bWrappedByScrollableDiv);
                };

                var elScrollable=bWrappedByScrollableDiv?elTable.parentNode:window;
                if(elScrollable.addEventListener)
                    elScrollable.addEventListener('scroll', onScrollEventHandler, false);
                else if (elScrollable.attachEvent)
                    elScrollable.attachEvent('scroll', onScrollEventHandler);

                //this is undesired for performance reasons, hooks and event listeners are prefered instead.
                if(nRepositionIntervalMilliseconds>0)
                    setInterval("_table_make_fixed_header_reposition('"+elTable.id+"', "+(bHorizontal?"true":"false")+", "+(bVertical?"true":"false")+", "+(bWrappedByScrollableDiv?"true":"false")+")", nRepositionIntervalMilliseconds);
            }

            function _table_make_fixed_header_reposition(strTableID, bHorizontal, bVertical, bWrappedByScrollableDiv)
            {
                var elTable=document.getElementById(strTableID);

                var strLeft;
                var strTop;
                if(bWrappedByScrollableDiv)
                {
                    strLeft=Math.min(Math.max(elTable.parentNode.scrollLeft-elTable.offsetLeft+elTable.parentNode.offsetLeft, 0), elTable.offsetWidth)+"px";
                    strTop=Math.min(Math.max(elTable.parentNode.scrollTop-elTable.offsetTop+elTable.parentNode.offsetTop, 0), elTable.offsetHeight)+"px";
                }
                else
                {
                    strLeft=Math.min(Math.max(f_scrollLeft()-elTable.offsetLeft, 0), elTable.offsetWidth)+"px";
                    strTop=Math.min(Math.max(f_scrollTop()-elTable.offsetTop, 0), elTable.offsetHeight)+"px";
                }

                if(bVertical)
                    for(var r=bHorizontal?1:0; r<elTable.rows.length; r++)
                        elTable.rows[r].cells[0].childNodes[0].style.left=strLeft;
                if(bHorizontal)
                    for(var c=bVertical?1:0; c<elTable.rows[0].cells.length; c++)
                        elTable.rows[0].cells[c].childNodes[0].style.top=strTop;
            }


            //http://www.softcomplex.com/docs/get_window_size_and_scrollbar_position.html
            function f_scrollLeft(){
                return f_filterResults (
                    window.pageXOffset ? window.pageXOffset : 0,
                    document.documentElement ? document.documentElement.scrollLeft : 0,
                    document.body ? document.body.scrollLeft : 0
                );
            }
            function f_scrollTop() {
                return f_filterResults (
                    window.pageYOffset ? window.pageYOffset : 0,
                    document.documentElement ? document.documentElement.scrollTop : 0,
                    document.body ? document.body.scrollTop : 0
                );
            }
            function f_filterResults(n_win, n_docel, n_body) {
                var n_result = n_win ? n_win : 0;
                if (n_docel && (!n_result || (n_result > n_docel)))
                    n_result = n_docel;
                return n_body && (!n_result || (n_result > n_body)) ? n_body : n_result;
            }


            //you should add an event handler for onload here
        </script>
    </head>
    <body>
        <p>
            Vertical and horizontal th cells should remain visible and aligned while scrolling.<br>
            This solution does not use any frameworks. Feel free to replace existing helpers (scroll offsets) using jquery or prototype (or any other framework).
        </p>

        <div style="width: 800px; height: 600px; overflow: scroll">
            <table class="TableLarge" id="mySpecialHugeTable">
                <tr>
                    <th>Fixed!</th>
                    <th>Fixed!</th>
                    <th>Fixed!</th>
                    <th>Fixed!</th>
                    <th>Fixed!</th>
                    <th>Fixed!</th>
                    <th>Fixed!</th>
                    <th>Fixed!</th>
                    <th>Fixed!</th>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Umm...how is this done again?</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>Umm...how is this done again?</td>
                    <td>Umm...how is this done again?</td>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>This is a very short story...Real short.</td>
                </tr>
                <tr>
                    <th>Fixed!<br>multi-line</th>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>The goose is pretty.</td>
                    <td>The goose is pretty.</td>
                    <td>Umm...how is this done again?</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>Umm...how is this done again?</td>
                    <td>The goose is pretty.</td>
                    <td>The goose is pretty.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>Hello world!</td>
                    <td>Hello world!</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Umm...how is this done again?</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>The goose is pretty.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>The goose is pretty.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>Hello world!</td>
                    <td>Umm...how is this done again?</td>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>This is a very short story...Real short.</td>
                </tr>
                <tr>
                    <th>Fixed!<br>multi-line</th>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>The goose is pretty.</td>
                    <td>The goose is pretty.</td>
                    <td>Umm...how is this done again?</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>Umm...how is this done again?</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>Hello world!</td>
                    <td>Umm...how is this done again?</td>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>This is a very short story...Real short.</td>
                </tr>
                <tr>
                    <th>Fixed!<br>multi-line</th>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>Hello world!</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>The goose is pretty.</td>
                    <td>Umm...how is this done again?</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>Umm...how is this done again?</td>
                    <td>The goose is pretty.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>Hello world!</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Umm...how is this done again?</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>The goose is pretty.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>The goose is pretty.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Umm...how is this done again?</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>The goose is pretty.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Umm...how is this done again?</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>Umm...how is this done again?</td>
                    <td>Umm...how is this done again?</td>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>This is a very short story...Real short.</td>
                </tr>
                <tr>
                    <th>Fixed!<br>multi-line</th>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>The goose is pretty.</td>
                    <td>The goose is pretty.</td>
                    <td>Umm...how is this done again?</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>Umm...how is this done again?</td>
                    <td>The goose is pretty.</td>
                    <td>The goose is pretty.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>Hello world!</td>
                    <td>Hello world!</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Umm...how is this done again?</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>The goose is pretty.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>The goose is pretty.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>Umm...how is this done again?</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>Hello world!</td>
                    <td>Umm...how is this done again?</td>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>This is a very short story...Real short.</td>
                </tr>
                <tr>
                    <th>Fixed!<br>multi-line</th>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>The goose is pretty.</td>
                    <td>The goose is pretty.</td>
                    <td>Umm...how is this done again?</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>Umm...how is this done again?</td>
                    <td>The goose is pretty.</td>
                    <td>The goose is pretty.</td>
                    <td>This is a very short story...Real short.</td>
                    <td>Hello world!</td>
                    <td>Hello world!</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>The goose is pretty.</td>
                    <td>The goose is pretty.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>The goose is pretty.</td>
                    <td>Umm...how is this done again?</td>
                    <td>Hello world!</td>
                    <td>This is a very short story...Real short.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                </tr>
                <tr>
                    <th>Fixed!</th>
                    <td>The goose is pretty.</td>
                    <td>Hello world!</td>
                    <td>Hello world!</td>
                    <td>Umm...how is this done again?</td>
                    <td>My mother has apples.</td>
                    <td>My mother has apples.</td>
                    <td>I think Javascript is some kind of Voodoo on the DOM.</td>
                    <td>This is a very short story...Real short.</td>
                </tr>
            </table>
        </div>

        <div id="padding_for_test">&nbsp;</div>

        <script type="text/javascript">
            table_make_fixed_header(document.getElementById("mySpecialHugeTable"), /*bHorizontal*/ true, /*bVertical*/ true, 1000, /*bWrappedByScrollableDiv*/ true);
        </script>
    </body>
</html>

It should be fairly easy to delete some CSS and make the fixed cells identical to scrollable cells. Also if you want a dedicated scrollbar, you could wrap this in a scrollable DIV and adjust inside _table_make_fixed_header_reposition by using the DIV's scroll offsets too.

Edit: updated code to keep headers as close to edge as possible, when table goes outside the viewport (+option to choose between vertical or horizontal headers, or both).

Edit2: added scrollable div support, and made this the default in the example.

oxygen
  • 5,891
  • 6
  • 37
  • 69
  • 1
    Added the javascript code as-is to one of my projects (a complex large table), and it works well. – oxygen Jun 06 '12 at 19:40
  • This is a realy simple working code, easy to adapt to everything. Thanks! – Saic Siquot Feb 19 '16 at 17:26
  • 1
    Here's the latest version: https://ctrl.bigstep.com/website/classes/JavaScript/JSkippy/TableHeaders/table_headers.js https://ctrl.bigstep.com/website/classes/JavaScript/JSkippy/TableHeaders/table_headers.css – oxygen Feb 19 '16 at 17:28
  • Thank you Tiberiu. Please remove `margin-top: 55px !important;` from css rules as it alters table in a inapropiate manner and may confuse somebody. Your code is great !!!! – Saic Siquot Feb 20 '16 at 21:57
  • Yeah, that's a hack for that specific website, as it has a fixed header menu (the logo and all that) – oxygen Feb 20 '16 at 22:00
6

If you'd rather not go with a plugin, combine fixed header vertical scrolling (CSS)

tbody{display:block;overflow-y:auto;/*+fixed height set w/jQuery etc*/}

​with the fixed first column horizontal scrolling (JS)

$('#table-container').scroll(function() {
    var _left = $(this).scrollLeft();
    $('#table th').css('left', _left); //"stick" the first column to viewport
});

#table-container{overflow-x:scroll;/*+fixed width set*/}
thead, tbody{display:block;}    
th {position:relative;left:0;/*gets adjusted with JS above*/}

Fiddle'd here, this does not address resizing to fit browser dimensions though. Assuming it will be run in a dedicated window, it would be fairly trivial; if not and it's intended to be run in-page, it would be rather tough keeping it uncluttered.

Good luck.

Oleg
  • 24,465
  • 8
  • 61
  • 91
  • This is a really nice, almost entirely CSS solution, although it seems to suffer from fragmentation on the left hand side when moving quickly, and the v-scroll is not visible unless you scroll all the way to the right – tonycoupland Oct 10 '12 at 08:02
  • @o.v. you know that this never worked properly on Firefox(from year 2000)? – HellBaby May 16 '14 at 12:49
3

If you don't like to use heavy loaded plugins you could do:

Create a table with only the fixed table header

Create a div with fixed width (remember the scrollbar width) and height and set scrolling Y direction. Within this div you place the body of the table.

Create the 3th and last table and place the table below the div to make it look like 1 big table.

<table> HEADER </table>
<div><table> BODY </table></div> (div is scrollable)
<table> Foot </table>

If you need to make changes dynamicly use bare javascript, you don't need to use jquery or other heavy plugin.

Greezer
  • 515
  • 2
  • 4
  • 18