Last week I was tasked with porting a couple of reports for a client from Crystal Reports to HTML/CSS, so I thought I’d document my trials here. Luckily because this was running on a server and the printing was initiated on the server side, I was able to focus just on one browser (Internet Explorer 8) rather than ensuring wide cross-browser compatibility.
The Goal
Generate an invoice with a header repeated at the top of every page and with a footer fixed to the bottom of only the last page. Here’s a quick round up of the approaches I tried.
Position: Fixed
According to the CSS 2.1 specification, “In the case of the print media type, the box is rendered on every page, and is fixed with respect to the page box…”. This would work for the header, but since the box is taken out of the normal flow, so you’ll need to account for that so it doesn’t overlay your content. If your header/footer is a variable height, this is less than ideal.
Table Based Layout
According to the HTML4 specification, “the table head and foot information may be repeated on each page that contains table data.” This works great for the header, but in my case, didn’t fit the bill as the footer needed to display on the last page only. Internet Explorer 8 supports this splendidly, unfortunately the same can’t be said for some other browsers we typically consider to be superior (see below).
Position: Absolute
The CSS 2.1 specification makes no mention of how absolutely positioned boxes should be handled in the case of the print media type. In the case of Internet Explorer 8, it seems that the box will be absolutely positioned with respect to the page upon which it would render based on it’s location in the HTML. For example, making the footer one of the last elements in the HTML document allowed the footer to be absolutely positioned to the bottom of the last page, which for my case was perfect.
One caveat to watch for is that because absolute positioning removes the box from the flow of the document, if your content takes 90% of the page and the footer takes 20% of the page, you will have 10% where the footer overlays the content. Since my footer was a variable height, I solved this by duplicating the footer element, keeping the second occurrence as absolutely positioned, however changing the first occurrence to static positioning (to stay in the flow of the document) but setting visibility: hidden;
so that it will maintain it’s dimensions yet not be visible. Given the same 90%/20% example from above, this solution causes the document to break to two pages, having all the content on one page and the footer fixed to the bottom of the second page.
Browser Support
Running the same report through the array of browsers I have installed locally, here’s a quick summary of my results.
Chrome 12 – Webkit doesn’t seem to support repeating thead
/tfoot
elements on each page (Bug 17205 and Bug 34218). Also treats absolutely positioned elements as if they were statically positioned, so the footer just follows directly after the content.
Safari 5 – Since it’s WebKit based, like Chrome, suffers same problems above.
Firefox 4 – Firefox gets the repeating thead
right, however the footer is placed at the bottom of the first page even thought it is one of the last elements in the source order.
Opera 11 – Opera doesn’t support repeating the thead
element on each page, and like Firefox, renders the absolutely positioned footer at the bottom of the first page as opposed to the last.
Internet Explorer 9 – IE9 properly repeats the thead
element on each page, however unlike IE8, it puts the footer at the bottom of the first page as opposed to the last.
Summary
Using a combination of table based layout and absolute positioning I was able to achieve exactly the result that was required in Internet Explorer 8. CSS3 looks like it will be giving some attention to the print media type, so it will be interesting to watch that develop. Given the wide range of how the same report renders with the print media type in different browsers, creating a very precise report that renders identically is more of a dream at this point. Focusing on one browser if you can, or possibly using a server side component to generate a PDF would be a much better approach to achieve cross-browser consistency.
Photo by bjmccray