Print Styles
Print stylesheets control how web content appears when printed or saved as PDF. While the web is primarily screen-based, many applications require high-quality print output — invoices, receipts, articles, reports, tickets, and documentation.
CSS provides dedicated features for print: the @media print media query, @page rules for page sizing and margins, and properties for controlling page breaks. A well-crafted print stylesheet turns a screen-first design into a clean, ink-efficient document.
| 1 | @media print { |
| 2 | /* Hide non-printable content */ |
| 3 | nav, footer, .sidebar, .ads { |
| 4 | display: none !important; |
| 5 | } |
| 6 | |
| 7 | /* Ensure text is readable in print */ |
| 8 | body { |
| 9 | font-size: 12pt; |
| 10 | line-height: 1.5; |
| 11 | color: #000; |
| 12 | background: #fff; |
| 13 | } |
| 14 | |
| 15 | /* Show URLs after links */ |
| 16 | a[href]::after { |
| 17 | content: " (" attr(href) ")"; |
| 18 | font-size: 0.8em; |
| 19 | color: #333; |
| 20 | } |
| 21 | } |
The @media print query targets printers and print-to-PDF scenarios. Styles inside this block override screen styles when the user prints or generates a PDF.
| 1 | /* Load print stylesheet conditionally */ |
| 2 | <link rel="stylesheet" href="print.css" media="print" /> |
| 3 | |
| 4 | /* Or use inline media queries */ |
| 5 | @media print { |
| 6 | /* Override screen-specific styles */ |
| 7 | body { |
| 8 | background: white; |
| 9 | color: black; |
| 10 | font-size: 12pt; |
| 11 | } |
| 12 | |
| 13 | /* Remove interactive elements */ |
| 14 | .no-print { display: none; } |
| 15 | |
| 16 | /* Ensure backgrounds print */ |
| 17 | * { |
| 18 | -webkit-print-color-adjust: exact; |
| 19 | print-color-adjust: exact; |
| 20 | } |
| 21 | } |
info
The @page at-rule controls the printed page dimensions, margins, and pseudo-selectors for first, blank, and left/right pages.
| 1 | /* Global page settings */ |
| 2 | @page { |
| 3 | size: A4; /* A4 paper (default varies by locale) */ |
| 4 | margin: 20mm 15mm; /* margins around the page */ |
| 5 | size: letter; /* US letter */ |
| 6 | size: A4 landscape; /* landscape orientation */ |
| 7 | size: 210mm 297mm; /* custom dimensions */ |
| 8 | } |
| 9 | |
| 10 | /* First page */ |
| 11 | @page :first { |
| 12 | margin-top: 30mm; /* extra margin for first page */ |
| 13 | } |
| 14 | |
| 15 | /* Left and right pages (for booklets) */ |
| 16 | @page :left { |
| 17 | margin-left: 25mm; |
| 18 | margin-right: 15mm; |
| 19 | } |
| 20 | |
| 21 | @page :right { |
| 22 | margin-left: 15mm; |
| 23 | margin-right: 25mm; |
| 24 | } |
| 25 | |
| 26 | /* Blank pages */ |
| 27 | @page :blank { |
| 28 | @top-center { |
| 29 | content: "This page intentionally left blank"; |
| 30 | } |
| 31 | } |
orphans and widows
| 1 | /* orphans: minimum lines at bottom of page */ |
| 2 | p { orphans: 3; } |
| 3 | |
| 4 | /* widows: minimum lines at top of next page */ |
| 5 | p { widows: 3; } |
| 6 | |
| 7 | /* Prevent single lines stranded alone */ |
| 8 | p { |
| 9 | orphans: 3; |
| 10 | widows: 3; |
| 11 | } |
page-break Controls
| 1 | /* Page-break before an element */ |
| 2 | h1 { page-break-before: always; } |
| 3 | .page-break { page-break-before: always; } |
| 4 | |
| 5 | /* Page-break after */ |
| 6 | section { page-break-after: always; } |
| 7 | |
| 8 | /* Avoid page breaks inside */ |
| 9 | pre, table, img, code { |
| 10 | page-break-inside: avoid; |
| 11 | } |
| 12 | |
| 13 | /* Modern properties (newer browsers) */ |
| 14 | h1 { break-before: page; } |
| 15 | section { break-after: page; } |
| 16 | pre { break-inside: avoid; } |
| 17 | |
| 18 | /* Keep related content together */ |
| 19 | h2 { |
| 20 | break-after: avoid; /* keep heading with following content */ |
| 21 | } |
| 22 | |
| 23 | ul { |
| 24 | break-inside: avoid; /* keep list on one page if possible */ |
| 25 | } |
Many page elements have no value in print — navigation, sidebars, ads, videos, interactive widgets, and modals. The print stylesheet should hide these aggressively.
| 1 | @media print { |
| 2 | /* Hide entire sections */ |
| 3 | nav, footer, .sidebar, .ads, |
| 4 | .video-player, .interactive, |
| 5 | .modal, .toolbar, .search-bar, |
| 6 | .comments, .related-posts { |
| 7 | display: none !important; |
| 8 | } |
| 9 | |
| 10 | /* Hide background images to save ink */ |
| 11 | * { |
| 12 | background-image: none !important; |
| 13 | } |
| 14 | |
| 15 | /* But keep background colors for important elements */ |
| 16 | .highlight { |
| 17 | background: #f0f0f0 !important; |
| 18 | -webkit-print-color-adjust: exact; |
| 19 | } |
| 20 | |
| 21 | /* Show only print-friendly content */ |
| 22 | .print-only { |
| 23 | display: block !important; |
| 24 | } |
| 25 | |
| 26 | /* Hide elements with no-print class */ |
| 27 | .no-print { |
| 28 | display: none !important; |
| 29 | } |
| 30 | } |
| 31 | |
| 32 | /* Elements that only show in print */ |
| 33 | .print-only { |
| 34 | display: none; |
| 35 | } |
best practice
Screen and print have different rendering characteristics. Print requires higher contrast, serif fonts for readability, and ink-conscious color choices.
| 1 | @media print { |
| 2 | /* Fonts */ |
| 3 | body { |
| 4 | font-family: Georgia, 'Times New Roman', serif; |
| 5 | font-size: 12pt; |
| 6 | line-height: 1.6; |
| 7 | } |
| 8 | |
| 9 | code, pre { |
| 10 | font-family: 'Courier New', Courier, monospace; |
| 11 | font-size: 10pt; |
| 12 | } |
| 13 | |
| 14 | h1, h2, h3, h4 { |
| 15 | font-family: 'Helvetica', Arial, sans-serif; |
| 16 | page-break-after: avoid; |
| 17 | } |
| 18 | |
| 19 | /* Colors — high contrast for print */ |
| 20 | body { |
| 21 | color: #000; |
| 22 | background: #fff; |
| 23 | } |
| 24 | |
| 25 | a { |
| 26 | color: #000; |
| 27 | text-decoration: underline; |
| 28 | } |
| 29 | |
| 30 | /* Ensure colored backgrounds print */ |
| 31 | .bg-highlight { |
| 32 | background: #f5f5f5 !important; |
| 33 | -webkit-print-color-adjust: exact; |
| 34 | print-color-adjust: exact; |
| 35 | } |
| 36 | } |
warning
Hyperlinks lose their interactivity on paper. Showing the destination URL after each link makes printouts useful — readers can manually visit referenced pages.
| 1 | @media print { |
| 2 | /* Show full URLs after links */ |
| 3 | a[href]::after { |
| 4 | content: " (" attr(href) ")"; |
| 5 | font-size: 0.8em; |
| 6 | color: #555; |
| 7 | font-weight: normal; |
| 8 | } |
| 9 | |
| 10 | /* Skip internal links and anchors */ |
| 11 | a[href^="#"]::after, |
| 12 | a[href^="javascript:"]::after { |
| 13 | content: ""; |
| 14 | } |
| 15 | |
| 16 | /* Show email addresses */ |
| 17 | a[href^="mailto:"]::after { |
| 18 | content: " (" attr(href) ")"; |
| 19 | } |
| 20 | |
| 21 | /* Styling */ |
| 22 | a { |
| 23 | text-decoration: underline; |
| 24 | color: #000; |
| 25 | } |
| 26 | } |
QR codes bridge the gap between print and digital. Include print-only QR codes that link to dynamic content, downloads, or digital versions of printed materials.
| 1 | /* Print-only QR code container */ |
| 2 | .print-only .qr-code { |
| 3 | display: flex; |
| 4 | align-items: center; |
| 5 | gap: 16px; |
| 6 | margin-top: 24px; |
| 7 | padding: 16px; |
| 8 | border: 1px solid #ccc; |
| 9 | border-radius: 4px; |
| 10 | } |
| 11 | |
| 12 | .print-only .qr-code img { |
| 13 | width: 80px; |
| 14 | height: 80px; |
| 15 | } |
| 16 | |
| 17 | .print-only .qr-text { |
| 18 | font-size: 9pt; |
| 19 | color: #333; |
| 20 | } |
| 21 | |
| 22 | /* Hide QR on screen */ |
| 23 | .qr-code { |
| 24 | display: none; |
| 25 | } |
| 26 | |
| 27 | @media print { |
| 28 | .qr-code { |
| 29 | display: flex; |
| 30 | } |
| 31 | } |
Generate QR codes server-side or via an API (e.g., https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=URL) and include them as images in your print layout.
| 1 | /* print.css — full print stylesheet */ |
| 2 | |
| 3 | @page { |
| 4 | size: A4; |
| 5 | margin: 20mm 15mm; |
| 6 | } |
| 7 | |
| 8 | @page :first { |
| 9 | margin-top: 30mm; |
| 10 | } |
| 11 | |
| 12 | @media print { |
| 13 | /* Reset */ |
| 14 | * { |
| 15 | background: transparent !important; |
| 16 | color: #000 !important; |
| 17 | box-shadow: none !important; |
| 18 | text-shadow: none !important; |
| 19 | } |
| 20 | |
| 21 | /* Hide non-print content */ |
| 22 | nav, footer, .sidebar, .ads, .no-print, |
| 23 | .print-button, video, audio, canvas { |
| 24 | display: none !important; |
| 25 | } |
| 26 | |
| 27 | /* Show print-only */ |
| 28 | .print-only { display: block !important; } |
| 29 | |
| 30 | /* Typography */ |
| 31 | body { |
| 32 | font: 12pt/1.6 Georgia, 'Times New Roman', serif; |
| 33 | } |
| 34 | |
| 35 | h1, h2, h3 { |
| 36 | font-family: Helvetica, Arial, sans-serif; |
| 37 | page-break-after: avoid; |
| 38 | } |
| 39 | |
| 40 | /* Links */ |
| 41 | a[href]::after { |
| 42 | content: " (" attr(href) ")"; |
| 43 | font-size: 0.8em; |
| 44 | color: #555 !important; |
| 45 | } |
| 46 | |
| 47 | a[href^="#"]::after { content: ""; } |
| 48 | |
| 49 | /* Page breaks */ |
| 50 | h1, h2 { page-break-after: avoid; } |
| 51 | pre, table, img { page-break-inside: avoid; } |
| 52 | section { page-break-before: auto; } |
| 53 | |
| 54 | /* Tables */ |
| 55 | table { font-size: 10pt; border-collapse: collapse; } |
| 56 | th, td { border: 1pt solid #999; padding: 4pt; } |
| 57 | |
| 58 | /* Code */ |
| 59 | code, pre { |
| 60 | font: 10pt/1.4 'Courier New', monospace; |
| 61 | border: 1pt solid #ccc; |
| 62 | padding: 4pt; |
| 63 | } |
| 64 | |
| 65 | /* Prevent orphaned lines */ |
| 66 | p, li { orphans: 3; widows: 3; } |
| 67 | } |