How to make Scrollable Table with fixed headers using CSS

319,973

Solution 1

What you want to do is separate the content of the table from the header of the table. You want only the <th> elements to be scrolled. You can easily define this separation in HTML with the <tbody> and the <thead> elements.
Now the header and the body of the table are still connected to each other, they will still have the same width (and same scroll properties). Now to let them not 'work' as a table anymore you can set the display: block. This way <thead> and <tbody> are separated.

table tbody, table thead
{
    display: block;
}

Now you can set the scroll to the body of the table:

table tbody 
{
   overflow: auto;
   height: 100px;
}

And last, because the <thead> doesn't share the same width as the body anymore, you should set a static width to the header of the table:

th
{
    width: 72px;
}

You should also set a static width for <td>. This solves the issue of the unaligned columns.

td
{
    width: 72px;
}


Note that you are also missing some HTML elements. Every row should be in a <tr> element, that includes the header row:
<tr>
     <th>head1</th>
     <th>head2</th>
     <th>head3</th>
     <th>head4</th>
</tr>

I hope this is what you meant.

jsFiddle

Addendum

If you would like to have more control over the column widths, have them to vary in width between each other, and course keep the header and body columns aligned, you can use the following example:

    table th:nth-child(1), td:nth-child(1) { min-width: 50px;  max-width: 50px; }
    table th:nth-child(2), td:nth-child(2) { min-width: 100px; max-width: 100px; }
    table th:nth-child(3), td:nth-child(3) { min-width: 150px; max-width: 150px; }
    table th:nth-child(4), td:nth-child(4) { min-width: 200px; max-width: 200px; }

Solution 2

I can think of a cheeky way to do it, I don't think this will be the best option but it will work.

Create the header as a separate table then place the other in a div and set a max size, then allow the scroll to come in by using overflow.

table {
  width: 500px;
}

.scroll {
  max-height: 60px;
  overflow: auto;
}
<table border="1">
  <tr>
  <th>head1</th>
  <th>head2</th>
  <th>head3</th>
  <th>head4</th>
  </tr>
</table>
<div class="scroll">
  <table>
    <tr><td>Text Text</td><td>Text Text</td><td>Text Text</td><td>Text Text</td></tr>
    <tr><td>Text Text</td><td>Text Text</td><td>Text Text</td><td>Text Text</td></tr>
    <tr><td>Text Text</td><td>Text Text</td><td>Text Text</td><td>Text Text</td></tr>
    <tr><td>Text Text</td><td>Text Text</td><td>Text Text</td><td>Text Text</td></tr>
    <tr><td>Text Text</td><td>Text Text</td><td>Text Text</td><td>Text Text</td></tr>
    <tr><td>Text Text</td><td>Text Text</td><td>Text Text</td><td>Text Text</td></tr>
    <tr><td>More Text</td><td>More Text</td><td>More Text</td><td>More Text</td></tr>
    <tr><td>Text Text</td><td>Text Text</td><td>Text Text</td><td>Text Text</td></tr>
    <tr><td>Even More Text Text</td><td>Even More Text Text</td><td>Even More Text Text</td><td>Even More Text Text</td></tr>
  </table>
</div>
Share:
319,973
Xavi
Author by

Xavi

i am a programmer :)

Updated on July 05, 2022

Comments

  • Xavi
    Xavi almost 2 years

    I want to make header of my table fixed.Table is present inside the scrollable div.Please see my code here: http://jsfiddle.net/w7Mm8/114/ kindly suggest me the solution to this.

    Thanks

    My Code:

    <div style="position: absolute; height: 200px; overflow: auto; ">
        <div style="height: 250px;">
            <table border="1">
                <th>head1</th>
                <th>head2</th>
                <th>head3</th>
                <th>head4</th>
                <tr>
                    <td>row 1, cell 1</td>
                    <td>row 1, cell 2</td>
                    <td>row 1, cell 2</td>
                    <td>row 1, cell 2</td>
                </tr>
                <tr>
                    <td>row 2, cell 1</td>
                    <td>row 2, cell 2</td>
                    <td>row 1, cell 2</td>
                    <td>row 1, cell 2</td>
                </tr>
            </table>
        </div>
    </div>
  • dezman
    dezman over 10 years
    The width of the headers and the body cells become misaligned with this solution.
  • Massimo
    Massimo over 10 years
    This works only if the table has a fixed width and fixed column sizes; how can I correctly align the header to the table columns if this is not the case?
  • Massimo
    Massimo over 10 years
    This doesn't work even in your demo... the table content doesn't scroll at all, even when adding additional rows. And yes, the header isn't aligned with the body.
  • nsimeonov
    nsimeonov over 9 years
    You cannot. Even using javascript to set column widths the calculation may be 1 pixel off sometimes.
  • Elmue
    Elmue over 9 years
    Nice but useless for me. If I have to define a fix width for the header and the columns this solution is not useful for my needs. I want the table to adapt dynamically to it's content and the width of the browser window. Did the browser developers not invent a more intelligent solution for this problem? For me it is obvious that a TH should be displayed over the corresponding TD and not in any other place. This is the SENSE of a table header!
  • Supra
    Supra over 9 years
    Does not work for me
  • cprn
    cprn over 7 years
    I know this isn't part of the question but I think is strongly related. Can you make e.g. last column in width table to be fixed and the rest to scroll with horizontal overflow in a similar way or is that entirely different case?
  • nkmol
    nkmol over 7 years
    @cprn This would be somewhat different. You can try yourself and eventually post a new question for it. Or maybe a table plugin exists for this?
  • cprn
    cprn over 7 years
    @nkmol I needed a quick fix so I ended up rendering another table next to the original one with a fixed row height so it would match. I'm still interested in finding out how to do it "properly" so I'll post a question later on.
  • J. Musyoka
    J. Musyoka about 7 years
    I've learnt the hard way not to mess with table (and its children) display property. Makes the table loose some functionality like matching column cell widths for header and body automatically
  • Prasanna
    Prasanna over 6 years
    Hi @nkmol , this is great solution but what if there are 15 coulmns and need to provide both x-y axis scrolling??? i want to do it but when i did display:block is reducing size of <td> though <th> are wider. table design is getting displaced. can you help me for same
  • Danger
    Danger over 5 years
    As others have noticed, this messes up the formatting
  • Ray
    Ray about 5 years
    This did not work for me. The headers still scrolled out of view.