DocRaptor

Header and Footer Tips

It’s been a while since we last talked about headers and footers in PDFs, and we’ve learned a lot about how best to use them in the interim. Here’s a list of best practices and gotchas, in no particular order.

There are a couple of general ways to do this. The first is using the CSS property string-set. The pieces we need are pretty simple — a couple of CSS rules and one piece of HTML:

/* Set the content of an H1 to the identifier "doctitle" */
h1 { string-set: doctitle content(); }
/* Use the value from "doctitle" as the content for headers */
@page {
  @top { content: string(doctitle); }
}
<h1>A Curious Document of Dubious Origin</h1>

a sample document using string-set

The second way to use content from your document involves a technique called “static flows”. It is also achieved using a very small amount of CSS and HTML:

/* The content of the h1 will only be usable via the flow CSS property */
h1 { flow: static(header); }
/* Use the value from "header" as the content for the page header */
@page {
  @top { content: flow(header); }
}
<h1>A Curious Document of Dubious Origin</h1>

a header example using static flow

Note in this example output the content of the h1 is not shown in the document itself, because that content has been flow‘ed into the header. This allows us to create complicated headers. Here is a comparison between string-set and flow when that h1‘s text becomes a link:

a comparison of string-set and static flow using a link in the content

As you can see, string-set strips out the anchor element and only uses its text. It goes even further than that, though! We recently had a customer who was having issues with string-set stripping spaces, in the sense that three spaces would be turned into one. If you are using a font where spaces are important, then you should not use string-set.

This is a gotcha that has gotten us, and many of our customers! Header and footer content cannot be used on pages prior to the page on which that content appears. Here is a demonstrative example using static flow:

/* The content of the h1 will only be usable via the flow CSS property */
h1 { flow: static(header); }
/* Use the value from "header" as the content for the page header */
@page {
   @top { content: flow(header); }
}
/* make a page break */
hr { page-break-after: always; }
<p>Page 1 content.</p>
<hr />
<p>Page 2 content.</p>
<h1>A Header</h1>
<hr />
<p>Page 3 content.</p>

headers are only used on or after the page the content appears on

As you can see, the content placement must be considered, but also this opens up a door to having lots of different header and footer content to us.

Building on the sample from the previous section, here’s how one might easily achieve chapter headings for an ebook or other partitioned content:

/* The content of the h2 be used in the header */
h2 { flow: static(header); }
/* Use the DOM elements from "header" as the content for the page header */
@page {
  @top { content: flow(header); }
}
/* force page breaks */
h1, hr { page-break-after: always; }
<h1>A <em>Very</em> Short Book</h1>
<h2>Chapter 1</h2>
<p>Chapter 1 content.</p>
<hr />
<p>Another page in chapter 1.</p>
<hr />
<h2>Chapter 2</h2>
<p>Chapter 2 content.</p>

a short book sample using statically flowed header content

And that’s all the news that’s fit to print. We hope that helps you get started when you do complicated header layouts! Have a great tip of your own you want us to publish? Let us know!