The complete guide to print CSS

By

Build reliable print and PDF layouts with CSS media queries, @page, page breaks, tables, images, links, colors, browser debugging, and print testing.

~~~

A web page and a printed document need different layouts.

Navigation, forms, videos, and sticky buttons rarely belong on paper. Links lose their destinations. Long tables need headers on every page. Cards and images should not split in awkward places.

CSS gives us a separate print presentation without duplicating the HTML.

Start with a print media query

Put print-only rules inside @media print:

@media print {
  nav,
  footer,
  .newsletter-form {
    display: none;
  }
}

The browser applies these declarations in print preview, on paper, and when saving the page as a PDF.

Your normal styles still apply. Print rules override only what needs to change.

Use a separate print stylesheet

For a large print design, link a dedicated file:

<link rel="stylesheet" href="/print.css" media="print">

Use href, not src.

A separate file keeps print rules easy to find. An inline @media print block is simpler when you only have a few overrides.

Both approaches produce the same cascade.

Build a useful print baseline

Start by removing browser-oriented layout constraints:

@media print {
  body {
    margin: 0;
    color: #000;
    background: #fff;
    font: 11pt/1.5 Georgia, serif;
  }

  main {
    width: auto;
    max-width: none;
    margin: 0;
    padding: 0;
  }
}

Printers are good at black text on white paper. Removing decorative backgrounds also saves ink.

Point units make sense for type in print. Physical units such as mm, cm, and in are useful for page measurements.

Hide interface controls

Use a reusable class for elements that have no printed value:

@media print {
  .no-print {
    display: none !important;
  }
}

Typical candidates include:

Do not hide content just because it is interactive on screen. A form’s submitted values might still need a readable printed representation.

Show print-only content

Sometimes print needs extra context:

.print-only {
  display: none;
}

@media print {
  .print-only {
    display: block;
  }
}

Use this for a document title, print date, signature line, or short note explaining the source.

Keep important information in the HTML. CSS-generated content should enhance it, not carry the only copy of essential data.

Set page margins with @page

The @page rule controls the page box:

@page {
  margin: 18mm;
}

You can set the paper size and orientation:

@page {
  size: A4 portrait;
  margin: 18mm;
}

Or request landscape:

@page {
  size: A4 landscape;
}

The user can still choose a different paper size in the print dialog. Treat size as the intended format, not an absolute guarantee.

Style the first, left, and right pages

Paged media defines page pseudo-classes:

@page :first {
  margin-top: 30mm;
}

@page :left {
  margin-left: 22mm;
  margin-right: 16mm;
}

@page :right {
  margin-left: 16mm;
  margin-right: 22mm;
}

This is useful for book-like layouts where the binding needs extra space.

Browser support for advanced paged-media features is uneven. Test in every browser used to create the final PDF.

Force a page break

Use the modern fragmentation properties:

@media print {
  .chapter {
    break-before: page;
  }

  .chapter-end {
    break-after: page;
  }
}

Older code uses page-break-before and page-break-after. Browsers still support those aliases, but break-before and break-after are the current properties.

Do not add forced breaks after every section. Small changes in font rendering can otherwise create almost-empty pages.

Keep an element together

Use break-inside: avoid:

@media print {
  figure,
  table,
  blockquote,
  .card {
    break-inside: avoid;
  }
}

This is a request, not magic.

If an element is taller than a page, the browser must split it. Apply the rule to compact pieces such as figures and cards, not an entire long article.

Avoid lonely headings

A heading at the bottom of one page with its paragraph on the next looks broken.

Ask the browser to avoid a break after headings:

@media print {
  h1,
  h2,
  h3 {
    break-after: avoid-page;
  }
}

You can also keep a heading with a short section wrapper:

@media print {
  .section-intro {
    break-inside: avoid;
  }
}

Again, keep the wrapper small enough to fit on a page.

Control widows and orphans

widows and orphans control how many lines of a paragraph stay together across a page break:

@media print {
  p {
    orphans: 3;
    widows: 3;
  }
}

orphans is the minimum number of lines left at the bottom of a page.

widows is the minimum number carried to the top of the next page.

Support and exact pagination can vary, so treat these as quality hints.

Paper cannot open a link. You can append external URLs with generated content:

@media print {
  a[href^='http']::after {
    content: ' (' attr(href) ')';
    font-size: 0.85em;
    overflow-wrap: anywhere;
  }
}

This works well for articles and reference documents.

Skip links where the URL adds no value:

@media print {
  a[href^='#']::after,
  a[href^='javascript:']::after {
    content: '';
  }
}

Long tracking URLs can make a document unreadable. Consider printing a short canonical URL or collecting references in a dedicated list instead.

Color might disappear on a monochrome printer.

Use an underline:

@media print {
  a {
    color: inherit;
    text-decoration: underline;
  }
}

Do not rely on color alone to communicate meaning.

Make images fit the page

Prevent wide images from overflowing:

@media print {
  img,
  svg {
    max-width: 100%;
    height: auto;
  }

  figure {
    margin-inline: 0;
    break-inside: avoid;
  }
}

Background images and colors are often disabled by the user’s print settings. Use real <img> elements for content that must appear.

Add useful alt text in the HTML. It helps readers and gives the document a meaningful fallback if an image cannot print.

Control printed colors

Browsers may adjust colors to save ink.

For a part that requires exact colors, use:

@media print {
  .color-key {
    print-color-adjust: exact;
  }
}

The prefixed property is still useful for some browsers:

@media print {
  .color-key {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}

Use this sparingly. Exact backgrounds consume ink, and the user’s print settings can still win.

Always make the document understandable in grayscale.

Let the table use the available width:

@media print {
  table {
    width: 100%;
    border-collapse: collapse;
  }

  th,
  td {
    border: 1px solid #777;
    padding: 4pt;
    text-align: start;
  }
}

Use semantic table sections:

<table>
  <thead>...</thead>
  <tbody>...</tbody>
</table>

Browsers can repeat <thead> on each printed page. You can reinforce the display behavior:

@media print {
  thead {
    display: table-header-group;
  }

  tr {
    break-inside: avoid;
  }
}

Very wide tables need a deliberate plan. Use landscape pages, reduce columns, or create a separate print representation. Shrinking everything until it fits usually makes the result unreadable.

Expand collapsed interface content

Accordions and tabs can hide important content.

Prefer semantic HTML such as <details> and decide whether all sections should print open.

CSS cannot change the open attribute. A small print preparation script can open details before printing and restore them afterward:

const closedDetails = []

window.addEventListener('beforeprint', () => {
  document.querySelectorAll('details:not([open])').forEach(details => {
    closedDetails.push(details)
    details.open = true
  })
})

window.addEventListener('afterprint', () => {
  closedDetails.splice(0).forEach(details => {
    details.open = false
  })
})

Use JavaScript only when the CSS print layout cannot express the required state.

Add a print button

Call window.print() from a user action:

document.querySelector('#print').addEventListener('click', () => {
  window.print()
})

Hide the button in the printed result:

@media print {
  #print {
    display: none;
  }
}

The browser still owns the print dialog. JavaScript cannot silently choose the user’s printer and settings in a normal web page.

Debug print CSS in Chrome

You do not need to open print preview after every change.

In Chrome DevTools:

  1. Open the command menu.
  2. Search for Show Rendering.
  3. Find Emulate CSS media type.
  4. Choose print.

The page now renders with print media rules while DevTools stays open.

This emulates the media query, not final pagination. Open real print preview to inspect page breaks, margins, headers, and footers.

Test the final PDF

Print rendering differs between browser engines and operating systems.

Before shipping, check:

Also copy text from the PDF. A visually correct PDF can still have a confusing reading order if the HTML structure is poor.

Browser headers and footers

Print dialogs can add the page URL, date, title, and page number.

The user controls those settings. Normal page CSS cannot reliably remove browser-added headers and footers.

Advanced paged-media margin boxes can describe running headers and page numbers, but browser support is not consistent enough to depend on everywhere.

If exact book publishing is required, use a dedicated HTML-to-PDF engine and test against that engine’s supported CSS.

A complete starting stylesheet

Here is a small baseline you can adapt:

@page {
  size: A4;
  margin: 18mm;
}

@media print {
  body {
    margin: 0;
    color: #000;
    background: #fff;
    font: 11pt/1.5 Georgia, serif;
  }

  nav,
  footer,
  form,
  .no-print {
    display: none !important;
  }

  main {
    width: auto;
    max-width: none;
    margin: 0;
    padding: 0;
  }

  h1,
  h2,
  h3 {
    break-after: avoid-page;
  }

  figure,
  table,
  blockquote {
    break-inside: avoid;
  }

  img,
  svg {
    max-width: 100%;
    height: auto;
  }

  a {
    color: inherit;
    text-decoration: underline;
  }

  p {
    orphans: 3;
    widows: 3;
  }
}

The best print stylesheet starts with readable HTML. CSS should remove interface noise, preserve meaning, and guide pagination without fighting the browser on every page.

Tagged: CSS · All topics
~~~

Related posts about css: