Make Web Pages Print Like a Polished Report: Practical @media print Tricks That Clients Love
TL;DR Summary: Optimize your web pages for professional printouts easily with @media print tricks. Hide unnecessary elements, force clean page breaks, maintain brand colors, use fallbacks for charts, and ensure consistent formatting. Impress clients with agency-ready reports by following these straightforward steps. Read the full guide for practical tips on enhancing your print layouts.
Web Developers: How to Optimize a Web Page for Print
Most “Export to PDF” buttons spit out ugly pages. Headers, nav, and buttons get printed. Charts disappear. Fonts switch to Times. It looks amateur. The fix is simple: treat print like a first-class layout target.
This post shows exactly how to do that using plain CSS and a few HTML hooks. No heavy libraries. No theme rewrites. Just targeted changes that make your pages print like agency-ready reports.
The Big Idea
Give your report page a dedicated print layer:
- Use
@media printto hide chrome and show print-only blocks - Force page breaks so sections start cleanly
- Keep your brand colors and gradients
- Use predictable chart fallbacks that render in headless PDF
- Lock in sans-serif fonts so nothing flips to Times
Do this once and every client deliverable looks “premium.”
1. Start with a print stylesheet
Add a print section to the page or your site CSS. This hides navigation, footer junk, and little UI buttons that would look weird on paper.
@media print {
/* Page box and margins */
@page {
size: Letter; /* or A4 */
margin: 16mm 14mm;
}
/* Kill site chrome */
header, footer, nav,
.site-header, .site-footer,
.topbar, .page-footer,
.actions, .btn {
display: none !important;
}
/* Remove drop shadows that muddy in print */
.card, .panel, .widget {
box-shadow: none !important;
}
/* Don’t append raw URLs after links */
a[href]:after { content: '' !important; }
/* Keep colors and gradients */
* {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
/* Page-break hygiene */
h1, h2, h3 { break-after: avoid; }
.card, .table-wrap { page-break-inside: avoid; }
/* Hide screen-only elements, show print-only */
.screen-only { display: none !important; }
.print-only { display: block !important; }
}Why it matters: clients don’t want buttons in a PDF. They want clean sections that look intentional.
2. Force clean page breaks where it counts
If you know two sections should never share a page, drop a marker before the next one.
@media print {
.page-break {
page-break-before: always; /* legacy-friendly */
break-before: always; /* modern */
}
}<div class="page-break"></div>
<div class="card">
<h2>AI Analysis</h2>
...
</div>
<div class="page-break"></div>
<div class="card">
<h2>Quick Keyword Wins</h2>
...
</div>Tip: put the break before a section header. The section reads like a new chapter.
3. Lock the look: fonts, sizes, spacing
Browsers often switch fonts in print. Force a sane stack.
@media print {
html, body {
font-family: Inter, Helvetica, Arial, sans-serif;
color: #111;
font-size: 13px;
line-height: 1.4;
background: #fff !important;
}
}4. Keep your brand colors and gradients
Gradients and brand colors make a report look like it came from a product, not a spreadsheet. Most headless renderers respect -webkit-print-color-adjust: exact. Keep it on and avoid fancy blend modes.
Simple branded progress bar:
<div style="height:18px;background:#eef2f7;border:1px solid #e5e7eb;border-radius:10px;overflow:hidden;">
<div style="height:100%;width:82%;background:linear-gradient(90deg,#2973C1,#3CB371);"></div>
</div>5. Charts that actually print
Canvas charts often vanish in print. Use a graceful fallback:
- On the web: CSS bars, small canvas, or SVG
- In print/PDF: a tiny server-generated PNG or inline SVG
Hide the web chart in print and show the fallback:
@media print {
canvas.screen-only { display: none !important; }
.print-only { display: block !important; }
}Example stacked bar as a PNG for print:
<?php
// Make a 360x20 PNG bar from segments
$W=360; $H=20;
$img=imagecreatetruecolor($W,$H);
imagealphablending($img,true); imagesavealpha($img,true);
$transparent=imagecolorallocatealpha($img,0,0,0,127);
imagefilledrectangle($img,0,0,$W,$H,$transparent);
// background and border
$bg=imagecolorallocate($img,238,242,247); // #eef2f7
$bd=imagecolorallocate($img,209,213,219); // #d1d5db
imagefilledrectangle($img,0,0,$W-1,$H-1,$bg);
imagerectangle($img,0,0,$W-1,$H-1,$bd);
// segments (pass/soft/fail/na)
$segs = [
['w' => (int)round(($W-2)*($pass/100)), 'c' => imagecolorallocate($img,22,163,74)],
['w' => (int)round(($W-2)*($soft/100)), 'c' => imagecolorallocate($img,245,158,11)],
['w' => (int)round(($W-2)*($fail/100)), 'c' => imagecolorallocate($img,220,38,38)],
];
$used = array_sum(array_column($segs,'w'));
$segs[] = ['w'=>max(0,($W-2)-$used),'c'=>imagecolorallocate($img,156,163,175)];
$x=1;
foreach ($segs as $s) {
if ($s['w']<=0) continue;
imagefilledrectangle($img,$x,1,$x+$s['w']-1,$H-2,$s['c']);
$x += $s['w'];
}
ob_start(); imagepng($img); $png=ob_get_clean(); imagedestroy($img);
echo '<img class="print-only" style="display:block;margin:8px auto" src="data:image/png;base64,'.base64_encode($png).'" alt="Technical Health">';
?>This gives you consistent bars in PDFs without leaning on a JS charting library.
6. Sticky table headers on new pages
Long tables are easier to read if headers reappear after a page break. Many PDF engines respect this trick:
@media print {
table thead th {
position: sticky; /* or 'repeating-header' in some engines */
top: 0;
background: #f5f7fa !important;
border-bottom: 1px solid #e5e7eb;
}
}Not guaranteed everywhere, but often works in modern Chromium-based print.
7. Centering that always works
Margins can fail in print. Wrap the element in a centered container and use inline-block.
<div style="text-align:center">
<img class="print-only" style="display:inline-block;margin:8px auto;width:420px;height:18px" src="...">
</div>Same trick works for inline SVG.
8. Screenshot blocks that don’t break
Base64-inline the screenshot in print so you don’t depend on external fetches at PDF time:
<?php
$path = __DIR__.'/screenshots/'.$filename;
if (file_exists($path)) {
$b64 = base64_encode(file_get_contents($path));
echo '<img class="shot" src="data:image/jpeg;base64,'.$b64.'" alt="Homepage screenshot">';
} else {
echo '<div class="muted">No screenshot available yet.</div>';
}
?>9. Make it clean/white-label by default
- Hide nav, footer, login links, export buttons in print
- Avoid printing raw URLs after links
- Use neutral badges and muted tip copy
- Put your brand in headers and progress bars, not watermarks
10. Quick checklist before you ship
- Page breaks at the start of big sections
- All canvases have print fallbacks
- Colors and gradients preserved
- Sans-serif fonts locked in
- Tables don’t explode the layout
- Bars and charts are centered
- No random site chrome in the PDF
You don’t need a report builder framework. A little @media print, a couple of page breaks, and pragmatic fallbacks go a long way. If you’re handing reports to clients or selling white-label SEO deliverables, this is the polish that separates you from “just screenshots.”
📄 Download a PDF of This Article

