Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safari calculates wrong top position with position sticky in table when there are multiple tbodies

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>
like image 953
nej_simon Avatar asked Dec 17 '18 09:12

nej_simon


1 Answers

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>
like image 165
Lloyd Nicholson Avatar answered Oct 13 '22 02:10

Lloyd Nicholson