Professional Documents
Culture Documents
Designing For Print With CSS
Designing For Print With CSS
Designing For Print With CSS
If you mention printing with CSS to many people who work on the
web, print style sheets are the use that comes to mind. We are all
well used to creating a style sheet that is called upon when a web
document is printed. These style sheets ensure that the print
version is legible and that we don’t cause a user to print out huge
images. However, CSS is also being used to format books, catalogs
and brochures — content that may never have been designed to be a
web page at all.
In this article, we’ll take a look at the CSS modules that have been created
not for use in web browsers, but to deal with printed and paged media. I’ll
explain how the selectors, properties and values that they introduce work.
I’ll finish up with a working example that you can use as a starting point for
your own experiments. For that example, we’ll need a user agent that
supports this specialized CSS. I’ll be using Prince, which is a commercial
product. However, Prince has a free version that can be used for non-
commercial use, making it a good tool to try out these examples.
It may seem a bit strange that content not particularly destined for the web
should be maintained as HTML and formatted with CSS. It seems less
strange when you realize that popular eReader formats such as EPUB and
MOBI (↦ https://www.smashingmagazine.com/2011/09/how-to-make-an-
ebook/) are HTML and CSS under the hood. In addition, even if the entirety
of a manuscript or catalog isn’t to be published on a website, some of it
likely will be. HTML becomes a handy format to standardize on, far easier
to deal with than having everything in a Word document or a traditional
desktop publishing package.
Paged media introduces concepts that make no sense on the web. For
example, you need to be able to generate page numbers, put chapter titles
in margins, break content appropriately in order that figures don’t become
disassociated from their captions. You might need to create cross-
references and footnotes, indexes and tables of content from your
document. You could import the document into a desktop publishing
package and create all of this by hand, however, the work would then need
redoing the next time you update the copy. This is where CSS comes in,
whose specifications are designed for use in creating paged media.
Much of the CSS you already know will be useful for formatting for print.
Specifically for print, we have the “CSS Paged Media Module (↦
http://www.w3.org/TR/css3-page/)” and the “CSS Generated Content for
Paged Media Module (↦ http://www.w3.org/TR/css-gcpm-3/)” specifications.
Let’s look at how these work.
The @page rule lets you specify various aspects of a page box. For
example, you will want to specify the dimensions of your pages. The rule
below specifies a default page size of 5.5 by 8.5 inches. If you intend to
print a book, perhaps by a print-on-demand service, then finding out the
sizes you can use is important.
@page {
In addition to specifying sizes with length values, you may also use paper
size keywords, such as “A4” or “legal.”
@page {
size: A4;
You may also use a keyword to specify the page’s orientation — “portrait”
or “landscape.”
@page {
size: A4 landscape;
Before going any further, we should understand how the page model for
paged media works, because it behaves somewhat differently to how
things work on screen.
The page model defines a page area and then 16 surrounding margin
boxes (↦ http://www.w3.org/TR/css3-page/#margin-boxes). You can control
the size of the page area and the size of the margin between the edge of
the page area and the end of the page itself. The table in the specification
explains very well how these boxes are sized.
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-
adb4-46f01eedd629/05d0cb51-22ec-4eaf-93c0-222f16de6136/1-image-margin-
boxes-large-opt.jpg)
The page area is the space on the page into which your page’s content will
flow. When it runs out of room, another page will be created. The margin
boxes are used only for CSS-generated content.
@page :left {
margin-left: 3cm;
@page :right {
margin-left: 4cm;
Two other pseudo-class selectors are defined. The :first selector targets
the first page of a document.
@page :first {
@page :blank {
@page:right{
@bottom-left {
font-size: 9pt;
color: #333;
h1 {
To avoid breaks directly after a heading, use page-break-after .
page-break-after: avoid;
table, figure {
page-break-inside: avoid;
COUNTERS # ( ↦ #COUNTERS)
Books are all about numbering things — pages, chapters, even figures. We
can actually add these numbers via CSS, saving us from having to
renumber everything because we decided to, say, add a new figure partway
through a chapter. We do this using CSS counters (↦
https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Counters).
The obvious place to start is with page numbers. CSS gives us a predefined
page counter; it starts at 1 and increments with every new page. In your
style sheet, you would use this counter as the value of generated content,
to put the page counter in one of your margin boxes. In the example below,
we are adding page numbers to the bottom-right of right-hand pages and
the bottom-left of left-hand pages.
@page:right{
}
@page:left{
@bottom-left {
content: counter(page);
We’ve also created a counter named pages . This counter will always be the
total number of pages in your document. If you want to output “Page 3 of
120,” you can.
@page:left{
@bottom-left {
You can create your own named counters and increment and reset them as
you require. To create a counter, use the counter-reset property, increment
it with counter-increment . The CSS rules below will create a counter for
chapters named chapternum and increment it with each h1 — being the
start of a chapter in this book. We then use the value of that counter in
generated content to add the chapter number and a period before the
chapter’s actual title.
body {
counter-reset: chapternum;
h1.chapter:before {
We can do the same for figures in the book. A common way to number
figures is to use chapternum.figurenum . So, “Figure 3-2” would be the
second figure in chapter 3. On the h1 , we could reset figurenum in order
that it starts from 1 for each chapter.
body {
h1 {
counter-reset: figurenum;
h1.title:before {
counter-increment: chapternum;
figcaption:before {
counter-increment: figurenum;
Take a look at a printed book again. As you leaf through a chapter, you’ll
probably see that the chapter’s title is printed on the left or right page. As
strange as it may sound, the “Generated Content for Paged Media”
specification lets us achieve this using CSS.
h1 {
@page :right {
@top-right {
content: string(doctitle);
font-size: 8pt;
When your paged media is generated, each time an h1 occurs, the content
is written to doctitle and then outputted in the top-right margin box of
right-hand pages, changing only when another h1 occurs.
FOOTNOTES # ( ↦ #FOOTNOTES)
Footnotes are a part of the “CSS Generated Content for Paged Media
Module (↦ http://www.w3.org/TR/css-gcpm-3/#footnotes)” specification. The
way footnotes work is that you would add the text of your footnote inline,
wrapped in HTML tags (probably a span), with a class to identify it as a
footnote. When the page is generated, the content of that “footnote
element” is removed and turned into a footnote.
In your CSS, use the footnote value of the float property to create a rule
for your footnote class.
.fn {
float: footnote;
In your document, use that class to wrap any footnote text.
from the flow when the page is created.</span> are useful in books and
printed documents.</p>
Footnotes have a predefined counter that behaves in the same way as the
page counter. Typically, you will want to increment the counter by 1 each
time a fn class occurs and reset it at the beginning of each chapter.
.fn {
counter-increment: footnote;
h1 {
counter-reset: footnote;
.fn::footnote-call {
content: counter(footnote);
font-size: 9pt;
vertical-align: super;
The footnote-marker is the numeric marker placed in front of the footnote
text in the footer of your document. These behave in a similar way to the
numbers generated for an ordered list in CSS.
.fn::footnote-marker {
font-weight: bold;
The footnotes themselves are placed in the margin, within a special area of
the page named @footnote . You would target and style that area as
follows.
@page {
@footnote {
CROSS-REFERENCES # ( ↦ #CROSS-REFERENCES)
Then, after the link, use generated content again to output (page x) , where
x is the number of the location in the book where that ID can be found.
a.xref:after {
To actually create a book using this CSS, you’ll need a user agent that
supports it. Currently, very few things implement this specification well; the
one that is most accessible is Prince (↦ http://princexml.com). A standalone
commercial license for Prince is expensive, however, you may use Prince
free of charge for non-commercial projects. This means that if you just
want to try out these techniques, you can. Additionally, if you do have non-
commercial uses for this technology, you may use Prince to format those
books.
cd /Users/username/smashing-css-books
This will create a PDF in the builds folder named book.pdf . Now, if you
make any changes to the CSS or HTML, you can run Prince to see what is
different.
</head>
<body>
<div class="frontcover">
</div>
<div class="contents">
<h1>Extracts from Our Cats and All About Them by Harrison Weir</h1>
<ul class="toc">
</ul>
</div>
<p>… </p>
<p>… </p>
<p>… </p>
The CSS then uses all of the things we have described so far. To start, we
need to set up a size for the book using the @page rule. We then use the
:first pseudo-class selector to remove the margin on page 1, because
this page will have the cover image.
@page {
@page:first {
margin: 0;
We then deal with the image for the front cover, making sure that it covers
the whole page area.
div.frontcover {
page: cover;
content: url("images/cover.png");
width: 100%;
height: 100%;
}
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-
adb4-46f01eedd629/5ee0fcc9-3571-46c3-ba46-748501f1ea81/2-image-cover-
large-opt.jpg)
The right-hand spread will have the title of the book in the bottom-left
margin box, a page counter in the bottom-right, and the chapter’s title in
the top-right. The chapter’s title is set using string-set further down in
the style sheet.
@page:right{
@bottom-left {
font-size: 9pt;
color: #333;
@bottom-right {
content: counter(page);
font-size: 9pt;
@top-right {
content: string(doctitle);
font-size: 9pt;
color: #333;
}
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-
adb4-46f01eedd629/d4fc5b92-5748-419f-9568-bbc4f3bf00cb/3-image-spread-
right-large-opt.jpg)
The left-hand spread has the book’s title in the bottom-right and the page
counter in the bottom-left.
margin 10pt 0 30pt 0;
font-size: 9pt;
color: #333;
@bottom-left {
content: counter(page);
font-size: 9pt;
}
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-
adb4-46f01eedd629/9bfc8005-0c07-4b1e-80df-78bd374a0c09/4-image-spread-
left-large-opt.jpg)
For the first page, which contains the cover image, we’ll make sure that no
generated content appears by setting it to normal .
@page:first {
@bottom-right {
content: normal;
margin: 0;
@bottom-left {
content: normal;
margin: 0;
The next section of the style sheet deals with counters. In addition to the
preset page counter, we are defining counters for chapters and figures.
body {
line-height: 1.5;
font-size: 11pt;
/* Get the title of the current chapter, which will be the content of the
h1.
h1 {
page-break-before: always;
counter-reset: figurenum;
counter-reset: footnote;
line-height: 1.3;
h1.chapter:before {
counter-increment: chapternum;
figcaption:before {
counter-increment: figurenum;
}
Chapters now have their number placed before the title. Figures also
display their number.
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-
adb4-46f01eedd629/db3caf7f-a4a4-48ab-95a0-1cc8dd86ff82/5-image-figure-
number-large-opt.jpg)
.fn {
float: footnote;
.fn {
counter-increment: footnote;
.fn::footnote-call {
content: counter(footnote);
}
.fn::footnote-marker {
font-weight: bold;
@page {
@footnote {
padding-top: 8pt;
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-
adb4-46f01eedd629/c8703cde-60dd-4725-88ce-320fd9c55dc6/6-image-
footnotes-large-opt.jpg)
We then add some rules to control where pages break. You need to be fairly
careful about being too heavy handed with this. If your book has a lot of
tables and figures, then adding many specific rules here could cause a lot
of long gaps in the book. Experimenting and testing will show how far you
can take the control of breaks. I have found the rules below to be a good
starting point.
font-weight: bold;
page-break-after: avoid;
page-break-inside:avoid;
page-break-before: avoid;
table, figure {
page-break-inside: avoid;
Finally, we style the table of contents, and we use an interesting trick here.
When describing cross-references, I explained how we use target-counter
to display the page number that the ID is on. This is what we’ll do for our
table of contents. The rule below puts the page number after the link to
each chapter in the table of contents.
ul.toc a::after {
}
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-
adb4-46f01eedd629/05a27cd1-64c5-47ff-b4a4-8da05c568141/7-image-toc-
numbers-large-opt.jpg)
Commonly in books, however, you would use leader dots to line up all of
the page numbers against the right margin. Amazingly, CSS gives us a way
to do this, by adding leader() before the number in the generated content.
ul.toc a::after {
}
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-
adb4-46f01eedd629/df43c974-fde2-4455-86de-37c1bd3e8e90/8-image-toc-
leader-large-opt.jpg)
We now have a complete style sheet with which to build our book. I’ve
avoided spending a lot of time on typography here, concentrating instead
on the specifics of creating a book. From this point, however, you can
experiment and add your own styles to create a unique book design.
Remember that these techniques are not just for books. You could use
them to generate print and PDF versions of a product catalog directly from
the HTML of a website that you have developed for a client. Or you could
create flyers and brochures from web content.
If you want to create PDF documents from a website using Prince, then
DocRaptor (↦ https://docraptor.com/) is a great option. This service uses
Prince via an API. You can send documents via the API and receive a PDF
— perfect for allowing users to download content as a PDF on the fly.
Everything we have looked at in this article is possible via an API
integration with DocRaptor.
Even if you don’t have an immediate need for PDF generation, it’s a
fascinating aspect of CSS — and it’s a useful skill to have tucked away, so
that you know what is possible when a use case presents itself.
Explore more on
Print(↦ /category/print)