skip to Main Content

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>

2

Answers


  1. Chosen as BEST ANSWER

    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)`;});
    

  2. You can try this.

    With this structure, both the left and middle headers will remain sticky at the top, while allowing horizontal and vertical scrolling in the middle content area. The middle content area can scroll horizontally, and the headers will remain fixed in place, providing a stable view for the user.

    The key is to ensure that the table headers are in a container that is independent of the table body, which allows them to remain sticky.

    <div class="container">
      <div class="side-table-wrapper">
        <table class="side-table">
          <thead>
            <tr>
              <th>Side Header 1</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Side Row 1</td>
            </tr>
            <!-- More rows -->
          </tbody>
        </table>
      </div>
      <div class="middle-table-wrapper">
        <div class="middle-table-header">
          <table class="middle-table">
            <thead>
              <tr>
                <th>Middle Header 1</th>
                <th>Middle Header 2</th>
                <!-- More headers -->
              </tr>
            </thead>
          </table>
        </div>
        <div class="middle-table-body">
          <table class="middle-table">
            <tbody>
              <tr>
                <td>Middle Row 1 Col 1</td>
                <td>Middle Row 1 Col 2</td>
                <!-- More columns -->
              </tr>
              <!-- More rows -->
            </tbody>
          </table>
        </div>
      </div>
      <div class="side-table-wrapper">
        <table class="side-table">
          <thead>
            <tr>
              <th>Side Header 1</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Side Row 1</td>
            </tr>
            
            <!-- More rows -->
          </tbody>
        </table>
      </div>
    </div>
    
    .container {
      display: flex;
    }
    
    .side-table-wrapper {
      flex: 0 0 auto;
      width: 150px;
    }
    
    .middle-table-wrapper {
      flex: 1;
      position: relative;
    }
    
    .middle-table-header {
      overflow: hidden;
      position: sticky;
      top: 0;
      z-index: 10;
    }
    
    .middle-table-body {
      overflow-x: auto; /* Enable horizontal scrolling */
      overflow-y: auto; /* Enable vertical scrolling */
      max-height: 400px; /* Adjust based on your needs */
    }
    
    .middle-table th,
    .side-table th {
      position: sticky;
      top: 0;
      background-color: white;
      z-index: 2;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search