2

I have a big table with about 300 rows and 12 columns. While scrolling through the table by paging through the page the <thead> content is not displayed by default. I would like to see it while scrolling "within" <tbody>. That is, if the top of the screen starts with a row, I want that the header is displayed first. Otherwise it should behave like a regular table.

The common solution I have seen so far is to create a table that can scroll for itself (thus independently of page scrolling). That is, what answers to this question suggest.

But this is not very practical if you have many columns spanning the screen, in particular because there are now two independent scrollbars. On mobile devices the second scrollbar takes away a lot of precious space. And it is also very irritating to use. You cannot simply "leaf through", but you have to concentrate to hit that tiny scroll bar. On other browsers you can scroll touching the data within, but once you move outside, another irritating movement happens...

Is there a clean CSS way to do this?

Community
  • 1
  • 1
false
  • 10,264
  • 13
  • 101
  • 209

4 Answers4

11

Hoping that position:sticky will one day be the definitive answer to this problem (see announcement here) like mentioned in the comments above, I was still fascinated at making a simple HTML/CSS proof-of-concept, without the double scrollbars.

My simple solution — not meant to be a perfect one, more as an exercise — without scripting:

  • Duplicate the thead, one that scrolls with the page, and one that stays fixed
  • Play with z-indexes to show the appropriate thead

http://jsfiddle.net/willemvb/hEyZh/

Willem Van Bockstal
  • 2,233
  • 1
  • 17
  • 24
  • +1. What is so odd is that the W3 document about tables explicitly mentions this possibility [this mantra is repeated 9 times on SO](https://www.google.com/search?q=%22This+division+enables+user+agents+to+support+scrolling+of+table+bodies+independently+of+the+table+head+and+foot%22&sitesearch=stackoverflow.com%2Fquestions). And still, there is no clean solution, yet... – false Oct 17 '12 at 00:27
  • Looks nice. However [causes an overlap](https://www.dropbox.com/s/mz9mm99c2klr0s2/table_scrollable_body_1.png) when "real" table header is not completely scrolled up. – dma_k Jul 16 '14 at 13:43
  • I know. See the description in the jsfiddle: "small glitch on overlap of thead". I haven't found a way to fix this without scripting. – Willem Van Bockstal Jul 17 '14 at 07:40
  • This would also fail if the text in a cell is too long – Steven Jan 28 '16 at 00:52
  • @Steven, normal text will reflow, for longer strings you could work with text ellipsis: http://jsfiddle.net/hEyZh/138/ or just make the cells wider :) Again just an exercise, not meant to be an ideal solution. – Willem Van Bockstal Jan 28 '16 at 11:18
2

What if you:

Create your table as long and wide as necessary without a header. Created another table with your table head. Place your header table inside a separate DIV and float that over your data table (z-index + position:absolute). using JQuery, on window load, resize, scroll or any relevant events, you can reset each TH width to match it's corresponding TD. You can also reposition the table head DIV as you scroll. This should work. Let me know if you need an example. This way you should only see browser scroll bars if and when needed.

Good luck.

Bryan Allo
  • 696
  • 3
  • 9
  • +1: What you mean is essentially [solution #2](http://www.cssplay.co.uk/menu/tablescroll.html); yes? – false Oct 16 '12 at 18:02
  • 1
    I've built man data grids from the ground up but unfortunately I cannot think of an purely CSS solution that will satisfy all user/data scenarios without using JS. Will definitely welcome a fresh/creative approach that accomplishes this. – Bryan Allo Oct 16 '12 at 20:19
  • @BryanAllo: The demo of the solution which you propose is given [here](http://jsfiddle.net/ruslans_uralovs/zDaGk) (I have found it in [this reply](http://stackoverflow.com/a/18107873/267197)). – dma_k Jul 16 '14 at 14:00
2

This may help you :

Source from

JS Fiddle

HTML

 <!-- IE < 10 does not like giving a tbody a height.  The workaround here applies the scrolling to a wrapped        <div>. -->
 <!--[if lte IE 9]>
<div class="old_ie_wrapper">
 <!--<![endif]-->

 <table class="fixed_headers">
     <thead>
 <tr>
  <th>Name</th>
  <th>Color</th>
  <th>Description</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Apple</td>
  <td>Red</td>
  <td>These are red.</td>
</tr>
<tr>
  <td>Pear</td>
  <td>Green</td>
  <td>These are green.</td>
</tr>
<tr>
  <td>Grape</td>
  <td>Purple / Green</td>
  <td>These are purple and green.</td>
</tr>
<tr>
  <td>Orange</td>
  <td>Orange</td>
  <td>These are orange.</td>
</tr>
<tr>
  <td>Banana</td>
  <td>Yellow</td>
  <td>These are yellow.</td>
</tr>
<tr>
  <td>Kiwi</td>
  <td>Green</td>
  <td>These are green.</td>
</tr>
<tr>
  <td>Plum</td>
  <td>Purple</td>
  <td>These are Purple</td>
</tr>
<tr>
  <td>Watermelon</td>
  <td>Red</td>
  <td>These are red.</td>
</tr>
<tr>
  <td>Tomato</td>
  <td>Red</td>
  <td>These are red.</td>
</tr>
<tr>
  <td>Cherry</td>
  <td>Red</td>
  <td>These are red.</td>
</tr>
<tr>
  <td>Cantelope</td>
  <td>Orange</td>
  <td>These are orange inside.</td>
</tr>
<tr>
  <td>Honeydew</td>
  <td>Green</td>
  <td>These are green inside.</td>
</tr>
<tr>
  <td>Papaya</td>
  <td>Green</td>
  <td>These are green.</td>
</tr>
<tr>
  <td>Raspberry</td>
  <td>Red</td>
  <td>These are red.</td>
</tr>
<tr>
  <td>Blueberry</td>
  <td>Blue</td>
  <td>These are blue.</td>
</tr>
<tr>
  <td>Mango</td>
  <td>Orange</td>
  <td>These are orange.</td>
</tr>
<tr>
  <td>Passion Fruit</td>
  <td>Green</td>
  <td>These are green.</td>
</tr>
</tbody>
 </table>

   <!--[if lte IE 9]>
   </div>
<!--<![endif]-->

CSS

 .fixed_headers {
     width: 750px;
     table-layout: fixed;
     border-collapse: collapse;
  }
 .fixed_headers th {
    text-decoration: underline;
  }
 .fixed_headers th,.fixed_headers td {
         padding: 5px;
         text-align: left;
   }
  .fixed_headers td:nth-child(1),.fixed_headers th:nth-child(1) {
         min-width: 200px;
   }
  .fixed_headers td:nth-child(2),.fixed_headers th:nth-child(2) {
         min-width: 200px;
    }
    .fixed_headers td:nth-child(3),.fixed_headers th:nth-child(3) {
        width: 350px;
    }
   .fixed_headers thead {
              background-color: #333333;
              color: #fdfdfd;
    }
    .fixed_headers thead tr {
             display: block;
             position: relative;
    }
    .fixed_headers tbody {
             display: block;
             overflow: auto;
             width: 100%;
             height: 300px;
    }
    .fixed_headers tbody tr:nth-child(even) {
             background-color: #dddddd;
    }
    .old_ie_wrapper {
            height: 300px;
            width: 750px;
            overflow-x: hidden;
            overflow-y: auto;
     }
    .old_ie_wrapper tbody {
            height: auto;
      }

Source from

JS Fiddle

Nishchit
  • 18,284
  • 12
  • 54
  • 81
  • 1
    Thanks for interesting solution. Looks as one provided [here](http://tjvantoll.com/2012/11/10/creating-cross-browser-scrollable-tbody/). – dma_k Jul 16 '14 at 13:41
0

You can use the plugin, it works fine: http://web-gladiator.com/stickythead/

Boltosaurus
  • 2,138
  • 3
  • 21
  • 33
  • In some sense this solution repeats [jQuery Datatable](https://datatables.net/examples/api/tabs_and_scrolling.html) which also creates separate table for header and separate table for body. – dma_k Jul 16 '14 at 13:47