There ain't no web developer that never worried about a table with a fixed header. HTML browsers should implement this out of the box. But they don't. We need to do it.
Here is a normal HTML table with a height restricted to 12 em.
One | Two | Three |
---|---|---|
1 Apples | Oranges | Plum |
2 Apples | Oranges | Plum |
3 Apples | Oranges | Plum |
4 Apples | Oranges | Plum |
5 Apples | Oranges | Plum |
6 Apples | Oranges | Plum |
7 Apples | Oranges | Plum |
8 Apples | Oranges | Plum |
9 Apples | Oranges | Plum |
10 Apples | Oranges | Plum |
11 Apples | Oranges | Plum |
12 Apples | Oranges | Plum |
13 Apples | Oranges | Plum |
14 Apples | Oranges | Plum |
15 Apples | Oranges | Plum |
16 Apples | Oranges | Plum |
17 Apples | Oranges | Plum |
18 Apples | Oranges | Plum |
19 Apples | Oranges | Plum |
20 Apples | Oranges | Plum |
Here is the same with fixed header.
One | Two | Three |
---|---|---|
1 Apples | Oranges | Plum |
2 Apples | Oranges | Plum |
3 Apples | Oranges | Plum |
4 Apples | Oranges | Plum |
5 Apples | Oranges | Plum |
6 Apples | Oranges | Plum |
7 Apples | Oranges | Plum |
8 Apples | Oranges | Plum |
9 Apples | Oranges | Plum |
10 Apples | Oranges | Plum |
11 Apples | Oranges | Plum |
12 Apples | Oranges | Plum |
13 Apples | Oranges | Plum |
14 Apples | Oranges | Plum |
15 Apples | Oranges | Plum |
16 Apples | Oranges | Plum |
17 Apples | Oranges | Plum |
18 Apples | Oranges | Plum |
19 Apples | Oranges | Plum |
20 Apples | Oranges | Plum |
Don't see no difference? It's not always the look, sometimes it's the feel :-)
You feel the difference as soon as you scroll down.
The fixed header stays at its position while the table content scrolls under it.
The non-fixed header scrolls away with the content and is no more visible.
How to achieve this? We now enter the kingdom of absolute and relative positioning :-)
Relative and Absolute Positioning
When you explored my latest Blog you can skip this chapter.
An HTML element that was positioned by CSS position: relative
(or absolute
, or fixed
) is the point of reference
for its children with position: absolute
.
An HTML element that was positioned by CSS position: absolute
will position
itself relative to its nearest parent with a position
different to static
.
The relative position is then given by top, left, right, bottom
coordinates.
Fix the Header
How can this knowledge be applied to fix a table header?
We need ...
-
... a parent
div
withposition: relative
that will be the reference point for the absolutely positioned header -
... another parent
div
to restrict the table-content to a certainheight
, and restrict the content'soverflow
toauto
, else it won't have a scrollbar (default overflow is visible) -
... to set the header to
position: absolute
and give it atop: 0
coordinate (default coordinate would be its static position below or beside its predecessor HTML element)
Sounds simple and logical. The header would then go absolutely to its relative parent and stay there, while the table scrolls under it.
Unfortunately the browser's table implementations make it
impossible to tear the header cells out of the table and pull it up onto some siding.
And, fortunately, clever people have found a workaround for that:
- wrap the content of the
th
header cells intodiv
elements, and - position the
div
absolutely (instead of theth
cells).
So, step by step now.
1. The Header Parent
.headerSiding { position: relative; /* need a non-static position */ padding-top: 1.4em; /* place for the fixed header */ }
The topmost parent is positioned relatively, to be the reference point for absolutely positioned child elements. It prepares a siding for the header by declaring a padding. (This padding might need adjustment for headers that are multi-line.)
<div class="headerSiding"> .... </div>
2. The Scroll Pane
.scrollPane { height: 20em; /* without height no scrollbar ever */ overflow: auto; /* show scrollbar when needed */ }
This is a standard scroll pane. By setting the height
,
and setting overflow: auto
, you force scrollbars when the content
does not fit into the height. Mind that this is positioned static, NOT relative, else
the scrollPane would be the reference point for the table header, not the headerSiding!
<div class="headerSiding"> <div class="scrollPane"> .... </div> </div>
3. The Header Cells
.scrollPane th div { position: absolute; /* pinned to next non-static parent */ top: 0; /* at top of parent */ }
This is the tricky part, nevertheless very short.
Simply tell the div
elements containing the header cell content to go to top,
where a padding was prepared for them. That's all concerning CSS, now we also
need to look at the HTML.
<div class="headerSiding"> <div class="scrollPane"> <table> <thead> <tr> <th><div>One</div></th><th><div>Two</div></th><th><div>Three</div></th> </tr> </thead> <tbody> <tr> <td>1 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>2 Apples</td><td>Oranges</td><td>Plum</td> </tr> .... <tbody> </table> </div> </div>
This shows the wrapping
of the th
header cell contents into div
elements.
No more tricks needed for this. This is the layout part. One of the few pure CSS soutions I can believe in. I also tried this out on complex pages with further relative and absolute parents, it works everywhere.
You can view this example also on my hompage.
Click here to see full source code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | <!DOCTYPE HTML> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>Fixed table header</title> <style type="text/css"> .headerSiding { position: relative; /* need a non-static position */ padding-top: 1.4em; /* place for the fixed header */ } .scrollPane { height: 20em; /* without height no scrollbar ever */ overflow: auto; /* show scrollbar when needed */ } .scrollPane th div { position: absolute; /* pinned to next non-static parent */ top: 0; /* at top of parent */ } </style> </head> <body style="margin-left: 25%; margin-right: 25%;"> <!-- center contents --> <h1>Table with CSS-only Fixed Header</h1> <div class="headerSiding"> <div class="scrollPane"> <table> <thead> <tr> <th><div>One</div></th><th><div>Two</div></th><th><div>Three</div></th> </tr> </thead> <tbody> <tr> <td>1 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>2 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>3 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>4 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>5 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>6 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>7 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>8 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>9 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>10 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>11 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>12 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>13 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>14 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>15 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>16 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>17 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>18 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>19 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>20 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>21 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>22 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>23 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>24 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>25 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>26 Apples</td><td>Oranges</td><td>Plum</td> </tr> <tr> <td>27 Apples</td><td>Oranges</td><td>Plum</td> </tr> </tbody> </table> </div> </div> </body> </html> |
Keine Kommentare:
Kommentar veröffentlichen