-2

UPDATE: The below proposed solution does not use any scripting at all, just HTML and CSS to achive sticky table column headers. This is not a duplicate.

Try "Run Code Snippet" please (unless you are in IE or FireFox - which do not support this. However, they degrade gracefully with no errors, but no sticky headers show up. Importantly there is not a single line of JavaScript code that can break).

When scrolling down through large HTML tables where the column headers go out of view, I want to make the column headers stick to the top of the window above each row value so that the content type of each table cell is clear. I find this feature quite critical for usability.

enter image description here


This is a Q/A style question.

This question has come up in many incarnations before, but I haven't seen this "scriptless solution" posted before. The below seems to work with just HTML and CSS only - no scripting needed at all. IE / FireFox not supported, otherwise it seems to work in all latest version browsers.

Apologies if I just haven't found relevant previous posts. I don't follow the HTML tag regularly. I just want to check if what I have stumbled upon can be helpful for others. I am not an experienced HTML developer.

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164

1 Answers1

1

If you are not using IE or FireFox, try clicking "Run Code Snippet" below directly - I think it will show you all you need to "know" without all the babble. It is sticky table headers without any JavaScript at all. Just CSS / HTML.


I have seen many complicated solutions for sticky HTML table columns based on JavaScript, JQuery and advanced CSS. They are probably very good, and work well in several browsers, but the approach below should be very simple to implement (it can't get any more trivial) and be natively supported in all the latest browsers except IE11 and FireFox. No complexity to deal with.

I have also seen frequent suggestions to use two tables in sequence where the first one is fixed showing column values only, and the second table hides its column headers and shows value rows only. This seems quite clunky.

I have seen several other approaches as well.


Based on my limited testing the below works in the latest versions of Edge, Chrome, Opera and Vivaldi, but not in IE or FireFox (no errors will show up, there will just be no sticky headers - it degrades gracefully). I am not set up with enough test resources to be able to verify the compatibility exactly. Importantly there is not a single line of JavaScript code that can break.

The core of this "solution" is this CSS extract:

th {
     position: sticky;
     top: 0px;
}

It seems this will make the table header cells <th> stick to its parent div's top border (top: 0px), and this is apparently all that is needed to achieve sticky column headers in most recent browser versions.

Furthermore you can put several div's in the flow each with their own tables, or you can put several tables in the same div for that matter. It seems to work OK automagically.

I have a large test table with sorting enabled, and sorting also works fine when you click on the sticky headers.

The below sample has been cut down to minimum whilst still trying to implement a proper test of the overall approach. I will post a second answer with a longer table with proper thead and tbody sections (excluded in this simple sample).

#testdiv {
background-color: wheat;
height: 180px;
width: 600px; /* Try commenting this out as well */
overflow: scroll;
}

th {
/* The two core settings for sticky table headers */
position: sticky;
top: 0px;

/* A few more settings for better display*/
background-color: purple;
color: white;
white-space: nowrap;
border: 1px solid black;
text-align: left;
}

table, td {
border-collapse: collapse;
border: 1px solid black;
white-space: nowrap; /* Try commenting this out as well */
}
<div id="testdiv">

<p>Just a leading paragraph for demonstration.</p>
<p>Scroll down and sideways to check the sticky table headers.</p>

<table id='testtable'>
    <tr>
        <th>This is the first column:</th>
        <th>Column Two:</th>
        <th>Third in line here:</th>
    </tr>
    <tr>
        <td>A summer night a long time ago I saw a fox chase a firefly.</td>
        <td>A winter night a long long time ago, I watched the aurora borealis dance in the sky.</td>
        <td>Hello world.</td>
    </tr>
    <tr>
        <td>What is your favorite color?</td>
        <td>Time's Arrow.</td>
        <td>Just a short while ago I was young.</td>
    </tr>
    <tr>
        <td colspan="3">This is a colspan.</td>
    </tr>
    <tr>
        <td>Live long and prosper.</td>
        <td>Kosmonaut.</td>
        <td>What is the airspeed velocity of an unladen swallow?</td>
    </tr>
    <tr>
        <td>A base in space, just to protect the human race.</td>
        <td>Unimatrix Zero.</td>
        <td>Are there any women here?</td>
    </tr>
    <tr>
        <td>Raven.</td>
        <td>Beware, here be dragons.</td>
        <td>Timeless.</td>
    </tr>
    <tr>
        <td>Astronaut.</td>
        <td>42</td>
        <td>HTML and CSS, the fiddliest of endeavours.</td>
    </tr>
    <tr>
        <td rowspan="3">This is rowspan.</td>
        <td>Oh my God.</td>
        <td>777</td>
    </tr>
    <tr>
        <td>Holy Crap.</td>
        <td>778</td>
    </tr>
    <tr>
        <td>The neighbour of the beast.</td>
        <td>668</td>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
    </tr>

    <tr>
        <td colspan="2" rowspan="2">This is colspan and rowspan.</td>
        <td>1</td>
    </tr>
    <tr>
        <td>1</td>
    </tr>
    <tr>
        <td>Three</td>
        <td>Columns</td>
        <td>Here</td>
    </tr>

</table>

<p>A trailing paragraph for demonstration.</p>
<p>A trailing paragraph for demonstration.</p>
<p>A trailing paragraph for demonstration.</p>
<p>A trailing paragraph for demonstration.</p>       
<p>A trailing paragraph for demonstration.</p>

</div>
Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164