Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML table with fixed headers?

Is there a cross-browser CSS/JavaScript technique to display a long HTML table such that the column headers stay fixed on-screen and do not scroll with the table body. Think of the "freeze panes" effect in Microsoft Excel.

I want to be able to scroll through the contents of the table, but to always be able to see the column headers at the top.

like image 213
Cheekysoft Avatar asked Mar 23 '09 12:03

Cheekysoft


People also ask

How do I fix a header row in HTML table?

To freeze the row/column we can use a simple HTML table and CSS. HTML: In HTML we can define the header row by <th> tag or we can use <td> tag also. Below example is using the <th> tag. We also put the table in DIV element to see the horizontal and vertical scrollbar by setting the overflow property of the DIV element.

How do I make my table scrollable with fixed header?

Create a Table That Has a Fixed Header. We can create an HTML table that has a fixed header with some CSS. We set the height of the table element to 120px to make restrict the height of it so we can make it scrollable. To make it scrollable, we set the overflow CSS property to scroll .

How do I fix the header of a table in CSS?

By setting postion: sticky and top: 0, we can create a fixed header on a scroll in HTML tables.


2 Answers

This can be cleanly solved in four lines of code.

If you only care about modern browsers, a fixed header can be achieved much easier by using CSS transforms. Sounds odd, but works great:

  • HTML and CSS stay as-is.
  • No external JavaScript dependencies.
  • Four lines of code.
  • Works for all configurations (table-layout: fixed, etc.).
document.getElementById("wrap").addEventListener("scroll", function(){    var translate = "translate(0,"+this.scrollTop+"px)";    this.querySelector("thead").style.transform = translate; }); 

Support for CSS transforms is widely available except for Internet Explorer 8-.

Here is the full example for reference:

document.getElementById("wrap").addEventListener("scroll",function(){     var translate = "translate(0,"+this.scrollTop+"px)";     this.querySelector("thead").style.transform = translate;  });
/* Your existing container */  #wrap {      overflow: auto;      height: 400px;  }    /* CSS for demo */  td {      background-color: green;      width: 200px;      height: 100px;  }
<div id="wrap">      <table>          <thead>              <tr>                  <th>Foo</th>                  <th>Bar</th>              </tr>          </thead>          <tbody>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>              <tr><td></td><td></td></tr>          </tbody>      </table>  </div>
like image 181
Maximilian Hils Avatar answered Sep 17 '22 01:09

Maximilian Hils


I was looking for a solution for this for a while and found most of the answers are not working or not suitable for my situation, so I wrote a simple solution with jQuery.

This is the solution outline:

  1. Clone the table that needs to have a fixed header, and place the cloned copy on top of the original.
  2. Remove the table body from top table.
  3. Remove the table header from bottom table.
  4. Adjust the column widths. (We keep track of the original column widths)

Below is the code in a runnable demo.

function scrolify(tblAsJQueryObject, height) {    var oTbl = tblAsJQueryObject;      // for very large tables you can remove the four lines below    // and wrap the table with <div> in the mark-up and assign    // height and overflow property      var oTblDiv = $("<div/>");    oTblDiv.css('height', height);    oTblDiv.css('overflow', 'scroll');    oTbl.wrap(oTblDiv);      // save original width    oTbl.attr("data-item-original-width", oTbl.width());    oTbl.find('thead tr td').each(function() {      $(this).attr("data-item-original-width", $(this).width());    });    oTbl.find('tbody tr:eq(0) td').each(function() {      $(this).attr("data-item-original-width", $(this).width());    });        // clone the original table    var newTbl = oTbl.clone();      // remove table header from original table    oTbl.find('thead tr').remove();    // remove table body from new table    newTbl.find('tbody tr').remove();      oTbl.parent().parent().prepend(newTbl);    newTbl.wrap("<div/>");      // replace ORIGINAL COLUMN width				    newTbl.width(newTbl.attr('data-item-original-width'));    newTbl.find('thead tr td').each(function() {      $(this).width($(this).attr("data-item-original-width"));    });    oTbl.width(oTbl.attr('data-item-original-width'));    oTbl.find('tbody tr:eq(0) td').each(function() {      $(this).width($(this).attr("data-item-original-width"));    });  }    $(document).ready(function() {    scrolify($('#tblNeedsScrolling'), 160); // 160 is height  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>    <div style="width:300px;border:6px green solid;">    <table border="1" width="100%" id="tblNeedsScrolling">      <thead>        <tr><th>Header 1</th><th>Header 2</th></tr>      </thead>      <tbody>        <tr><td>row 1, cell 1</td><td>row 1, cell 2</td></tr>        <tr><td>row 2, cell 1</td><td>row 2, cell 2</td></tr>        <tr><td>row 3, cell 1</td><td>row 3, cell 2</td></tr>        <tr><td>row 4, cell 1</td><td>row 4, cell 2</td></tr>			        <tr><td>row 5, cell 1</td><td>row 5, cell 2</td></tr>        <tr><td>row 6, cell 1</td><td>row 6, cell 2</td></tr>        <tr><td>row 7, cell 1</td><td>row 7, cell 2</td></tr>        <tr><td>row 8, cell 1</td><td>row 8, cell 2</td></tr>			      </tbody>    </table>  </div>

This solution works in Chrome and IE. Since it is based on jQuery, this should work in other jQuery supported browsers as well.

like image 31
Mahes Avatar answered Sep 18 '22 01:09

Mahes