TABLE with sticky header row and scrollable body rows

J

JJ

I have a vertically long TABLE that I need to be scrollable. For this,
currently I put it in a DIV and use that DIV as the scroller. i.e.:

<div style="height:500px;overflow-y:auto">
<table>
<thead>
<tr><th>header1</th><th>header2</th><th>header3</th></tr>
</thead>
<tbody>
<tr><td>data1 col1</td><td>data1 col2</td><td>data1 col3</td></tr>
<tr><td>data2 col1</td><td>data2 col2</td><td>data2 col3</td></tr>
<tr>
<td>this column can be multiple lines. also variable width</td>
<td>this one always in one line. fixed width</td>
<td>this one always in one line. fixed width</td>
</tr>
<!-- etc. -->
</tbody>
</table>
</div>

This works, but the disadvantage is that, the header row can get out of view
when the table is scrolled. So I want to make the header row sticky like
Windows Explorer's Detail view.

I thought of assigning "overfow-y:auto" style to TBODY, but it's not
applicable since that style is for block/inline-block elements only. But if
I use "display:block" on the TBODY, the table layout is messed up.

So how can I make the header row sticky?
If possible, without using JavaScript at all.
 
T

Tim Streater

JJ <[email protected]> said:
I have a vertically long TABLE that I need to be scrollable. For this,
currently I put it in a DIV and use that DIV as the scroller. i.e.:
[snip]

So how can I make the header row sticky?
If possible, without using JavaScript at all.

The only way I found to do it is to have two tables. With suitable CSS
it looks like one table. The upper one has just the one row, obviously.
 
D

dorayme

JJ said:
I have a vertically long TABLE that I need to be scrollable. For this,
currently I put it in a DIV and use that DIV as the scroller. i.e.:

<div style="height:500px;overflow-y:auto">
<table>
<thead>
<tr><th>header1</th><th>header2</th><th>header3</th></tr>
</thead>
<tbody>
<tr><td>data1 col1</td><td>data1 col2</td><td>data1 col3</td></tr>
<tr><td>data2 col1</td><td>data2 col2</td><td>data2 col3</td></tr>
<tr>
<td>this column can be multiple lines. also variable width</td>
<td>this one always in one line. fixed width</td>
<td>this one always in one line. fixed width</td>
</tr>
<!-- etc. -->
</tbody>
</table>
</div>

This works, but the disadvantage is that, the header row can get out of view
when the table is scrolled. So I want to make the header row sticky like
Windows Explorer's Detail view.

I thought of assigning "overfow-y:auto" style to TBODY, but it's not
applicable since that style is for block/inline-block elements only. But if
I use "display:block" on the TBODY, the table layout is messed up.

So how can I make the header row sticky?
If possible, without using JavaScript at all.

Take a look at

<http://pics.cssbakery.com/treats/scrollingtable/tableTest6.php>

If it is sort of thing you want, look at the source, or see through

<http://www.cssbakery.com/2010/12/css-scrolling-tables-with-fixed.html>
 
J

JJ

The only way I found to do it is to have two tables. With suitable CSS
it looks like one table. The upper one has just the one row, obviously.

I tried that once, but the header table column widths won't match/align with
the data table.

Even though my table width is fixed, there are at least two columns whose
width must be variable depending on their cells' contents.
 
J

JJ


Sorry I forgot to mention that, my table has at least two columns whose
width must be variable depending on their cells' contents. The table width
is fixed.

The examples in that pages use fixed width for all columns. But maybe I
could use them later. Thanks.
 
J

Jukka K. Korpela

I tried that once, but the header table column widths won't match/align with
the data table.

Even though my table width is fixed, there are at least two columns whose
width must be variable depending on their cells' contents.

Yes, that's the nasty part. Tim's method works if you can use explicit
width settings and table-layout: fixed. But that means the layout is
rigid. And fixed layout implies that cell content may get truncated.

I suppose we could have two tables so that initially they default
table-layout to auto, and then you use JavaScript to get the allocated
widths of columns, set the same widths to the columns of the first
table, and set table-layout: fixed on both tables. Wait... some header
cells might have more content than data cells in the same column, so I
guess you would need to have a copy of the header row(s) in the second
table initially but delete it after you have fixed the column widths.

This sounds so simple that I wonder whether there's some trap here.
Beoynd the problem that the columns would not match when JavaScript is
disabled, of course. (Perhaps you should have just a single table
initially, so the fallback would be a simple table with no scrollable
body. Then you would split it into two tables in JavaScript.)
 
T

Tim Streater

JJ said:
I tried that once, but the header table column widths won't match/align with
the data table.

Even though my table width is fixed, there are at least two columns whose
width must be variable depending on their cells' contents.

Yes. In my case I use javascript to set the column widths in both
tables, and I use overflow: hidden and text-overflow: ellipsis to deal
with the content.
 
D

dorayme

JJ said:
Sorry I forgot to mention that, my table has at least two columns whose
width must be variable depending on their cells' contents. The table width
is fixed.

Perhaps you can supply - apart from a non-scrolling header - an
example that demonstrates the criteria you have mentioned. Your
example in your opening post didn't seem to fit what you wanted (apart
from the problem you posted about).

* A fixed width table (like presumably styled to be table {width:
600px;})

* Your "data1 col2" and "this one always in one line. fixed width" and
the cell that has "this column can be multiple lines. also variable
width" actually varying.

I mention because if you supply something that works exactly how you
want it except for the header scrolling away, maybe someone can
suggest an actual solution for you (rather that a bit of vague hand
waving in some direction which might fall foul of some other
requirement you have.
 
B

Ben C

Yes, that's the nasty part. Tim's method works if you can use explicit
width settings and table-layout: fixed. But that means the layout is
rigid. And fixed layout implies that cell content may get truncated.

I suppose we could have two tables so that initially they default
table-layout to auto, and then you use JavaScript to get the allocated
widths of columns, set the same widths to the columns of the first
table, and set table-layout: fixed on both tables.

You could use visibility: hidden and position: relative to hide the
headings row on the second table, while leaving the headings in there so
that the column widths are not affected (borrowing an idea from the CSS
"solution" below).
Wait... some header cells might have more content than data cells in
the same column, so I guess you would need to have a copy of the
header row(s) in the second table initially but delete it after you
have fixed the column widths.

Yes. You would put the whole table in the markup as normal. Then the
JavaScript would come along, read the column widths of the headings row,
and use them to make the "headings" table, and fix everything up.

This would work quite well because if JavaScript was turned off or
didn't work you'd just have the normal table.

It is possible to avoid JavaScript if you don't mind just repeating the
whole table twice and relying on CSS.

The strategy is to put the first table in an overflow:hidden div so you
can only see the top row, and the rest of it in a scrollable one (see
below).

<style type="text/css">
div.show_head
{
height: 40px;
overflow: hidden;
}
thead { height: 40px; }

div.show_head table tbody { visibility: hidden; }
div.show_body table thead { visibility: hidden; }

div.show_body
{
height: 500px;
overflow: scroll;
}

div.show_body table
{
position: relative;
top: -40px;
}
</style>

...

<div class="show_head">
<table>
<thead>

...

</thead>
<tbody>

...

</tbody>
</table>
</div>
<div class="show_body">
<table>
<thead>

...

</thead>
<tbody>

...

</tbody>
</table>
</div>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top