How to Create Printer-friendly Pages with CSS
ShareThis article was updated in 2020 to reflect latest best practices in CSS print styling.
In this article, we review the art of creating printer-friendly web pages with CSS.
“Who prints web pages?” I hear you cry! Relatively few pages will ever be reproduced on paper. But consider:
- printing travel or concert tickets
- reproducing route directions or timetables
- saving a copy for offline reading
- accessing information in an area with poor connectivity
- using data in dangerous or dirty conditions — for example, a kitchen or factory
- outputting draft content for written annotations
- printing web receipts for bookkeeping purposes
- providing documents to those with disabilities who find it difficult to use a screen
- printing a page for your colleague who refuses to use this newfangled t’internet nonsense.
Unfortunately, printing pages can be a frustrating experience:
- text can be too small, too large, or too faint
- columns can be too narrow, too wide, or overflow page margins
- sections may be cropped or disappear entirely
- ink is wasted on unnecessary colored backgrounds and images
- link URLs can’t be seen
- icons, menus, and advertisements are printed which could never be clicked!
Many developers advocate web accessibility, yet few remember to make the printed web accessible!
Converting responsive, continuous media to paged paper of any size and orientation can be challenging. However, CSS print control has been possible for many years, and a basic style sheet can be completed within hours. The following sections describe well-supported and practical options for making your pages printer-friendly.
Print Style Sheets
Print CSS can either be:
- Applied in addition to screen styling. Taking your screen styles as a base, the printer styles override those defaults as necessary.
- Applied as separate styles. The screen and print styles are entirely separate; both start from the browser’s default styles.
The choice will depend on your site/app. Personally, I use screen styles as a print base most of the time. However, I have used separate style sheets for applications with radically different outputs — such as a conference session booking system which displayed a timetable grid on-screen but a chronological schedule on paper.
A print style sheet can be added to the HTML
<head>
after the standard style sheet:<span class="token tag"><span class="token punctuation"><</span>link <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>main.css<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token punctuation"><</span>link <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>print<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>print.css<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
The
print.css
styles will be applied in addition to screen styles when the page is printed.To separate screen and print media,
main.css
should target the screen only:<span class="token tag"><span class="token punctuation"><</span>link <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>screen<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>main.css<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token punctuation"><</span>link <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>print<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>print.css<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
Alternatively, print styles can be included within an existing CSS file using
@media
rules. For example:<span class="token comment">/* main.css */</span> <span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">2</span><span class="token unit">em</span><span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode color">#fff</span><span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token hexcode color">#000</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* override styles when printing */</span> <span class="token atrule"><span class="token rule">@media</span> print</span> <span class="token punctuation">{</span> <span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode color">#000</span><span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token hexcode color">#fff</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
Any number of
@media print
rules can be added, so this may be practical for keeping associated styles together. Screen and print rules can also be separated if necessary:<span class="token comment">/* main.css */</span> <span class="token comment">/* on-screen styles */</span> <span class="token atrule"><span class="token rule">@media</span> screen</span> <span class="token punctuation">{</span> <span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">2</span><span class="token unit">em</span><span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode color">#fff</span><span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token hexcode color">#000</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">/* print styles */</span> <span class="token atrule"><span class="token rule">@media</span> print</span> <span class="token punctuation">{</span> <span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token hexcode color">#000</span><span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token hexcode color">#fff</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
Testing Printer Output
It’s not necessary to kill trees and use outrageously expensive ink every time you want to test your print layout! The following options replicate print styles on-screen.
Print Preview
The most reliable option is the print preview option in your browser. This shows how page breaks will be handled using your default paper size.
Alternatively, you may be able to save or preview the page by exporting to a PDF.
Developer Tools
The DevTools (F12 or Cmd/Ctrl + Shift + I) can emulate print styles, although page breaks won’t be shown.
In Chrome, open the Developer Tools and select More Tools, then Rendering from the three-dot icon menu at the top right. Change the Emulate CSS Media to print at the bottom of that panel.
In Firefox, open the Developer Tools and click the Toggle print media simulation icon on the Inspector tab’s style pane:
Hack Your Media Attribute
Presuming you’re using a
<link>
tag to load printer CSS, you could temporarily change themedia
attribute toscreen
:<span class="token tag"><span class="token punctuation"><</span>link <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>main.css<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token punctuation"><</span>link <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>screen<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>print.css<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
Again, this won’t reveal page breaks. Don’t forget to restore the attribute to
media="print"
once you finish testing.Remove Unnecessary Sections
Before doing anything else, remove and collapse redundant content with
display: none;
. Typical unnecessary sections on paper could include navigation menus, hero images, headers, footers, forms, sidebars, social media widgets, and advertising blocks (usually anything in aniframe
):<span class="token comment">/* print.css */</span> <span class="token selector">header<span class="token punctuation">,</span> footer<span class="token punctuation">,</span> aside<span class="token punctuation">,</span> nav<span class="token punctuation">,</span> form<span class="token punctuation">,</span> iframe<span class="token punctuation">,</span> <span class="token class">.menu</span><span class="token punctuation">,</span> <span class="token class">.hero</span><span class="token punctuation">,</span> <span class="token class">.adslot</span></span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token punctuation">}</span>
It may be necessary to use
display: none !important;
if CSS or JavaScript functionality is showing elements according to particular UI states. Using!important
isn’t normally recommended, but we can justify its use in a basic set of printer styles which override screen defaults.Linearize the Layout
It pains me to say this, but Flexbox and Grid rarely play nicely with printer layouts in any browser. If you encounter issues, consider using
display: block;
or similar on layout boxes and adjust dimensions as necessary. For example, setwidth: 100%;
to span the full page width.Printer Styling
Printer-friendly styling can now be applied. Recommendations:
- ensure you use dark text on a white background
- consider using a serif font, which may be easier to read
- adjust the text size to
12pt
or higher- modify paddings and margins where necessary. Standard
cm
,mm
, orin
units may be more practical.Further suggestions include …
Adopt CSS Columns
Standard A4 and US Letter paper can result in longer and less readable lines of text. Consider using CSS columns in print layouts. For example:
<span class="token comment">/* print.css */</span> <span class="token selector">article</span> <span class="token punctuation">{</span> <span class="token property">column-width</span><span class="token punctuation">:</span> <span class="token number">17</span><span class="token unit">em</span><span class="token punctuation">;</span> <span class="token property">column-gap</span><span class="token punctuation">:</span> <span class="token number">3</span><span class="token unit">em</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
In this example, columns will be created when there’s at least
37em
of horizontal space. There’s no need to set media queries; additional columns will be added on wider paper.Use Borders Instead of Background Colors
Your template may have sections or call-out boxes denoted by darker or inverse color schemes:
Save ink by representing those elements with a border:
Remove or Invert Images
Users will not want to print decorative and non-essential images and backgrounds. You could consider a default where all images are hidden unless they have a
<span class="token comment">/* print.css */</span> <span class="token selector">*</span> <span class="token punctuation">{</span> <span class="token property">background-image</span><span class="token punctuation">:</span> none <span class="token important">!important</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">img<span class="token punctuation">,</span> svg</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> none <span class="token important">!important</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">img<span class="token class">.print</span><span class="token punctuation">,</span> svg<span class="token class">.print</span></span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span> <span class="token property">max-width</span><span class="token punctuation">:</span> <span class="token number">100</span><span class="token unit">%</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
Ideally, printed images should use dark colors on a light background. It may be possible to change HTML-embedded SVG colors in CSS, but there will be situations where you have darker bitmaps:
A CSS filter can be used to invert and adjust colors in the print style sheet. For example:
<span class="token comment">/* print.css */</span> <span class="token selector">img<span class="token class">.dark</span></span> <span class="token punctuation">{</span> <span class="token property">filter</span><span class="token punctuation">:</span> <span class="token function">invert</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token unit">%</span><span class="token punctuation">)</span> <span class="token function">hue-rotate</span><span class="token punctuation">(</span><span class="token number">180</span><span class="token unit">deg</span><span class="token punctuation">)</span> <span class="token function">brightness</span><span class="token punctuation">(</span><span class="token number">120</span><span class="token unit">%</span><span class="token punctuation">)</span> <span class="token function">contrast</span><span class="token punctuation">(</span><span class="token number">150</span><span class="token unit">%</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
The result:
Add Supplementary Content
Printed media often requires additional information which would not be necessary on-screen. The CSS
content
property can be employed to append text to::before
and::after
pseudo-elements. For example, display a link’s URL in brackets after the text:<span class="token comment">/* print.css */</span> <span class="token selector">a<span class="token pseudo-element">::after</span></span> <span class="token punctuation">{</span> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">" ("</span> <span class="token function">attr</span><span class="token punctuation">(</span>href<span class="token punctuation">)</span> <span class="token string">")"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
Or you can add print-only messages:
<span class="token comment">/* print.css */</span> <span class="token selector">main<span class="token pseudo-element">::after</span></span> <span class="token punctuation">{</span> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">"Copyright site.com"</span><span class="token punctuation">;</span> <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token punctuation">}</span>
For more complex situations, consider using a class such as
<span class="token tag"><span class="token punctuation"><</span>p <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>print<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Article printed at 1:23pm 5 September 2020. Please see https://site.com/page for the latest version.<span class="token tag"><span class="token punctuation"></</span>p<span class="token punctuation">></span></span>
The CSS:
<span class="token comment">/* hidden on-screen */</span> <span class="token selector"><span class="token class">.print</span></span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token atrule"><span class="token rule">@media</span> print</span> <span class="token punctuation">{</span> <span class="token comment">/* visible when printed */</span> <span class="token selector"><span class="token class">.print</span></span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
Note: most browsers display the URL and current date/time on the printed page’s header and/or footer, so there’s rarely a need to generate this information in code.
Page Breaks
The CSS3 properties
break-before
andbreak-after
allow you control how page, column, or region breaks behave before and after an element. Support is excellent, but older browsers may use the similarpage-break-before
andpage-break-after
properties.The following
break-before
andbreak-after
values can be used:
auto
: the default — a break is permitted but not forcedavoid
: avoid a break on the page, column or regionavoid-page
: avoid a page breakpage
: force a page breakalways
: an alias ofpage
left
: force page breaks so the next is a left pageright
: force page breaks so the next is a right pageExample: force a page break immediately prior to any
<h1>
heading:<span class="token comment">/* print.css */</span> <span class="token selector">h1</span> <span class="token punctuation">{</span> <span class="token property">break-before</span><span class="token punctuation">:</span> always<span class="token punctuation">;</span> <span class="token punctuation">}</span>
Note: be wary of over-using page breaks. Ideally, printer output should use as few pages as possible.
The
break-inside
(and olderpage-break-inside
) property specifies whether a page break is permitted inside an element. The commonly supported values:
auto
: the default — a break is permitted but not forcedavoid
: avoid an inner break where possibleavoid-page
: avoid an inner page break where possibleThis can be preferable to specifying page breaks, since you can use as little paper as possible while avoiding page breaks within grouped data such as tables or images:
<span class="token comment">/* print.css */</span> <span class="token selector">table<span class="token punctuation">,</span> img<span class="token punctuation">,</span> svg</span> <span class="token punctuation">{</span> <span class="token property">break-inside</span><span class="token punctuation">:</span> avoid<span class="token punctuation">;</span> <span class="token punctuation">}</span>
The
widows
property specifies the minimum number of lines in a block that must be shown at the top of a page. Imagine a block with five lines of text. The browser wants to make a page break after line four so the last line appears at the top of the next page. Settingwidows: 3;
breaks on or before line two so at least three lines carry over to the next page.The
orphans
property is similar towidows
except it controls the minimum number of lines to show at the bottom of a page.The
box-decoration-break
property controls element borders across pages. When an element with a border has an inner page break:
slice
: the default, splits the layout. The top border is shown on the first page and the bottom border is shown on the second page.clone
: replicates the margin, padding, and border. All four borders are shown on both pages.Finally, CSS Paged Media (
@page
) has limited browser support but provides a way to target specific pages so alternative margins or breaks can be defined:<span class="token comment">/* print.css */</span> <span class="token comment">/* target all pages */</span> <span class="token atrule"><span class="token rule">@page</span></span> <span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">2</span><span class="token unit">cm</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* target the first page only */</span> <span class="token atrule"><span class="token rule">@page</span> <span class="token punctuation">:</span>first</span> <span class="token punctuation">{</span> <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token number">6</span><span class="token unit">cm</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* target left (even-numbered) pages only */</span> <span class="token atrule"><span class="token rule">@page</span> <span class="token punctuation">:</span>left</span> <span class="token punctuation">{</span> <span class="token property">margin-right</span><span class="token punctuation">:</span> <span class="token number">4</span><span class="token unit">cm</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* target right (odd-numbered) pages only */</span> <span class="token atrule"><span class="token rule">@page</span> <span class="token punctuation">:</span>right</span> <span class="token punctuation">{</span> <span class="token property">margin-left</span><span class="token punctuation">:</span> <span class="token number">4</span><span class="token unit">cm</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
The CSS page break properties can be placed within your
screen
orBe aware that page break control is little more than a suggestion to the browser. There’s no guarantee a break will be forced or avoided because layout is restricted to the confines of the paper.
Printing Pains
Control over printing web media will always be limited, and results can vary across browsers. That said:
- printer-friendly style sheets can be retro-fitted to any site
- most printer styling will work in the majority of browsers
- print styles will not affect or break existing functionality
- the development costs are minimal.
Adding a few page breaks and removing unnecessary sections will delight users and raise your site above competitors. Add it to your to-do list!
For more advanced CSS knowledge, read our book, CSS Master, 2nd Edition.
How to Create Printer-friendly Pages with CSS
Pages: 1 2