Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Freeze the top row for an html table only (Fixed Table Header Scrolling)

Tags:

html

css

People also ask

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 .


This is called Fixed Header Scrolling. There are a number of documented approaches:

http://www.imaputz.com/cssStuff/bigFourVersion.html

You won't effectively pull this off without JavaScript ... especially if you want cross browser support.

There are a number of gotchyas with any approach you take, especially concerning cross browser/version support.

Edit:

Even if it's not the header you want to fix, but the first row of data, the concept is still the same. I wasn't 100% which you were referring to.

Additional thought I was tasked by my company to research a solution for this that could function in IE7+, Firefox, and Chrome.

After many moons of searching, trying, and frustration it really boiled down to a fundamental problem. For the most part, in order to gain the fixed header, you need to implement fixed height/width columns because most solutions involve using two separate tables, one for the header which will float and stay in place over the second table that contains the data.

//float this one right over second table
<table>
  <tr>
    <th>Header 1</th>
    <th>Header 2</th>
  </tr>
</table>

<table>
//Data
</table>

An alternative approach some try is utilize the tbody and thead tags but that is flawed too because IE will not allow you put a scrollbar on the tbody which means you can't limit its height (so stupid IMO).

<table>
  <thead style="do some stuff to fix its position">
  <tr>
    <th>Header 1</th>
    <th>Header 2</th>
  </tr>
  </thead>
  <tbody style="No scrolling allowed here!">
     Data here
  </tbody>
</table>

This approach has many issues such as ensures EXACT pixel widths because tables are so cute in that different browsers will allocate pixels differently based on calculations and you simply CANNOT (AFAIK) guarantee that the distribution will be perfect in all cases. It becomes glaringly obvious if you have borders within your table.

I took a different approach and said screw tables since you can't make this guarantee. I used divs to mimic tables. This also has issues of positioning the rows and columns (mainly because floating has issues, using in-line block won't work for IE7, so it really left me with using absolute positioning to put them in their proper places).

There is someone out there that made the Slick Grid which has a very similar approach to mine and you can use and a good (albeit complex) example for achieving this.

https://github.com/6pac/SlickGrid/wiki


I know this has several answers, but none of these really helped me. I found [this article][1] which explains why my sticky wasn't operating as expected.

Basically, you cannot use position: sticky; on <thead> or <tr> elements. However, they can be used on <th>.

The minimum code I needed to make it work is as follows:

table {
  text-align: left;
  position: relative;
}

th {
  background: white;
  position: sticky;
  top: 0;
}

With the table set to relative the <th> can be set to sticky, with the top at 0 [1]: https://css-tricks.com/position-sticky-and-table-headers/

NOTE: It's necessary to wrap the table with a div with max-height:

<div id="managerTable" >
...
</div>

where:

#managerTable {
    max-height: 500px;
    overflow: auto;
}

According to Pure CSS Scrollable Table with Fixed Header , I wrote a DEMO to easily fix the header by setting overflow:auto to the tbody.

table thead tr{
    display:block;
}

table th,table td{
    width:100px;//fixed width
}


table  tbody{
  display:block;
  height:200px;
  overflow:auto;//set tbody to auto
}

My concern was not to have the cells with fixed width. Which seemed to be not working in any case. I found this solution which seems to be what I need. I am posting it here for others who are searching of a way. Check out this fiddle

Working Snippet:

html, body{
  margin:0;
  padding:0;
  height:100%;
}
section {
  position: relative;
  border: 1px solid #000;
  padding-top: 37px;
  background: #500;
}
section.positioned {
  position: absolute;
  top:100px;
  left:100px;
  width:800px;
  box-shadow: 0 0 15px #333;
}
.container {
  overflow-y: auto;
  height: 160px;
}
table {
  border-spacing: 0;
  width:100%;
}
td + td {
  border-left:1px solid #eee;
}
td, th {
  border-bottom:1px solid #eee;
  background: #ddd;
  color: #000;
  padding: 10px 25px;
}
th {
  height: 0;
  line-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  color: transparent;
  border: none;
  white-space: nowrap;
}
th div{
  position: absolute;
  background: transparent;
  color: #fff;
  padding: 9px 25px;
  top: 0;
  margin-left: -25px;
  line-height: normal;
  border-left: 1px solid #800;
}
th:first-child div{
  border: none;
}
<section class="">
  <div class="container">
    <table>
      <thead>
        <tr class="header">
          <th>
            Table attribute name
            <div>Table attribute name</div>
          </th>
          <th>
            Value
            <div>Value</div>
          </th>
          <th>
            Description
            <div>Description</div>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>align</td>
          <td>left, center, right</td>
          <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the alignment of a table according to surrounding text</td>
        </tr>
        <tr>
          <td>bgcolor</td>
          <td>rgb(x,x,x), #xxxxxx, colorname</td>
          <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the background color for a table</td>
        </tr>
        <tr>
          <td>border</td>
          <td>1,""</td>
          <td>Specifies whether the table cells should have borders or not</td>
        </tr>
        <tr>
          <td>cellpadding</td>
          <td>pixels</td>
          <td>Not supported in HTML5. Specifies the space between the cell wall and the cell content</td>
        </tr>
        <tr>
          <td>cellspacing</td>
          <td>pixels</td>
          <td>Not supported in HTML5. Specifies the space between cells</td>
        </tr>
        <tr>
          <td>frame</td>
          <td>void, above, below, hsides, lhs, rhs, vsides, box, border</td>
          <td>Not supported in HTML5. Specifies which parts of the outside borders that should be visible</td>
        </tr>
        <tr>
          <td>rules</td>
          <td>none, groups, rows, cols, all</td>
          <td>Not supported in HTML5. Specifies which parts of the inside borders that should be visible</td>
        </tr>
        <tr>
          <td>summary</td>
          <td>text</td>
          <td>Not supported in HTML5. Specifies a summary of the content of a table</td>
        </tr>
        <tr>
          <td>width</td>
          <td>pixels, %</td>
          <td>Not supported in HTML5. Specifies the width of a table</td>
        </tr>
      </tbody>
    </table>
  </div>
</section>

You can use CSS position: sticky; for the first row of the table MDN ref:

.table-class tr:first-child>td{
    position: sticky;
    top: 0;
}