Fix bad printing: a custom @media print stylesheet for any site
You hit Ctrl+P on a long article and the preview is a disaster: the navigation bar eats the first page, the sidebar overlaps the text, a cookie bar floats over paragraph three, and a solid dark background is about to drain your printer cartridge. The site just never wrote a print stylesheet. So write one yourself — it lives in a JustZix CSS rule and it makes "Save as PDF" usable again.
Why most sites print badly
Printing is the most ignored part of web development. Designers test on screens; QA tests on screens; nobody opens the print preview. The result is that a huge share of the web has either no @media print block at all, or one written years ago that no longer matches the layout. The browser then prints the screen layout as-is — fixed headers, multi-column grids, dark themes and all.
The fix is a CSS rule that only applies when the page is being printed. Everything inside @media print { ... } is invisible on screen and only kicks in for paper and PDF export. That means you can be aggressive: hide whole regions, recolor everything, force single-column — none of it touches normal browsing.
Step 1 — hide everything that is not content
Navigation, sidebars, footers, share widgets, cookie bars, sticky "subscribe" boxes: none of it belongs on paper. Start by hiding the obvious chrome.
@media print {
header, nav, aside, footer,
.sidebar, .site-header, .site-footer,
.cookie-banner, .newsletter, .share-bar,
.ad, [class*="advert" i], [id*="cookie" i],
[role="banner"], [role="navigation"],
[aria-label*="cookie" i] {
display: none !important;
}
}
If the page still prints junk, open the print preview, find the offending block in DevTools, and add its selector to the list. You only need to do this once per site — the rule is saved.
Step 2 — expand truncated content
Many sites clamp text to a few lines, hide overflow, or put the article in a fixed-height scrolling box. On screen that is fine; on paper it cuts your content off. Undo the clamping.
@media print {
/* Kill height limits and scroll boxes */
main, article, .content, .post-body {
height: auto !important;
max-height: none !important;
overflow: visible !important;
}
/* Undo line-clamp truncation */
* {
-webkit-line-clamp: unset !important;
overflow: visible !important;
}
/* Force the article full width, drop the grid */
body, main, article {
display: block !important;
width: 100% !important;
max-width: 100% !important;
margin: 0 !important;
float: none !important;
}
}
The blanket overflow: visible on * looks heavy-handed, but inside @media print it is exactly what you want — nothing should be clipped on a printout.
Step 3 — control page breaks
The single biggest improvement to a printout is stopping things from breaking across pages mid-element. A code block split over two sheets, a heading stranded at the bottom of a page, a table row torn in half — all fixable with the fragmentation properties.
@media print {
/* Never split these across a page */
pre, blockquote, table, figure, img,
li, .card {
break-inside: avoid;
}
/* Keep a heading with the text that follows it */
h1, h2, h3, h4 {
break-after: avoid;
}
/* Start each top-level section on a fresh page */
.chapter, section.page {
break-before: page;
}
}
The modern properties are break-inside, break-before and break-after. The old page-break-* names still work and Chrome maps them automatically, but write the new ones for new rules.
Step 4 — show link URLs after anchors
A printed link is useless — the reader cannot click "click here". Print the actual URL next to it using a generated-content trick.
@media print {
a[href^="http"]::after {
content: " (" attr(href) ")";
font-size: 0.85em;
color: #555;
word-break: break-all;
}
/* Don't print URLs for in-page anchors or javascript: links */
a[href^="#"]::after,
a[href^="javascript:"]::after {
content: "";
}
}
This pulls the href attribute into visible text. Skip it for anchor links and image links if it gets noisy — a printout full of long tracking URLs is its own kind of mess.
Step 5 — set margins with @page
The @page rule controls the printed sheet itself: its margins and size. Browsers also let you set margins in the print dialog, but baking them into the rule means every print of that site is consistent.
@media print {
@page {
margin: 18mm 16mm;
size: A4;
}
/* Tighter margin on the first page if you have a title block */
@page :first {
margin-top: 12mm;
}
}
Step 6 — force a light background to save ink
Dark-themed sites print as a wall of toner. By default Chrome strips background colors when printing (unless "Background graphics" is ticked), but text often stays light gray on the assumption of a dark backdrop. Force a clean black-on-white.
@media print {
html, body, * {
background: #fff !important;
background-image: none !important;
color: #000 !important;
box-shadow: none !important;
text-shadow: none !important;
}
/* Keep images and real photos intact */
img, svg, video { filter: none !important; }
/* Slightly soften secondary text so it still reads as secondary */
.muted, .meta, time, small { color: #444 !important; }
}
This guarantees readable, ink-cheap output regardless of the site's theme — and it pairs well with turning off "Background graphics" in the print dialog.
Putting it together in JustZix
- Create a rule scoped to the site you print from often — for example
https://docs.example.com/*. - Paste all six blocks into the CSS pane, wrapped in one
@media print(or keep separate blocks — both work). - Open the page, hit Ctrl+P, and watch the preview. Iterate: anything still wrong gets a selector added.
- Sync your key so the same clean print setup follows you to every device.
Because the whole thing sits inside @media print, you can leave the rule active permanently. It is dormant during normal browsing and only wakes up when you print or export a PDF.
Pitfalls worth knowing
- Background graphics toggle — Chrome's print dialog has a "Background graphics" checkbox that overrides some of your color choices. Your
!importantrules still win for foreground, but test both states. - Fixed/sticky elements repeat on every printed page in some browsers. If a header keeps showing up, set
position: static !importanton it inside the print block. - Generated URLs can wrap badly — that is why we add
word-break: break-all; without it a long URL pushes the layout sideways. - Don't hide too much — captions, figure credits and author bylines are content, not chrome. Be specific with your hide list.
See also
- A responsive debugging overlay — find layout problems before they reach the printout.
- Copy a page as clean Markdown — another way to get content off a messy page.
A good print stylesheet is a one-time, fifteen-minute job that pays off every single time you save a PDF. Install JustZix, scope a rule to your most-printed site, and never fight the print preview again.
Rate this post
No ratings yet — be the first.