Search code examples
htmlcsshtml-tablecss-positionsticky

How to make table header with 2 rows sticky?! (without js)


I have two rows in my table header and I want it to be fixed on scroll. How can I do this? I've tried setting the position of th elements to sticky, but the second row overlaps the first on scroll (see snippet).

I've seen lots of js based solutions to this, but am not interested in them at all. Surely it's possible using just CSS!

I'd also rather not a solution where you have to hard code the height of your header rows.

.wrapper {
  height: 200px;
  width: 150px;
  background: red;
  overflow: auto;
}

table {
  width: 100%;
  border-spacing: 0;
}

th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: blue;
  text-align: left;
}
<div class="wrapper">
  <table>
    <thead>
      <tr>
        <th>a</th>
        <th>b</th>
      </tr>
      <tr>
        <th>c</th>
        <th>d</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>e</td>
        <td>f</td>
      </tr>
      <tr>
        <td>g</td>
        <td>h</td>
      </tr>
      <tr>
        <td>i</td>
        <td>j</td>
      </tr>
      <tr>
        <td>k</td>
        <td>l</td>
      </tr>
      <tr>
        <td>m</td>
        <td>n</td>
      </tr>
      <tr>
        <td>o</td>
        <td>p</td>
      </tr>
      <tr>
        <td>q</td>
        <td>r</td>
      </tr>
      <tr>
        <td>s</td>
        <td>t</td>
      </tr>
      <tr>
        <td>u</td>
        <td>v</td>
      </tr>
      <tr>
        <td>w</td>
        <td>x</td>
      </tr>
      <tr>
        <td>y</td>
        <td>z</td>
      </tr>
    </tbody>
  </table>
</div>


Solution

  • They become sticky but overlay over each other. You need to specify the top of the second row to be with a space of the first row.

    .wrapper {
      height: 200px;
      width: 150px;
      background: red;
      overflow: auto;
    }
    
    table {
      width: 100%;
      border-spacing: 0;
    }
    
    th {
      position: sticky;
      top: 0;
      z-index: 2;
      background: blue;
      text-align: left;
    }
    
    thead>tr:nth-child(2) th {
      top: 20px;
    }
    <div class="wrapper">
      <table>
        <thead>
          <tr>
            <th>a</th>
            <th>b</th>
          </tr>
          <tr>
            <th>c</th>
            <th>d</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>e</td>
            <td>f</td>
          </tr>
          <tr>
            <td>g</td>
            <td>h</td>
          </tr>
          <tr>
            <td>i</td>
            <td>j</td>
          </tr>
          <tr>
            <td>k</td>
            <td>l</td>
          </tr>
          <tr>
            <td>m</td>
            <td>n</td>
          </tr>
          <tr>
            <td>o</td>
            <td>p</td>
          </tr>
          <tr>
            <td>q</td>
            <td>r</td>
          </tr>
          <tr>
            <td>s</td>
            <td>t</td>
          </tr>
          <tr>
            <td>u</td>
            <td>v</td>
          </tr>
          <tr>
            <td>w</td>
            <td>x</td>
          </tr>
          <tr>
            <td>y</td>
            <td>z</td>
          </tr>
        </tbody>
      </table>
    </div>