2

I have table like this: http://jsfiddle.net/A34tH/1/

             <table id="fixed_hdr2">
       <thead>
       <tr>
       <th colspan="5" rowspan="2"></th>
       <th colspan="31">december</th></tr>
        <tr>
                  <th>mon</th><th>th</th><th>we</th><th>tu</th><th>fr</th><th>sa</th><th>mon</th>        <th>th</th><th>we</th><th>tu</th><th>fr</th><th>sa</th><th>mon</th><th>th</th><th>we</th><th>tu</th><th>fr</th><th>sa</th><th>mon</th><th>th</th><th>we</th><th>tu</th><th>fr</th><th>sa</th><th>mon</th><th>th</th> 
    </tr>   
                 <tr>
        <th>#</th>
        <th>#</th>
        <th>#</th>
        <th>#</th>
        <th>#</th>
        <th>02</th><th>03</th><th>04</th><th>05</th><th>06</th><th>07</th><th>09</th><th>10</th>        <th>11</th><th>12</th><th>13</th><th>14</th><th>16</th><th>17</th><th>18</th><th>19</th><th>20</th><th>21</th><th>23</th><th>24</th><th>25</th><th>26</th><th>27</th><th>28</th>    <th>30</th><th>31</th> 
        </tr>   
    </thead>
[...]
    <table>

I need to see first 3 rows and 5 columns always visible. Real table is bigger (more rows and cols). When You scroll such big table, You can't control headers (left and top) so working with table is horrible. Tried a lot of solutions to fix headers (above). None of them is not working properly with my table (I think problem is in colspan and rowspan. Some of them act almost but headers are shifted.

Does anyone know any solution to control the table headers? I'm out of ideas.

Tested:

Community
  • 1
  • 1
Peter222
  • 154
  • 1
  • 16
  • What do you want to be done with the `test` row? – Zach Saucier Dec 09 '13 at 23:11
  • test row is part of scrollable data, it repeats like this http://jsfiddle.net/A34tH/3/. I need only see forst 5 columns and 3 rows like here: https://drive.google.com/file/d/0Bxc5r6H_-OovbVBFUjl6MnJtZk0/edit?usp=sharing – Peter222 Dec 10 '13 at 05:04
  • Yes, I understand that, but when scrolled there will be a blank space where the left most of the 'test' line is. Is that what you want? – Zach Saucier Dec 10 '13 at 07:35
  • 1
    This row can be splitted: http://jsfiddle.net/A34tH/5/. It should work exactly like this spreadsheet: https://docs.google.com/spreadsheet/ccc?key=0Ahc5r6H_-OovdGwwbEIyNDR5WS1CeXBybzBQZWhpYWc&usp=sharing – Peter222 Dec 10 '13 at 09:42

1 Answers1

1

There are a couple ways to do this. The first is to in CSS/HTML by turn it into three tables instead of one. The second is using some type of plugin for it (hadn't looked but I assume there is one). Assuming you don't want to do either of those, you can use javascript/jQuery to do it as well

My approach is built on this approach to keep the headers and labels fixed

var numDays = 31, // Days of the months in the table
    // Get all header cells
    $headerCells = $('thead tr th'), 
    // Get all label cells
    $labelCells = $('tbody tr td:nth-child(-n + 5):not([colspan]), tbody tr [colspan="5"]'), 
    // Get all body cells
    $bodyCells = $('tbody tr td:nth-child(n + 5), tbody tr [colspan="' + (numDays - 5) + '"]');

$bodyCells.each(function() { // Give each body cell `position:absolute`
    absoluteIt($(this));    
});                   
$headerCells.each(function() { // Give each header cell `position:fixed`
    fixIt($(this));
    $(this).css('z-index', '2'); // When scrolled, place over the other table cells
});
$labelCells.each(function() { // Give each label cell `position:fixed`
    fixIt($(this));
    $(this).css('z-index', '1'); // When scrolled, place over tbody cells
});

$(window).scroll(function(){ // Compensate for scrolling
    // Get scroll positions
    var sLeft = - $('body').scrollLeft(), sTop = - $('body').scrollTop();
    $headerCells.each(function() { // Only scroll horizontally
        $(this).css({
            'left':sLeft + $(this).data('origPosition').oLeft
        });
    });
    $labelCells.each(function() { // Only scroll vertically
        $(this).css({
            'top': sTop + $(this).data('origPosition').oTop
        });
    });        
});


function fixIt($elem) { // Changes the given element into `position:fixed`
    $elem.data('origPosition', { // Saves original values in a data attribute for later
        oTop: $elem.offset().top, 
        oLeft: $elem.offset().left,
        oWidth: $elem.width(),
        oHeight: $elem.height()
    });

    setTimeout(function() { // Necessary to force after the `.data`
        $elem.css({ // Fix the element and make sure it looks like it did before
            position: 'fixed',
            top: $elem.data('origPosition').oTop,
            left: $elem.data('origPosition').oLeft,
            width: $elem.data('origPosition').oWidth,
            height: $elem.data('origPosition').oHeight
        });
    }, 0);
}
// I tried using the same function as above and changing the position afterwards
// but it didn't work out very well
function absoluteIt($elem) { // Changes the given element into `position:absolute`
    $elem.data('origPosition', { // Saves original values in a data attribute for later
        oTop: $elem.offset().top, 
        oLeft: $elem.offset().left,
        oWidth: $elem.width(),
        oHeight: $elem.height()
    });

    setTimeout(function() { // Necessary to force after the `.data`
        $elem.css({ // Absolutely position the element and make sure it looks like it did before
            position: 'absolute',
            top: $elem.data('origPosition').oTop,
            left: $elem.data('origPosition').oLeft,
            width: $elem.data('origPosition').oWidth,
            height: $elem.data('origPosition').oHeight
        });
    }, 0);
}

Demo

My demo is assuming that the labels as a whole are taking up a colspans of 5. This question/answers might be useful if you are in need of more dynamic results because it uses a custom nth-col of sorts

Here is another version with the table (with some modifications) placed in a container. It utilizes a kind of pseudo-fixed position. The big changes in this version: div container with an arbitrary width/height, added the following CSS to table: transform: translateZ(0);

Let me know if you have any questions

Community
  • 1
  • 1
Zach Saucier
  • 24,871
  • 12
  • 85
  • 147
  • Thank You very much for Your work! its nearly what I want. It's best solution from list above. But still have problems. My table is more complicated than in example. I have some filter forms above table. More months (for example may-november). Many rows (100-120). Unfortunately, there are lags while scrolling in so big table. header falls too late. Another problem is, that in full page (not iframe block like fiddle) I must scroll down to see horizontal bar. So, I tried to reduce DIV to fixed height. Unfortunatelly, it doesn't work with script: http://jsfiddle.net/ByaLR/1/. I will try to fix it – Peter222 Dec 11 '13 at 18:06
  • @Peter222 Check out my edit for a container version. It may solve some of your issues – Zach Saucier Dec 11 '13 at 19:21
  • Finally it works! Perfectly - many thanks! I learned something again :) – Peter222 Dec 11 '13 at 22:43
  • another problem... it doesn't work with Firefox, I can not do find the cause – Peter222 Dec 16 '13 at 05:47
  • @Peter222 It's because in the CSS I used `-webkit-transform`. Adding the unprefixed `transform: translateZ(0);` fixed the issue – Zach Saucier Dec 16 '13 at 14:11