skip to content

What does @media print change about how a page is styled in CSS, and which properties control page breaks and printed backgrounds?

level: middleimportance: nice to knowfreq 22%

answer

  1. no viewport, pages instead
  2. mostly a subtraction stylesheet
  3. break-inside is the workhorse
  4. ink is not free by default
  5. save-as-PDF runs this code

basics

~20 s

@media print applies only when a page is rendered to paper or PDF, where content is paginated instead of scrolled. Use break-inside, break-before and break-after to control pagination, @page for margins and sheet size, and print-color-adjust: exact to keep backgrounds the browser would otherwise drop.

solid answer

~50 s

`@media print` matches only when the document is being rendered for paper or PDF, and the rendering model changes: there is no viewport to scroll, content is broken into fixed-size pages, fixed positioning and scroll containers stop being meaningful, and browsers drop background colours and images by default to save ink. A print stylesheet is mostly subtraction — hide navigation, sidebars and cookie banners, drop multi-column layout to a single flow, and often expose link targets with `a[href]::after { content: " (" attr(href) ")" }`. Pagination is controlled with the fragmentation properties: `break-inside: avoid` to keep a table row or figure whole, `break-before: page` to force a new sheet, plus `orphans` and `widows` for stray lines. The `@page` rule sets sheet margins and `size`. If a background genuinely carries meaning, `print-color-adjust: exact` asks the browser to honour it — Safari still wants the `-webkit-` prefixed spelling.

code

css · 15 lines
css
@page {
  size: A4;
  margin: 20mm;
}

@media print {
  nav, .sidebar, .cookie-banner { display: none; }

  body { font-size: 11pt; color: #000; }

  figure, tr, pre { break-inside: avoid; }
  h1 { break-before: page; }

  a[href^="http"]::after { content: " (" attr(href) ")"; }
}

go deeper

for a junior

Know that @media print applies when printing or saving as PDF, and that the first job is hiding navigation and other screen-only chrome so the content prints alone.

for a middle

Explain that print is paged rather than scrolled, name break-inside: avoid and break-before: page for pagination, and know that browsers drop backgrounds unless print-color-adjust asks otherwise.

for a senior

Show you have shipped a document-generation path: overflow containers truncating content, fixed elements stamping every page, tables splitting mid-row, and why colour alone must never carry meaning on paper.

for a principal

Decide whether browser printing is the right mechanism at all for the product's documents versus a server-side renderer, and own the consequences for fidelity, pagination control and long-term maintenance.

## A different rendering model `print` is one of the small set of media types that still matter (`all`, `screen`, `print`, `speech`). `@media print` matches when the user prints, when they open print preview, and when they "save as PDF" — that last one is why print styles are worth more than their reputation: invoices, tickets, reports and receipts are usually generated by a browser printing an HTML page. The model differs from screen in ways that break assumptions: - There is **no scrolling viewport**. Content is fragmented across pages of a fixed size. - **`position: fixed`** elements no longer stick to a scrolling viewport; browsers may repeat or drop them, and a fixed header often ends up printed once at the top or on every page depending on the engine. Sticky headers, floating action buttons and cookie banners routinely print as blobs of ink. - **Scroll containers** cannot scroll, so `overflow: hidden` or `auto` on a tall region silently truncates the content to whatever fits. - **Backgrounds are omitted by default.** Browsers suppress background colours and images unless the user ticks "Background graphics", on the reasonable assumption that nobody wants a full-bleed dark hero rendered in toner. - **Viewport units are meaningless.** `100vh` resolves against the page box, not a screen, so full-height sections behave nothing like they do on screen. ## What a print stylesheet usually contains Mostly removals and simplifications: ```css @media print { nav, .sidebar, .cookie-banner, .share-buttons { display: none; } body { color: #000; background: #fff; } .layout { display: block; } /* collapse the grid to one flow */ a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 90%; } } ``` That last rule is the classic print idiom: a printed link is a dead end unless its destination is visible, so the URL is appended as generated content. Restrict it to absolute URLs, or every in-page anchor prints a fragment of noise. ## Controlling pagination The fragmentation properties tell the engine where it may and may not break: - `break-inside: avoid` — do not split this box across pages. The workhorse: apply it to figures, table rows, cards and code blocks so they do not get sliced in half. - `break-before: page` / `break-after: page` — force a new sheet, e.g. `h1 { break-before: page; }` to start each chapter on its own page. - `orphans` and `widows` — the minimum number of lines of a paragraph that may be left at the bottom of one page or carried to the top of the next; both default to 2. The older `page-break-inside` / `page-break-before` / `page-break-after` properties are the CSS 2.1 spelling and are now aliases of the `break-*` family. New code should use `break-*`; you will still meet the old names in existing stylesheets. ## The `@page` rule `@page` styles the page box itself rather than any element: ```css @page { size: A4; margin: 20mm; } @page :first { margin-top: 40mm; } ``` `size` accepts a named sheet (`A4`, `letter`) and/or an orientation (`landscape`), and `margin` sets the printable margin. The `:first`, `:left` and `:right` page pseudo-classes let a cover page or a bound edge differ. Engine support beyond `size` and `margin` is uneven, so keep expectations modest — running headers and footers via `@page` margin boxes are largely unimplemented in browsers. ## Backgrounds you actually need When a background carries meaning — a status chip, a striped table for legibility, a coloured header on a certificate — ask for it explicitly: ```css @media print { .status-chip { print-color-adjust: exact; -webkit-print-color-adjust: exact; } } ``` This is a *request*, not a guarantee: the user's own "Background graphics" setting and the printer driver still have the final say. The prefixed spelling remains necessary for Safari, which is one of the few places a vendor prefix is still load-bearing rather than legacy noise. A more robust design does not depend on colour at all — a status that reads "Paid" in text survives a black-and-white printer; a green pill does not. ## Using physical units Print is the one context where absolute units are appropriate rather than a smell. `pt`, `mm` and `cm` mean real physical measurements on paper, so `@page { margin: 20mm }` and `body { font-size: 11pt }` inside a print block are conventional. On screen the same units are a mistake, since they ignore the user's text-size preference. ## Testing Printing to PDF exercises the same code path and is the fastest loop. Check the obvious failure modes: content truncated inside an `overflow` container, a table split mid-row, a fixed header stamped on every page, and links whose destinations vanished.

  • A printed table keeps splitting rows across pages. What do you change?
    Apply `break-inside: avoid` to the rows — `@media print { tr { break-inside: avoid; } }` — so the engine moves a whole row to the next page rather than slicing it. `thead` repeating on each page is the browser's default for real table markup. The legacy `page-break-inside: avoid` is the CSS 2.1 spelling of the same thing and still works as an alias.
  • Why do fixed-position elements cause trouble in print, and what do you do about them?
    There is no scrolling viewport in paged media, so a fixed element has nothing to stick to; engines variously print it once, print it on every page, or overlap it with content. Sticky headers, floating buttons and chat widgets are the usual culprits. The reliable fix is to hide them in the print block and, where a header is genuinely wanted on every page, accept that browsers do not support running headers well.
  • Can you rely on print-color-adjust: exact to guarantee a coloured background prints?
    No. It requests that the browser preserve the colours rather than optimise them away, but the user's "Background graphics" checkbox, the print dialog and the driver all outrank it, and a monochrome printer ignores colour entirely. Treat it as an improvement, and make sure the meaning survives without colour — a text label rather than a coloured pill alone.

saying these in an interview costs you the question

  • Assumes screen layout prints unchanged
  • Believes backgrounds print by default
  • Only knows page-break-* and not the break-* properties
  • Uses pt and mm for on-screen typography
  • Ignores that save-as-PDF triggers the print stylesheet

context