14

I have a table that is grouped with multiple <tbody> elements, each one having one initial row with a <th> element that titles the group. I wan't these <th>:s to be sticky but I can't get safari to set the correct top position.

If I set top: 0px or any positive value on the <th>:s it works as expected in Firefox, Chrome and Edge but in safari I get 0px + the height of all above tbodies and caption. This results in all <th>:s getting stuck at the same time well below the top scroll position.

I can work around the problem by flattening the table, removing the <tbody> elements and putting all <tr>:s directly under the table. But that would complicate styling and it makes sense for accessibility to group the table in my case so I'd prefer if I didn't have to do that.

Do you have any ideas how can fix or work around this problem?

Expected (Chrome, Safari and Edge):

Works in Chrome, Safari and Edge

Safari 12:

Doesn't work in Safari 12

div {
  height: 200px;
  overflow: auto;
}

td, th {
  border: 1px solid gray;
}

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

tbody th {
  top: 20px;
}

td {
  background: lightgray;
}
<div>
  <table>
    <caption>The table</caption>
    <thead>
      <tr>
        <th>First col</th>
        <th>Second col</th>
        <th>Third col</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th colspan="3">Group 1</th>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
    </tbody>
    <tbody>
      <tr>
        <th colspan="3">Group 2</th>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
    </tbody>
    <tbody>
      <tr>
        <th colspan="3">Group 3</th>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
      <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
      </tr>
    </tbody>
  </table>
</div>
nej_simon
  • 171
  • 7
  • I have the same issue with `th` in the first `thead` in the table. I want my `caption` and `th` to be sticky when the table is scrolled. I have given `th` `top: 46px` which is the height of `caption`. It works in chrome but not in safari. – Sushmit Sagar Nov 28 '19 at 08:02

1 Answers1

2

The code below will work for both Safari and Google Chrome. The trick is to change your th's to thead's and then set the position to sticky in various ways. position: -webkit-ms-sticky, position: -webkit-o-sticky, position: -webkit-sticky, position:sticky.

You should also add two check in css for the thead and in the second check find every child of that thead tag to ensure it selects each child tag in Chrome as well.

div {
  height: 200px;
  overflow: auto;
}

td, th {
  border: 1px solid gray;
}

tbody thead {
  top: 20px;
}

thead {
  position: -webkit-sticky;
  position: -webkit-o-sticky;
  position: -webkit-ms-sticky;
  position: sticky;
  z-index: 1;
  top: 0px;
  background: white;
}

thead tr:nth-child(1) th{
  background: white;
  position: sticky;
  top: 0;
  z-index: 10;
}

td {
  background: lightgray;
}
      <table>
        <caption>The table</caption>
        <thead>
          <tr>
            <th>First col</th>
            <th>Second col</th>
            <th>Third col</th>
          </tr>
        </thead>
        <tbody>
          <thead>
            <tr>
              <th colspan="3">Group 1</th>
            </tr>
          </thead>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
        </tbody>
        <tbody>
          <thead>
            <tr>
              <th colspan="3">Group 2</th>
            </tr>
          </thead>

          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
        </tbody>
        <tbody>
          <thead>
            <tr>
              <th colspan="3">Group 3</th>
            </tr>
          </thead>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
          <tr>
            <td>foo</td>
            <td>bar</td>
            <td>baz</td>
          </tr>
        </tbody>
      </table>
Lloyd Nicholson
  • 474
  • 3
  • 12
  • Hello! Thank you for taking the time! It does indeed work, however according to the table spec the `` should be a child directly under the `` and it should be followed by a any number of ``:s. I noticed in your example that safari actually moves the nested ``:s up to the parent element. Doing that could maybe be the solution but the spec also say that there should only be on `` per table. Of course code that doesn't follow the spec precisely usually work so maybe this isn't a problem. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/thead
    – nej_simon Dec 17 '18 at 13:16
  • This doesn't work. I just run your snippet in Safari and it didn't work at all... – Marko Zadravec Apr 16 '20 at 16:22