Sticky header to relative parent with overflow

Viewed 1851

I've seen variations of this problem everywhere but none seem to solve my problem. I have a tall page that already has a Y scrollbar due to content. Part of the content is a div style="position: relative;", let's call it Div1. Div1 has content in it causing an X and Y scrollbar. In Div1 let's say I have a table with so many columns that it's causing the X overflow and so many rows that it's causing the Y overflow of Div1.

Is there any way to make the tables header row stick to the top of and maintain it's width in Div1?

Imagine the structure like so:

<div id="MainPageDiv">
    //OnScreenContent
    //OnScreenContent
    //OnScreenContent
    //OnScreenContent
    <div class=outerDiv>
        <table class="innerTable">
            <thead>
                //thead columns
            </thead>
            <tbody>
                //tbody rows
            </tbody>
        </table>
    </div>
    //OnScreenContent
    //OnScreenContent
    //OnScreenContent
    //OFFScreenContent
    //OFFScreenContent
    //OFFScreenContent
</div>

So the outerDiv and table sit a little ways down from the top of the page. Also note there is OFFscreenContent farther down.

I want the main page to scroll like normal, but within the outerDiv section I want the thead to stay at the top of the outerDiv container when I scroll in outerDiv.

2 Answers

I ended up using CSS and jQuery to get the desired result. In my wrapper class I used position: relative and on the table header I made it's position absolute and on the wrappers scroll event I adjusted the top value to whatever the scrollTop() of the wrapper was.

.outerDiv {
  overflow:scroll;
  height:140px;
}
thead {
 position:absolute;
  top:0; 
}
tbody {
  display:block;
  position:relative;
  padding-top:10px;
}
<div class="outerDiv">
  <table class="innerTable">
  <thead>
    <tr>
      <th>#</th>
      <th>First</th>
      <th>Last</th>
      <th>Handle</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <td>2</td>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <td>3</td>
      <td colspan="2">Larry the Bird</td>
      <td>@twitter</td>
    </tr>
    <tr>
      <td>1</td>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <td>1</td>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
     <tr>
      <td>1</td>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <td>2</td>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
  </tbody>
</table>
</div>

There are two ways you can achieve this

  1. set overflow:scroll; on parent element of table.
  2. You can use Bootstrap inbuilt table-responsive class here. https://getbootstrap.com/docs/4.1/content/tables/#responsive-tables
Related