Search code examples
javascripthtmlcssvue.js

How to Make Table Headers Sticky on Horizontal Scrolling?


I'm working on a layout where I need the header of a horizontally scrollable middle table to remain sticky at the top while scrolling vertically. The headers for the left and right tables stick just fine, but I'm having trouble with the middle table's header (probably due to its horizontal scroll).

https://codepen.io/Reynaldo-Rodriguez-the-sasster/pen/XWLqRxo

.container {
  position: relative;
  display: flex;
}

table th {
  position: sticky;
  top: 0;
  background: white;
}

.table-center {
  overflow-x: scroll;
}

table,
th,
td {
  border: 1px solid black;
}

th,
td {
  padding: .5em 1em;
  white-space: nowrap;
}

::-webkit-scrollbar {
  -webkit-appearance: none;
  background-color: transparent;
  height: 7px;
}

::-webkit-scrollbar-thumb {
  border-radius: 4px;
  background-color: rgb(121 121 121);
  box-shadow: none;
}

::-webkit-scrollbar-track {
  background-color: white;
  border: none;
}
<div class="container">
  <div class="table-left">
    <table>
      <tr>
        <th>RIDER #</th>
        <th>RIDER NAME</th>
      </tr>
      <tr>
        <td>#322</td>
        <td>Chase Lanes</td>
      </tr>
      <tr>
        <td>#87</td>
        <td>Marshall Holbrook</td>
      </tr>
      <tr>
        <td>#567</td>
        <td>Marshall Holbrook</td>
      </tr>
      <tr>
        <td>#143</td>
        <td>Marshall Holbrook</td>
      </tr>
      <tr>
        <td>#322</td>
        <td>Chase Lanes</td>
      </tr>
      <tr>
        <td>#87</td>
        <td>Marshall Holbrook</td>
      </tr>
      <tr>
        <td>#567</td>
        <td>Marshall Holbrook</td>
      </tr>
      <tr>
        <td>#143</td>
        <td>Marshall Holbrook</td>
      </tr>
      <tr>
        <td>#322</td>
        <td>Chase Lanes</td>
      </tr>
      <tr>
        <td>#87</td>
        <td>Marshall Holbrook</td>
      </tr>
      <tr>
        <td>#567</td>
        <td>Marshall Holbrook</td>
      </tr>
      <tr>
        <td>#143</td>
        <td>Marshall Holbrook</td>
      </tr>
    </table>
  </div>
  <div class="table-center">
    <table>
      <tr>
        <th>Lap 1</th>
        <th>Lap 2</th>
        <th>Lap 3</th>
        <th>Lap 4</th>
        <th>Lap 5</th>
        <th>Lap 6</th>
        <th>Lap 7</th>
        <th>Lap 8</th>
        <th>Lap 9</th>
        <th>Lap 10</th>
        <th>Lap 11</th>
        <th>Lap 12</th>
        <th>Lap 13</th>
        <th>Lap 14</th>
        <th>Lap 15</th>
        <th>Lap 16</th>
        <th>Lap 17</th>
        <th>Lap 18</th>
        <th>Lap 19</th>
        <th>Lap 20</th>
        <th>Lap 21</th>
        <th>Lap 22</th>
        <th>Lap 23</th>
        <th>Lap 24</th>
        <th>Lap 25</th>
        <th>Lap 26</th>
        <th>Lap 27</th>
        <th>Lap 28</th>
        <th>Lap 29</th>
        <th>Lap 30</th>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
      <tr>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>00:02.826</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
        <td>--:---:--</td>
      </tr>
    </table>
  </div>
  <div class="table-right">
    <table>
      <tr>
        <th>FASTEST LAP</th>
        <th>AVG LAP</th>
        <th>OVERALL TIME</th>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
      <tr>
        <td>00:00</td>
        <td>00:00</td>
        <td>00:00</td>
      </tr>
    </table>
  </div>
</div>


Solution

  • I was able to resolve this issue by using JS and translateY. Updated version is up in codepen if you guys are curious.

    const middleTable = document.getElementById('middleTable');
    const stickyMiddleHeader = document.getElementById('stickyMiddleHeader');
            
    window.addEventListener('scroll', () => {
      const scrollTop = window.scrollY;
      const tableOffsetTop = middleTable.getBoundingClientRect().top + window.scrollY;
      const translateY = scrollTop > tableOffsetTop ? scrollTop - tableOffsetTop : 0;
      stickyMiddleHeader.style.transform = `translateY(${translateY}px)`;});