Reference
CSS for paged documents, and what actually works
The paged media specification is large and only partly implemented, and unimplemented CSS fails silently. Every entry below says which side of that line it falls on, because that is the part that is hard to find written down and the part that costs an afternoon.
For the dimensions themselves, meaning what A4, a 4 by 6 label or an 80mm receipt roll actually measure and what margin each one needs, see PDF page sizes. For the scripts where a font with the right characters still is not enough, see writing systems in PDF output.
The page box
- @pageWorks in a browser-based render
@page declares the properties of the page box itself: its dimensions and its margins, which are things no element selector can reach.
- sizeWorks in a browser-based render
The size descriptor inside @page sets the paper dimensions, either by name (A4, Letter) or as an explicit width and height.
- margin (in @page)Works in a browser-based render
The margin descriptor inside @page sets the unprintable border around the content area of every page.
- @page :first, :left, :rightWorks in a browser-based render
Page pseudo-classes let the first page, and left and right pages in a double-sided document, carry different margins from the rest.
- page (named pages)Only in dedicated print engines
A named @page rule plus the page property on an element lets one part of a document use a different page box from the rest.
- @top-center and the margin boxesDoes nothing in a browser-based render
The page margin boxes are sixteen named regions around the page box, such as @top-center and @bottom-right, each of which can hold generated content that repeats on every page.
- counter(page)Does nothing in a browser-based render
counter(page) and counter(pages) are automatic counters holding the current page number and the total, intended to be used in generated content.
Where pages break
- break-insideWorks everywhere
break-inside: avoid asks the layout not to put a page break inside this element.
- break-beforeWorks everywhere
break-before: page starts a new page before this element, whatever is left of the current one.
- break-afterWorks everywhere
break-after: avoid asks the layout not to break immediately after this element, which in practice keeps a heading attached to its section.
- page-break-insideWorks everywhere
page-break-before, page-break-after and page-break-inside are the original properties from CSS 2.1. The break-* properties replaced them and cover fragmentation in columns and regions as well as pages.
- orphans and widowsWorks everywhere
orphans sets the minimum number of lines of a paragraph that can be left at the bottom of a page; widows sets the minimum that can be carried to the top of the next one.
- box-decoration-breakWorks in a browser-based render
box-decoration-break decides whether an element that fragments across a break gets its border and padding applied once across the whole thing (slice) or on each fragment (clone).
- theadWorks everywhere
Rows inside a thead element repeat at the top of every page the table runs onto. This is markup, not CSS: there is no property that creates the behaviour.
- column-countWorks in a browser-based render
Multi-column layout flows content into columns, and in a paged context those columns fill one page before the flow continues on the next.
How it renders
- print-color-adjustWorks in a browser-based render
print-color-adjust: exact tells the renderer not to optimise colours away for printing, which is the per-element counterpart to the render's printBackground option.
- @media printWorks everywhere
The print media type matches when a document is being laid out for a paged medium, which a PDF render is.
- prefers-color-schemeWorks everywhere
prefers-color-scheme matches the environment's colour preference, which in a headless render is a default rather than anyone's choice.
- position: fixedWorks in a browser-based render
Fixed positioning places an element relative to the viewport. A paged document has either one viewport per page or none, depending on the engine, so the element repeats on every page or appears once.
- image-renderingWorks everywhere
image-rendering hints at the scaling algorithm, but blurry images in a PDF are almost always a resolution problem rather than an algorithm problem.
- background on bodyWorks in a browser-based render
A background set on html or body covers the canvas, which in a paged context means every page, though how it repeats depends on whether it is sized to the page or to the document.
- opacity and mix-blend-modeWorks in a browser-based render
Opacity works and produces real transparency in the output. Blend modes are composited during rendering, which means the result is correct and the layering information is gone.
- box-shadowWorks in a browser-based render
Shadows are backgrounds as far as print optimisation is concerned, so they are dropped along with background colours unless backgrounds are enabled.
Text and typography
- @font-faceWorks everywhere
@font-face declares a font and where to fetch it. The fetched font is embedded in the output, so the document renders identically for a reader who has never had the font installed.
- font-displayWorks everywhere
font-display controls what happens while a font is loading: swap shows fallback text immediately, block waits, optional gives up quickly.
- unicode-rangeWorks everywhere
unicode-range restricts a @font-face to a set of code points, so the browser only uses that face for characters inside the range.
- font-variant-numericWorks everywhere
font-variant-numeric: tabular-nums switches to fixed-width digit glyphs, so every digit occupies the same horizontal space.
- hyphensWorks everywhere
hyphens: auto lets the layout break words at syllable boundaries, using a dictionary for the language declared on the document.
- overflow-wrapWorks everywhere
overflow-wrap: break-word allows a break inside a word when the line has no other option; anywhere is more aggressive and also affects how the minimum width is calculated.
- white-spaceWorks everywhere
white-space: pre preserves formatting and refuses to wrap, which on a page means everything past the margin is lost. pre-wrap preserves the formatting and allows wrapping.
- text-align: justifyWorks everywhere
Justified text stretches the spaces on each line so both edges align. It is the default in most printed books and it needs hyphenation to look right.
- line-heightWorks everywhere
Line height sets the distance between baselines. Print conventions differ from screen conventions, and copying the screen value produces a document that looks loose and runs long.
- text-wrap: balanceWorks in a browser-based render
text-wrap: balance distributes a short block of text evenly across its lines rather than filling each line greedily, which prevents a heading ending with one word alone.
Units and measurement
- mm, cm, in, ptWorks everywhere
Physical units mean a real measurement in the output. A millimetre in a PDF is a millimetre on paper, which is not true of a millimetre on a screen.
- px in a paged contextWorks everywhere
CSS defines one inch as 96 pixels, so A4 at 210mm wide is 793.7 pixels. The fraction is the reason pixel-based page layouts drift.
- vh and vwWorks in a browser-based render
Viewport units resolve against the render viewport, which in a paged context is one page. 100vh is the height of a page, not the height of the document.
- resolutionWorks everywhere
CSS works at 96 dots per inch. Print quality is conventionally 300, so an image needs roughly three times its CSS pixel dimensions to look sharp on paper.