Table with fixed header and fixed column on pure css

110

I need to create a html table (or something similar looking) with a fixed header and a fixed first column.

Every solution I've seen so far uses Javascript or jQuery to set scrollTop/scrollLeft, but it doesn't work smoothly on mobile browsers, so I'm looking for a pure CSS solution.

I found a solution for a fixed column here: jsfiddle.net/C8Dtf/20/ but I don't know how I can enhance it to make the header fixed too.

I want it to work on webkit browsers or use some css3 features, but I repeat, I don't want to use Javascript for scrolling.

EDIT: This is example of the behaviour I want to achieve: https://web.archive.org/web/20130829032141/http://datatables.net/release-datatables/extras/FixedColumns/css_size.html

This question is tagged with html css html-table markup fixed-header-tables

~ Asked on 2013-04-04 12:48:04

The Best Answer is


168

An actual pure CSS solution with a fixed header row and first column

I had to create a table with both a fixed header and a fixed first column using pure CSS and none of the answers here were quite what I wanted.

The position: sticky property supports both sticking to the top (as I've seen it used the most) and to the side in modern versions of Chrome, Firefox, and Edge. This can be combined with a div that has the overflow: scroll property to give you a table with fixed headers that can be placed anywhere on your page:

Place your table in a container:

<div class="container">
  <table></table>
</div>

Use overflow: scroll on your container to enable scrolling:

div.container {
  overflow: scroll;
}

As Dagmar pointed out in the comments, the container also requires a max-width and a max-height.

Use position: sticky to have table cells stick to the edge and top, right, or left to choose which edge to stick to:

thead th {
  position: -webkit-sticky; /* for Safari */
  position: sticky;
  top: 0;
}

tbody th {
  position: -webkit-sticky; /* for Safari */
  position: sticky;
  left: 0;
}

As MarredCheese mentioned in the comments, if your first column contains <td> elements instead of <th> elements, you can use tbody td:first-child in your CSS instead of tbody th

To have the header in the first column stick to the left, use:

thead th:first-child {
  left: 0;
  z-index: 1;
}

_x000D_
_x000D_
/* Use overflow:scroll on your container to enable scrolling: */

div {
  max-width: 400px;
  max-height: 150px;
  overflow: scroll;
}


/* Use position: sticky to have it stick to the edge
 * and top, right, or left to choose which edge to stick to: */

thead th {
  position: -webkit-sticky; /* for Safari */
  position: sticky;
  top: 0;
}

tbody th {
  position: -webkit-sticky; /* for Safari */
  position: sticky;
  left: 0;
}


/* To have the header in the first column stick to the left: */

thead th:first-child {
  left: 0;
  z-index: 2;
}


/* Just to display it nicely: */

thead th {
  background: #000;
  color: #FFF;
  /* Ensure this stays above the emulated border right in tbody th {}: */
  z-index: 1;
}

tbody th {
  background: #FFF;
  border-right: 1px solid #CCC;
  /* Browsers tend to drop borders on sticky elements, so we emulate the border-right using a box-shadow to ensure it stays: */
  box-shadow: 1px 0 0 0 #ccc;
}

table {
  border-collapse: collapse;
}

td,
th {
  padding: 0.5em;
}
_x000D_
<div>
  <table>
    <thead>
      <tr>
        <th></th>
        <th>headheadhead</th>
        <th>headheadhead</th>
        <th>headheadhead</th>
        <th>headheadhead</th>
        <th>headheadhead</th>
        <th>headheadhead</th>
        <th>headheadhead</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th>head</th>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
      </tr>
      <tr>
        <th>head</th>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
      </tr>
      <tr>
        <th>head</th>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
      </tr>
      <tr>
        <th>head</th>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
      </tr>
      <tr>
        <th>head</th>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
      </tr>
      <tr>
        <th>head</th>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
        <td>body</td>
      </tr>
    </tbody>
  </table>
</div>
_x000D_
_x000D_
_x000D_

https://jsfiddle.net/qwubvg9m/1/

~ Answered on 2018-05-24 18:50:37


36

Nowadays, this is possible to achieve using CSS only with position: sticky property.

Here goes a snippet:

(jsFiddle: https://jsfiddle.net/hbqzdzdt/5/)

_x000D_
_x000D_
.grid-container {_x000D_
  display: grid; /* This is a (hacky) way to make the .grid element size to fit its content */_x000D_
  overflow: auto;_x000D_
  height: 300px;_x000D_
  width: 600px;_x000D_
}_x000D_
.grid {_x000D_
  display: flex;_x000D_
  flex-wrap: nowrap;_x000D_
}_x000D_
.grid-col {_x000D_
  width: 150px;_x000D_
  min-width: 150px;_x000D_
}_x000D_
_x000D_
.grid-item--header {_x000D_
  height: 100px;_x000D_
  min-height: 100px;_x000D_
  position: sticky;_x000D_
  position: -webkit-sticky;_x000D_
  background: white;_x000D_
  top: 0;_x000D_
}_x000D_
_x000D_
.grid-col--fixed-left {_x000D_
  position: sticky;_x000D_
  left: 0;_x000D_
  z-index: 9998;_x000D_
  background: white;_x000D_
}_x000D_
.grid-col--fixed-right {_x000D_
  position: sticky;_x000D_
  right: 0;_x000D_
  z-index: 9998;_x000D_
  background: white;_x000D_
}_x000D_
_x000D_
.grid-item {_x000D_
  height: 50px;_x000D_
  border: 1px solid gray;_x000D_
}
_x000D_
<div class="grid-container">_x000D_
  <div class="grid">_x000D_
    <div class="grid-col grid-col--fixed-left">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>Hello</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>Hello</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>Hello</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>Hello</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>Hello</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>Hello</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>Hello</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>Hello</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>Hello</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>Hello</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>P</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
    <div class="grid-col grid-col--fixed-right">_x000D_
      <div class="grid-item grid-item--header">_x000D_
        <p>HEAD</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>9</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>9</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>9</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>9</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>9</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>9</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>9</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>9</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>9</p>_x000D_
      </div>_x000D_
      <div class="grid-item">_x000D_
        <p>9</p>_x000D_
      </div>_x000D_
    </div>_x000D_
_x000D_
  </div>_x000D_
</div>
_x000D_
_x000D_
_x000D_

Regarding compatibility. It works in all major browsers, but not in IE. There is a polyfill for position: sticky but I never tried it.

~ Answered on 2017-10-24 20:32:09


Most Viewed Questions: