Fixed Table Header with Scrolling Page Body
Asked Answered
M

2

6

Initially scrolling, then fixed table header with scrolling page body.

I would like to put a table somewhere in the middle of my web page that has the following behavior:

  1. Acts like a "normal" html table for the most part... until you scroll past the table's headers
  2. When you scroll past the table's headers, the table headers stays fixed at or near the top of that page, while the rest of the table keeps scrolling with the rest of the page body. This is not the same as a scrolling <tbody> with fixed <thead>.
  3. Bonus points if the table headers disappear if you scroll past the last row of the table.
  4. Bonus points if the table rows disappear as they scroll higher than the headers. (I only need this feature when/if I were to try to place the fixed table header in a different location than at the very top of the page)

It should look something similar to the example given in this fiddle:
http://jsfiddle.net/yeAhU/260/
Except header contents would scroll to the top of the page before becoming fixed and the table contents should not show above the headers as it scrolls.

I have tried slightly tweaking most of the posted answers for "fixed table header scrolling body" questions online but I am not able to get the type of behavior I am looking for from those examples.

I would like the solution to be CSS-based if possible but I am open to other solutions like JS.

I would like the solution to be compatible with both Chrome & Firefox.


QUESTION

Is it possible to do this, and is it possible to do it in just CSS? How?

Maquis answered 16/5, 2016 at 23:45 Comment(2)
Hey there! You should mark some answer as correct here..Gasser
no. i havent been able to finalize anything regarding this yet.Maquis
B
14

In CSS you could use position:sticky; but since Firefox doesn't mix those two so well yet, you still need to use thead and tbody to break the table-layout to use sticky. ... reset the table-layout on tbody and set table-layout to fixed to help hold columns visually together from thead/tbody ... example :

http://jsfiddle.net/yeAhU/261/ i believe it meets points :1,2,3 (what is 4 actually ? )

http://caniuse.com/#search=sticky

chrome removed it a while ago next link might be helpfull

https://www.sitepoint.com/css-position-sticky-introduction-polyfills/

tbody, thead tr {
  display: table;
  width: 100%;
  table-layout: fixed;
}
td {
  border:1px solid;
}
* {box-sizing:border-box; border-collapse:collapse;}
Additional stuff
<br> Additional stuff
<br> Additional stuff
<br> Additional stuff
<br>

<table width="400" border="0" style="display:block;">
  <thead style="display:block;position: sticky;top:20px;background-color: grey;">
    <tr>
      <td width="200">
        Name
      </td>
      <td width="200">
        Age
      </td>
    </tr>
  </thead>
  <tbody>
  <tr>
    <td width="200">
      &nbsp;
    </td>
    <td width="200">
      &nbsp;
    </td>
  </tr>
  <tr>
    <td>
      John
    </td>
    <td>
      28
    </td>
  </tr>
  <tr>
    <td>
      Jacob
    </td>
    <td>
      22
    </td>
  </tr>
  <tr>
    <td>
      Nicole
    </td>
    <td>
      12
    </td>
  </tr>
  <tr>
    <td>
      Marie
    </td>
    <td>
      15
    </td>
  </tr>
  <tr>
    <td>
      Fabian
    </td>
    <td>
      18
    </td>
  </tr>
  <tr>
    <td>
      Caspar
    </td>
    <td>
      23
    </td>
  </tr>
  <tr>
    <td>
      Elder
    </td>
    <td>
      12
    </td>
  </tr>
  <tr>
    <td>
      Frank
    </td>
    <td>
      17
    </td>
  </tr>
  <tr>
    <td>
      Ling
    </td>
    <td>
      45
    </td>
  </tr>
  <tr>
    <td>
      Pong
    </td>
    <td>
      68
    </td>
  </tr>
  <tr>
    <td>
      Jason
    </td>
    <td>
      67
    </td>
  </tr>
  <tr>
    <td>
      Tony
    </td>
    <td>
      23
    </td>
  </tr>
  <tr>
    <td>
      Britney
    </td>
    <td>
      21
    </td>
  </tr>
  <tr>
    <td>
      Cusac
    </td>
    <td>
      91
    </td>
  </tr>
  <tr>
    <td>
      John
    </td>
    <td>
      28
    </td>
  </tr>
  <tr>
    <td>
      Jacob
    </td>
    <td>
      22
    </td>
  </tr>
  <tr>
    <td>
      Nicole
    </td>
    <td>
      12
    </td>
  </tr>
  <tr>
    <td>
      Marie
    </td>
    <td>
      15
    </td>
  </tr>
  <tr>
    <td>
      Fabian
    </td>
    <td>
      18
    </td>
  </tr>
  <tr>
    <td>
      Caspar
    </td>
    <td>
      23
    </td>
  </tr>
  <tr>
    <td>
      Elder
    </td>
    <td>
      12
    </td>
  </tr>
  <tr>
    <td>
      Frank
    </td>
    <td>
      17
    </td>
  </tr>
  <tr>
    <td>
      Ling
    </td>
    <td>
      45
    </td>
  </tr>
  <tr>
    <td>
      Pong
    </td>
    <td>
      68
    </td>
  </tr>
  <tr>
    <td>
      Jason
    </td>
    <td>
      67
    </td>
  </tr>
  <tr>
    <td>
      Tony
    </td>
    <td>
      23
    </td>
  </tr>
  <tr>
    <td>
      Britney
    </td>
    <td>
      21
    </td>
  </tr>
  <tr>
    <td>
      Cusac
    </td>
    <td>
      91
    </td>
  </tr>
  <tr>
    <td>
      John
    </td>
    <td>
      28
    </td>
  </tr>
  <tr>
    <td>
      Jacob
    </td>
    <td>
      22
    </td>
  </tr>
  <tr>
    <td>
      Nicole
    </td>
    <td>
      12
    </td>
  </tr>
  <tr>
    <td>
      Marie
    </td>
    <td>
      15
    </td>
  </tr>
  <tr>
    <td>
      Fabian
    </td>
    <td>
      18
    </td>
  </tr>
  <tr>
    <td>
      Caspar
    </td>
    <td>
      23
    </td>
  </tr>
  <tr>
    <td>
      Elder
    </td>
    <td>
      12
    </td>
  </tr>
  <tr>
    <td>
      Frank
    </td>
    <td>
      17
    </td>
  </tr>
  <tr>
    <td>
      Ling
    </td>
    <td>
      45
    </td>
  </tr>
  <tr>
    <td>
      Pong
    </td>
    <td>
      68
    </td>
  </tr>
  <tr>
    <td>
      Jason
    </td>
    <td>
      67
    </td>
  </tr>
  <tr>
    <td>
      Tony
    </td>
    <td>
      23
    </td>
  </tr>
  <tr>
    <td>
      Britney
    </td>
    <td>
      21
    </td>
  </tr>
  <tr>
    <td>
      Cusac
    </td>
    <td>
      91
    </td>
  </tr>
  <tr>
    <td>
      John
    </td>
    <td>
      28
    </td>
  </tr>
  <tr>
    <td>
      Jacob
    </td>
    <td>
      22
    </td>
  </tr>
  <tr>
    <td>
      Nicole
    </td>
    <td>
      12
    </td>
  </tr>
  <tr>
    <td>
      Marie
    </td>
    <td>
      15
    </td>
  </tr>
  <tr>
    <td>
      Fabian
    </td>
    <td>
      18
    </td>
  </tr>
  <tr>
    <td>
      Caspar
    </td>
    <td>
      23
    </td>
  </tr>
  <tr>
    <td>
      Elder
    </td>
    <td>
      12
    </td>
  </tr>
  <tr>
    <td>
      Frank
    </td>
    <td>
      17
    </td>
  </tr>
  <tr>
    <td>
      Ling
    </td>
    <td>
      45
    </td>
  </tr>
  <tr>
    <td>
      Pong
    </td>
    <td>
      68
    </td>
  </tr>
  <tr>
    <td>
      Jason
    </td>
    <td>
      67
    </td>
  </tr>
  <tr>
    <td>
      Tony
    </td>
    <td>
      23
    </td>
  </tr>
  <tr>
    <td>
      Britney
    </td>
    <td>
      21
    </td>
  </tr>
  <tr>
    <td>
      Cusac
    </td>
    <td>
      91
    </td>
  </tr></tbody>
</table>

Additional stuff
<br> Additional stuff
<br> Additional stuff
<br> Additional stuff
<br>Additional stuff
<br> Additional stuff
<br> Additional stuff
<br> Additional stuff
<br>Additional stuff
<br> Additional stuff
<br> Additional stuff
<br> Additional stuff
<br>Additional stuff
<br> Additional stuff
<br> Additional stuff
<br> Additional stuff
<br>Additional stuff
<br> Additional stuff
<br> Additional stuff
<br> Additional stuff
<br>Additional stuff
<br> Additional stuff
<br> Additional stuff
<br> Additional stuff
<br>Additional stuff
<br> Additional stuff
<br> Additional stuff
<br> Additional stuff
<br>
Boswell answered 17/5, 2016 at 0:19 Comment(12)
awesome... but i wish it worked on chrome since thats our "supported browser".Maquis
#4 means that the row entries become invisible as they are scrolled past the table header. I would only need this feature if I were to try to place the fixed table header at a specified location other than at the top of the page. Is your solution capable of placing the table header fixed position somewhere other than at the very top of the page?Maquis
position sticky and coordonates refer to window.you can use any coordonates with any values , once the sticky element reaches the coordonates it remains still untill something else pushes it away :).... i updated the snippet with a top:20px; can be a left or right or bottom coordonates used tooBoswell
sticky still not working with chrome .even prefixed ? would this help too : developers.google.com/web/updates/2012/08/… obviously it was removedBoswell
Is there some reason why you've mixed stylesheet styles with inline style attributes? (I found the answer confusing initially because I didn't notice the inline style at first.)Automate
@Automate The code is from the fiddle i updated , where at first (the op's) had inline style and position:fixed; Since the code is his, i expected he would easily see difference without figuring out where and what was different . Indeed, not a good practice that i could have also advised about.Boswell
@HermanKan , it does again now since a few month, seems like it will remain so this time ;)Boswell
I've tried dozens of different solutions, and this is the only one that works for me, you saved my dayEmptor
#4 is very important. Anyone did it?Oxley
@Oxley is the snippet demo not doing it ? (pushed away by additionnal stuff text)Boswell
@Boswell You can see the rows scrolled above the sticky header, I need to stick the header just like the demo - NOT in top: 0, and hide the rows when they scroll above the sticked header.Oxley
@Oxley have you made a question, else do you have a snippet of your case that we can look at ? (things are hidden behind, not around, a top white shadow could do increasing the area where that header stands visually or an extra element also sticky in between with a background codepen.io/gc-nomade/pen/ZEeZEZq )Boswell
G
2

Here is your solution.. fiddle by Jonas Schubert Erlandsson

<section class="">
  <div class="container">
    <table>
      <thead>
        <tr class="header">
          <th>
            Table attribute name
            <div>Table attribute name</div>
          </th>
          <th>
            Value
            <div>Value</div>
          </th>
          <th>
            Description
            <div>Description</div>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>align</td>
          <td>left, center, right</td>
          <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the alignment of a table according to surrounding text</td>
        </tr>
        <tr>
          <td>bgcolor</td>
          <td>rgb(x,x,x), #xxxxxx, colorname</td>
          <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the background color for a table</td>
        </tr>
        <tr>
          <td>border</td>
          <td>1,""</td>
          <td>Specifies whether the table cells should have borders or not</td>
        </tr>
        <tr>
          <td>cellpadding</td>
          <td>pixels</td>
          <td>Not supported in HTML5. Specifies the space between the cell wall and the cell content</td>
        </tr>
        <tr>
          <td>cellspacing</td>
          <td>pixels</td>
          <td>Not supported in HTML5. Specifies the space between cells</td>
        </tr>
        <tr>
          <td>frame</td>
          <td>void, above, below, hsides, lhs, rhs, vsides, box, border</td>
          <td>Not supported in HTML5. Specifies which parts of the outside borders that should be visible</td>
        </tr>
        <tr>
          <td>rules</td>
          <td>none, groups, rows, cols, all</td>
          <td>Not supported in HTML5. Specifies which parts of the inside borders that should be visible</td>
        </tr>
        <tr>
          <td>summary</td>
          <td>text</td>
          <td>Not supported in HTML5. Specifies a summary of the content of a table</td>
        </tr>
        <tr>
          <td>width</td>
          <td>pixels, %</td>
          <td>Not supported in HTML5. Specifies the width of a table</td>
        </tr>
      </tbody>
    </table>
  </div>
</section>

and the css

html, body{
  margin:0;
  padding:0;
  height:100%;
}
section {
  position: relative;
  border: 1px solid #000;
  padding-top: 37px;
  background: #500;
}
section.positioned {
  position: absolute;
  top:100px;
  left:100px;
  width:800px;
  box-shadow: 0 0 15px #333;
}
.container {
  overflow-y: auto;
  height: 200px;
}
table {
  border-spacing: 0;
  width:100%;
}
td + td {
  border-left:1px solid #eee;
}
td, th {
  border-bottom:1px solid #eee;
  background: #ddd;
  color: #000;
  padding: 10px 25px;
}
th {
  height: 0;
  line-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  color: transparent;
  border: none;
  white-space: nowrap;
}
th div{
  position: absolute;
  background: transparent;
  color: #fff;
  padding: 9px 25px;
  top: 0;
  margin-left: -25px;
  line-height: normal;
  border-left: 1px solid #800;
}
th:first-child div{
  border: none;
}
Gasser answered 17/5, 2016 at 17:53 Comment(5)
This solution seems exactly like the other various "scrolling <tbody> with fixed <thead>" solutions as mentioned in my #2. correct me if i am wrong.Maquis
Alright.. here is what you are looking for. tympanus.net/codrops/2014/01/09/sticky-table-headers-columnsGasser
alright. and if you could find your way through it.. dont forget to vote up or mark correct the answer..!Gasser
i might just use bootstrap affix. not sure yet, but ill mark you when I get through it.Maquis
This is a very clean solution that doesn't require any extra gems or plug-ins on top of what I already had. Where can I look to learn how to apply this idea to the left-most column of the table as well?Religieux

© 2022 - 2024 — McMap. All rights reserved.