7

I know, there are at least 3 dozen questions like this on stackoverflow and still, I could not make this happen:

A simple table where thead is sticked/fixed at the top, and the tbody is scrolled. I tried so much in the past days and now I ended up here crying for help.

A solution should work in IE8+ and newest FF, Chrome & Safari. The difference to other "possible duplicates like this one is that I don't want to use two nested tables or jQuery (plain javascript is fine though).

Demo of what I want:
http://www.imaputz.com/cssStuff/bigFourVersion.html.

Problem is it doesn't work in IE, and I would be fine to use some JS.

Community
  • 1
  • 1
ProblemsOfSumit
  • 19,543
  • 9
  • 50
  • 61

2 Answers2

14

Ok i got it:

You need to wrap the table in two DIVs:

<div class="outerDIV">
  <div class="innerDIV">
    <table></table>
  </div>
</div>

The CSS for the DIVs is this:

.outerDIV {
  position: relative;
  padding-top: 20px;   //height of your thead
}
.innerDIV {
  overflow-y: auto;
  height: 200px;       //the actual scrolling container
}

The reason is, that you basically make the inner DIV scrollable, and pull the THEAD out of it by sticking it to the outer DIV.

Now stick the thead to the outerDIV by giving it

table thead {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
}

The tbody needs to have display: block as well.

Now you'll notice that the scrolling works, but the widths are completely messep up. That's were Javascript comes in. You can choose on your own how you want to assign it. I for myself gave the TH's in the table fixed widths and built a simple script which takes the width and assigns them to the first TD-row in the tbody.

Something like this should work:

function scrollingTableSetThWidth(tableId)
{
    var table = document.getElementById(tableId);

    ths = table.getElementsByTagName('th');
    tds = table.getElementsByTagName('td');

    if(ths.length > 0) {
        for(i=0; i < ths.length; i++) {
            tds[i].style.width = getCurrentComputedStyle(ths[i], 'width');
        }
    }
}

function getCurrentComputedStyle(element, attribute)
{
    var attributeValue;
    if (window.getComputedStyle) 
    { // class A browsers
        var styledeclaration = document.defaultView.getComputedStyle(element, null);
        attributeValue = styledeclaration.getPropertyValue(attribute);
    } else if (element.currentStyle) { // IE
        attributeValue = element.currentStyle[vclToCamelCases(attribute)];
    }
    return attributeValue;
}

With jQuery of course this would be a lot easier but for now i was not allowed to use a third party library for this project.

ProblemsOfSumit
  • 19,543
  • 9
  • 50
  • 61
  • It should be - take the first TD-row in the tbody width and assign it to th width, the other way around. ths[i].style.width = getCurrentComputedStyle(tds[i], 'width'); – Chirag Mehta Aug 31 '12 at 10:37
  • Sure you can do it the other way around. In this specific usecase i had to do it this way, because the user defines the widths of the TH before (dynamicly created table) and it defines the width of the whole table – ProblemsOfSumit Sep 11 '12 at 07:28
  • ok, sounds like its diff use cases, hence handled differently. – Chirag Mehta Sep 12 '12 at 12:45
  • Sorry, but I didn't understand the 2nd function? what do I do with it? – Kyle Jul 15 '15 at 11:34
  • just insert the second function somewhere. It's called by the first function. It'll calculate the computed CSS styles for a given element (this, of course, is a lot easier with jQuery and the likes). – ProblemsOfSumit Jul 16 '15 at 06:16
-1

Maybe we should change a method to archieve this goal.Such as:

<div><ul><li>1</li><li>2</li></ul></div> //make it fixed
<table>
    <thead>
        <tr><th>1</th><th>2</th></tr>
    </thead>
    <tfoot></tfoot>
    <tbody></tbody>
</table>

Of course, this is not good to sematic.But it is the simplest way without js or jq. Don't you think so?

JChen___
  • 3,593
  • 2
  • 20
  • 12
  • no, I don't. Your div doesn't need to be fixed. It's not part of the scrolling table body. The widths would also be totally wrong compared to the table cell widths. Your answer is the same as Gandalfs below and does not work. This is not possible without JS. – ProblemsOfSumit Mar 27 '14 at 13:12
  • Are you sure? Give me your email, and I will send my example to you. – JChen___ Mar 28 '14 at 01:56
  • If your talbe is at the top of viewport, my solution will be fine. If not, make the display of that div none at start and make it block when the talbe scolls to the top and make it none again when the talbe can't be seen. Of course, some js should be used. – JChen___ Mar 28 '14 at 06:50
  • Yeah,right. Now you can go http://jsfiddle.net/JChen___/3fUFV/ to see my example. – JChen___ Mar 28 '14 at 10:26
  • great. First of all, your solution breaks apart when used in a real website, with other content, text, elements and of course, lots of these tables. Second: your solution is not flexible. 5 tables with different number of rows and content and it breaks apart. You would have to specifiy widths individually for each table which isn't an acceptable solution. Now take 100 server generated tables. You can't use your solution for dynamic and flexible layouts/contents/frameworks. – ProblemsOfSumit Mar 28 '14 at 14:17
  • Good analysis.But I believe that they can all be solved with some simple js, although I did not try. – JChen___ Mar 29 '14 at 02:05
  • You're right. They can be solved with simple JS. At least one of it. See the accepted answer for the script. – ProblemsOfSumit Mar 30 '14 at 07:26