Search code examples
htmlcsshtml-tablecss-position

HTML table body shows behind theader on scroll


I have a table and it is currently using border-collapse: separate property. My header is completely fine and the borders are looking great.

enter image description here

The problem is when I scroll, the borders start looking weird, as in the below image:

enter image description here

I realize that this is related to the way I have setted the border-collapse property, but is there a way I can have some sort of background on the thead or tr? Any workaround on this?

In the below snippet, as everyone can see, the borders on the header are "disappearing", I wanted to somehow add some sort of a background behind the thead so the borders could be kept the same as if there was no scroll.

* {
  box-sizing: border-box;
}
<style>
  table {
    font-family: arial, sans-serif;
    border-collapse: separate;
    width: 100%;
  }
  
  .first-col {
    position: sticky;
    left: 1px;
  }
  
  th {
    background-color: #d1d1d1;
  }
  
  thead {
    position: sticky;
    top: 0;
    z-index: 99999;
  }
  
  td,
  th {
    border: 1px solid #dddddd;
    text-align: left;
    padding: 8px;
  }
</style>

<div style="max-height: 300px; overflow: auto;">
  <table>
    <thead>
      <tr>
        <th class="first-col"> Row1 of Header </th>
        <th> 1 </th>
        <th> 2 </th>
        <th> 3 </th>
      </tr>
      <tr>
        <th class="first-col"> Row2 of Header </th>
        <th> 1 </th>
        <th> 2 </th>
        <th> 3 </th>
      </tr>
      <tr>
        <th class="first-col"> Row3 of Header </th>
        <th> 1 </th>
        <th> 2 </th>
        <th> 3 </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td> Row1 of Body </td>
        <td> 11 </td>
        <td> 24 </td>
        <td> 32 </td>
      </tr>
      <tr>
        <td> Row2 of Body </td>
        <td> 11 </td>
        <td> 24 </td>
        <td> 32 </td>
      </tr>
      <tr>
        <td> Row3 of Body </td>
        <td> 11 </td>
        <td> 24 </td>
        <td> 32 </td>
      </tr>
      <tr>
        <td> Row4 of Body </td>
        <td> 11 </td>
        <td> 24 </td>
        <td> 32 </td>
      </tr>
      <tr>
        <td> Row5 of Body </td>
        <td> 11 </td>
        <td> 24 </td>
        <td> 32 </td>
      </tr>
      <tr>
        <td> Row6 of Body </td>
        <td> 11 </td>
        <td> 24 </td>
        <td> 32 </td>
      </tr>
      <tr>
        <td> Row7 of Body </td>
        <td> 11 </td>
        <td> 24 </td>
        <td> 32 </td>
      </tr>
      <tr>
        <td> Row8 of Body </td>
        <td> 11 </td>
        <td> 24 </td>
        <td> 32 </td>
      </tr>
      <tr>
        <td> Row9 of Body </td>
        <td> 11 </td>
        <td> 24 </td>
        <td> 32 </td>
      </tr>
      <tr>
        <td> Row10 of Body </td>
        <td> 11 </td>
        <td> 24 </td>
        <td> 32 </td>
      </tr>
    </tbody>
  </table>
</div>


Solution

  • I suppose you mean that the contents and borders of the scrolled cells appear between the header cells when the table is scrolled up.

    To avoid that, you can add an :after pseudo element to thead with a white background-color, z-index: -1 and other settings as shown below. Note that I extended the selector in the CSS rule for the position:sticky elements in the header (.first-col) to include all th cells

    * {
      box-sizing: border-box;
    }
    
    table {
      font-family: arial, sans-serif;
      border-collapse: separate;
      width: 100%;
    }
    
    .first-col, .first-col ~ th {
      position: sticky;
      left: 1px;
    }
    
    td,
    th {
      border: 1px solid #dddddd;
      text-align: left;
      padding: 8px;
    }
    th {
      background-color: #d1d1d1;
    }
    
    thead {
      position: sticky;
      top: 0;
      z-index: 99999;
    }
    
    
    thead::after {
      content: '';
      position: absolute;
      top: 0;
      width: 100%;
      height: 100%;
      background-color: white;
      z-index: -1;
    }
    <div style="max-height: 300px; overflow: auto;">
      <table>
        <thead>
          <tr>
            <th class="first-col"> Row1 of Header </th>
            <th> 1 </th>
            <th> 2 </th>
            <th> 3 </th>
          </tr>
          <tr>
            <th class="first-col"> Row2 of Header </th>
            <th> 1 </th>
            <th> 2 </th>
            <th> 3 </th>
          </tr>
          <tr>
            <th class="first-col"> Row3 of Header </th>
            <th> 1 </th>
            <th> 2 </th>
            <th> 3 </th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td> Row1 of Body </td>
            <td> 11 </td>
            <td> 24 </td>
            <td> 32 </td>
          </tr>
          <tr>
            <td> Row2 of Body </td>
            <td> 11 </td>
            <td> 24 </td>
            <td> 32 </td>
          </tr>
          <tr>
            <td> Row3 of Body </td>
            <td> 11 </td>
            <td> 24 </td>
            <td> 32 </td>
          </tr>
          <tr>
            <td> Row4 of Body </td>
            <td> 11 </td>
            <td> 24 </td>
            <td> 32 </td>
          </tr>
          <tr>
            <td> Row5 of Body </td>
            <td> 11 </td>
            <td> 24 </td>
            <td> 32 </td>
          </tr>
          <tr>
            <td> Row6 of Body </td>
            <td> 11 </td>
            <td> 24 </td>
            <td> 32 </td>
          </tr>
          <tr>
            <td> Row7 of Body </td>
            <td> 11 </td>
            <td> 24 </td>
            <td> 32 </td>
          </tr>
          <tr>
            <td> Row8 of Body </td>
            <td> 11 </td>
            <td> 24 </td>
            <td> 32 </td>
          </tr>
          <tr>
            <td> Row9 of Body </td>
            <td> 11 </td>
            <td> 24 </td>
            <td> 32 </td>
          </tr>
          <tr>
            <td> Row10 of Body </td>
            <td> 11 </td>
            <td> 24 </td>
            <td> 32 </td>
          </tr>
        </tbody>
      </table>
    </div>