Header and footer for print in CSS

HTML and CSS are very convenient languages for preparing reports. Code generation is a much simpler task than generating .docx or .xlsx files. And although they were originally created to describe documents and are to some extent adapted to formatting the printout, they can still cause a lot of trouble in some circumstances. One of them is the ability to prepare a header and footer for each page of the printout.

I could not find a dedicated solution; there are code snippets like position: running (header); on the internet, but simply put – they just don’t work. So it is necessary – unfortunately – to use some tricks.

First, we need to insert an element that will be repeated on each page. It turns out, however, that it is enough to set its position parameter to fixed. An example header and footer might then look like this:

div.header {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    width: 100%;
    height: 15mm;
    background-image: url(/img/header.png);
    background-repeat: no-repeat;
    background-size: 180pt;
    background-position: right top;
}

div.footer {
    position: fixed;
    left: 0;
    bottom: 0;
    right: 0;
    width: 100%;
    height: 15mm;
    background-image: url(/img/footer.png);
    background-repeat: no-repeat;
    background-size: 250pt;
    background-position: right bottom;
}
<div class="header"></div>
<div class="footer"></div>

This fixes the display of the header and footer on each page of the printout. Unfortunately, however, there is another problem, as position: fixed; takes them out of the normal layout, what in turn causes them to blend in with the page content.

Of course, we could solve the problem with a block with margin, but then we go back to the starting point again: we would also have to repeat this margin on each page. And here comes the second trick: the table header and footer are repeated by default on each page.

So we introduce two additional styles for the blocks, which will become our margins, and then we organize the entire content of the page into a table with a properly constructed header and footer.

div.header-spacer {
    height: 15mm;
}

div.footer-spacer {
    height: 15mm;
}
<table>
    <thead>
        <tr>
            <td><div class="header-spacer"></div></td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                
                <!-- HERE GOES PAGE CONTENT -->
                
            </td>
        </tr>
    </tbody>

    <tfoot>
        <tr>
            <td>
                <div class="footer-spacer"></div>
            </td>
        </tr>
    </tfoot>
</table>

It’s not perfect, of course, but at least it works and doesn’t cause too many problems with formatting the page content.