I'd like to have my table's headers repeated for every printed page, but it seems Google Chrome doesn't support the <thead>
tag well...is there a way around this? I'm using Google Chrome v13.0.782.215.
The table code is very straightforward...nothing fancy:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css" media="all">
@page {
size: landscape;
margin-top: 0;
margin-bottom: 1cm;
margin-left: 0;
margin-right: 0;
}
table {
border: .02em solid #666; border-collapse:collapse;
width:100%;
}
td, th {
border: .02em solid #666; font-size:12px; line-height: 12px;
vertical-align:middle; padding:5px; font-family:"Arial";
}
th { text-align:left; font-size:12px; font-weight:bold; }
h2 { margin-bottom: 0; }
</style>
</head>
<body>
<h2>Page Title</h2>
<table>
<thead>
<tr class="row1">
<th><strong>Heading 1</strong></th>
<th><strong>Heading 2</strong></th>
<th><strong>Heading 3</strong></th>
<th><strong>Heading 4</strong></th>
<th><strong>Heading 5</strong></th>
</tr>
</thead>
<tbody>
<tr class="row2">
<td width="30">...</td>
<td width="30">...</td>
<td width="90">....</td>
<td width="190">...</td>
<td width="420">...</td>
</tr>
<tr class="row1">
<td width="30">...</td>
<td width="30">...</td>
<td width="90">....</td>
<td width="190">...</td>
<td width="420">...</td>
</tr>
....
</tbody>
</table>
</body>
</html>
Any insight into this is welcome.
for in-company browser based systems, i advice users to use firefox or IE instead;for websites intended for the public, i think we can't really do anything about it if users user chrome or browsers with similar limitations (opera also)
now it's possible to print in chrome using jQuery.... please try this code (i'm sorry forget who's the creator of this code before i modified - and my english language is not good :D hehehe)
UPDATE 2017-03-22: Repeating table headers have finally been implemented in Chrome! (Actually, I think they were implemented some time ago.) That means you probably don't need this solution anymore; just put your column headers in a
<thead>
tag and you should be all set. Use the solution below only if:SOLUTION (obsolete)
The code below demonstrates the best method I've found for multi-page table printing. It has the following features:
... and the following known limitations:
<thead>
(which is apparently the most you're allowed to have anyway)<tfoot>
(though Chrome-compatible running footers are technically possible)<caption>
margin
; to add white space above or below the table, insert an empty div and set a bottom margin on itborder-width
andline-height
) must be inpx
Column widths can't be set by applying width values to individual table cells; you should either let cell content automatically determine column width, or use
<col>s
to set specific widths if neededTable can't (easily) be changed dynamically after the JS has run
THE CODE
HOW IT WORKS (If you don't care, read no further; everything you need is above.)
Per @Kingsolmn's request, below is an explanation of how this solution works. It doesn't cover the JavaScript, which isn't strictly required (though it does make this technique much easier to use). Instead, it focuses on the generated HTML structures and associated CSS, which is where the real magic happens.
Here's the table we'll be working with:
(To save space, I gave it only 3 data rows; obviously, a multipage table would usually have more)
The first thing we need to do is split the table into a series of smaller tables, each with its own copy of the column headers. I call these smaller tables fauxRows.
The fauxRows are essentially clones of the original table, but with only one data row apiece. (If your table has a caption, though, only the top fauxRow should include it.)
Next we need to make the fauxRows unbreakable. What does that mean? (Pay attention-- this is probably the most important concept in page break handling.) "Unbreakable" is the term I use to describe a block of content that can't be split between two pages*. When a page break occurs within the space occupied by such a block, the whole block moves to the next page. (Note that I'm using the word "block" informally here; I'm not referring specifically to block level elements.) This behavior has an interesting side-effect that we'll make use of later on: it can expose content that was initially hidden due to layering or overflow.
We can make the fauxRows unbreakable by applying either of the following CSS declarations:
page-break-inside: avoid;
display: inline-table;
I usually use both, because the first is made for this purpose and the second works in older/noncompliant browsers. In this case, though, for simplicity's sake, I'll stick to the page-break property. Note that you will not see any change in the table's appearance after adding this property.
Now that the fauxRows are unbreakable, if a page break occurs within a data row, it will shift to the next page along with its attached header row. So the next page will always have column headers at the top, which is our goal. But the table looks very strange now with all the extra header rows. To make it look like a normal table again, we need to hide the extra headers in such a way that they'll appear only when needed.
What we're going to do is put each fauxRow in a container element with
overflow: hidden;
and then shift it upward so that the headers get clipped by the top of the container. This will also move the data rows back together so that they appear contiguous.Your first instinct might be to use divs for the containers, but we're going to use the cells of a parent table instead. I'll explain why later, but for now, let's just add the code. (Once again, this will not affect the table's appearance.)
Notice the CSS above the table markup. I added it for two reasons: first, it prevents the parent table from adding white space between the fauxRows; second, it makes the header height predictable, which is necessary since we're not using JavaScript to calculate it dynamically.
Now we just need to shift the fauxRows upward, which we'll do with negative margins. But it's not as simple as you might think. If we add a negative margin directly to a fauxRow, it will remain in effect when the fauxRow gets bumped to the next page, causing the headers to get clipped by the top of the page. We need a way to leave the negative margin behind.
To accomplish this, we'll insert an empty div above each fauxRow after the first and add the negative margin to it. (The first fauxRow is skipped because its headers should always be visible.) Since the margin is on a separate element, it won't follow the fauxRow to the next page, and the headers won't be clipped. I call these empty divs headerHiders.
That's it, we're done! On screen, the table should now look normal, with only one set of column headers at the top. In print, it should now have running headers.
If you were wondering why we used a parent table instead of a bunch of container divs, it's because Chrome/webkit has a bug that causes a div-enclosed unbreakable block to carry its container to the next page with it. Since the headerHider is also in the container, it won't get left behind like it's supposed to, which leads to clipped headers. This bug only happens if the unbreakable block is the topmost element in the div with a non-zero height.
I did discover a workaround while writing this tutorial: you just have to explicitly set
height: 0;
on the headerHider and give it an empty child div with a non-zero height. Then you can use a div container. I still prefer to use a parent table, though, because it has been more thoroughly tested, and it salvages the semantics to some extent by tying the fauxRows back together into a single table.EDIT: I just realized that the JavaScript-generated markup is slightly different in that it puts each fauxRow in a separate container table, and assigns the "fauxRow" className to it (the container). This would be required for footer support, which I intended to add someday but never did. If I were to update the JS, I might consider switching to div containers since my semantic justification for using a table doesn't apply.
* There is one situation in which an unbreakable block can be split between two pages: when it exceeds the height of the printable area. You should try to avoid this scenario; you're essentially asking the browser to do the impossible, and it can have some very strange effects on the output.
I believe this is a bug in Chrome.
This is an enhancement still not available in Webkit, Blink, and Vivliostyle, rather than in other more "print oriented formatters" (Firefox, IE).
You can check the issue for Google Chrome since version 4 here (6 years and 45 versions ago!), where we can appreciate it's got an owner lately (February 2016), who even seems to be working on it.
Some talk has been also held in the W3 where we can appreciate the concern upon it's usefulness:
Meanwhile, the JS and Jquery codes from @DoctorDestructo and @thefredzx have been really useful for my users not using Firefox nor IE (most of them).
The first one to be aware of a new version that includes this feature, should notice it in here, many of us would appreciate it.
From my testing in chrome setting
display: table-row-group;
to the thead stops the issue happening.eg if you try to print the below without the style you will see number on top of each page but if you add the style it only appears oncontextmenu.