This article will teach you everything you need to get started writing CSS for pages that are intended to be printed.
You might be building a page for your web app that will be converted to PDF. Or, maybe you just want your site's existing pages to look good when a user prints them.
The @media rule
If you've done any responsive design, you'll already know about the @media
rule. As well as different screen sizes, @media
also lets you target "print" media. Here's an example:
@media print {
/* These styles will only be used when the page is printed or saved to PDF. */
h1 { font-size: 16pt; }
}
Using this rule, you can specify your standard CSS as normal and then add some custom styles that will only be used when printing.
p { margin: 1em 0; }
@media print {
/* Hide related article links when printing. */
.related-articles { display: none; }
}
If you want to "zero out" all your standard screen styles and start from
scratch, you can wrap your screen styles in another @media
rule:
@media screen {
/* standard styles here. */
}
@media print {
/* print styles here. */
}
Page break properties
To make sure the content flows smoothly across pages, you'll want to control when content gets split between pages. For example, it looks awkward if a large heading appears at the bottom of a page - you want it to start on a new page instead. Similarly, you may want to avoid a table spanning multiple pages if possible.
You can do this using page-break-before
, page-break-after
, and page-break-inside
. You can set the value for these properties to always
or avoid
.
h1 {
/* h1 elements always start on the top of a new page. */
page-break-before: always;
}
section.city-map {
/* this section always occupies it's own page or pages. */
page-break-before: always;
page-break-after: always;
}
table {
/* tables don't split across pages if possible. */
page-break-inside: avoid;
}
Tip: Repeat table headings
If your document has tables that span multiple pages, it'll be hard to read when printed unless the table headers are repeated at the start of each page. This is pretty easy to accomplish - just use the thead
and tbody
elements in your table.
<table>
<thead>
<tr>
<th>City</th>
<th>Population</th>
</thead>
<tbody>
<tr>
<td>Sydney</td>
<td>4.627 million (2018)</td>
</tr>
</tbody>
</table>
When printed, your table will then look something like this:
Tip: Adding or removing content
Sometimes you might want to add content that's only shown when printing. For example - you might want to link URLs to be printed. You can do this by using the :after
pseudo-element:
@media print {
a[href]:after {
content: " (" attr(href) ")";
}
}
You might also want to hide or show certain elements only when printing. By combining @media
and display
this can be done quite easily.
/* hide the watermark on screens. */
.watermark {
display: none;
}
@media print {
/* hide the navidation when printing. */
nav {
display: hide;
}
/* show the watermark when printing */
.watermark {
display: initial;
}
}
Tip: Use emulate CSS media for development
To speed up your feedback loop during development, you can set your browser to display print styles. To do this in Chrome on Mac, open developer tools, then use the command-shift-P shortcut for "Run Command" and search for "Emulate CSS print media type".
Other browsers will have a similar feature in their dev tools.
Unfortunately to see page breaks you'll need to print to PDF manually each time.
Advanced tip: Orphans and widows
The orphans
and widows
properties control how text in an element is split across pages. Sometimes tweaking these values can improve the readability of your printed document.
p {
/* if there aren't at least three lines before the page
break, move the element to the start of a new page. */
orphans: 3;
}
On the left below, orphans
is set to 2, so the second paragraph begins
before the page break. By setting orphans
to 3, as on the right, the
paragraph is forced down to the start of the next page.
The widows
property is the opposite of orphans
- it specifies the minimum number of lines that can be at the start of a new page.
Advanced tip: the @page rule
With the @page
rule, you can customise the page margin for specific pages.
@page:first {
/* No margin on the first page. */
margin: 0;
}
@page {
/* Set a margin on all other pages. */
margin: 2cm;
}
Unfortunately, browser support for this is currently a little limited and you
can only use the :first
, :last
, :left
, :right
and :blank
pseudo-selectors to select pages.
Summary
You're now familiar with the important properties for print layout that are supported by modern browsers like Chrome, Firefox and Safari.
Unfortunately support for more advanced print layout features in modern
browsers is generally limited. For example, browsers don't provide a standard way of adding custom header or footer content using CSS. You may want to check out the paged.js project which offers a polyfill for many of the print layout features browsers are currently missing.
Top comments (0)