Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Page breaks

sghtmltopdf controls page breaks through the CSS Fragmentation properties.

Explicit page breaks

.chapter { break-before: page; }   /* break before this element */
.summary { break-after: page; }    /* break after this element */
.card    { break-inside: avoid; }  /* do not split this element across a page boundary */
PropertyAccepted values
break-before, break-afterauto, avoid (avoid-page and avoid-column mean the same), always (page means the same)
break-insideauto, avoid (as above)

The older page-break-before, page-break-after, and page-break-inside are accepted as aliases, so stylesheets written for wkhtmltopdf or wicked_pdf carry over unchanged.

The spread-related values left, right, recto, and verso, and the multi-column values, are not supported.

Without writing CSS

The same thing can be written as an HTML attribute.

<div data-page-break="before">…</div>
<div data-page-break="after">…</div>
<div data-page-break="avoid">…</div>

These count as low-priority hints, so a rule in a stylesheet can override any of them individually.

Keeping paragraphs from being split badly

p {
  orphans: 3;   /* leave at least three lines at the bottom of the page */
  widows: 3;    /* carry at least three lines to the top of the next page */
}

Both take an integer of 1 or more and default to 2. When the requirement cannot be met, the whole paragraph moves to the next page.

@page: paper and page margins

@page {
  size: A4;
  margin: 20mm;

  @top-center    { content: "Invoice"; }
  @bottom-center { content: counter(page) " / " counter(pages); }
}

@page :first {
  @bottom-center { content: "Cover"; }
}
  • size accepts a page size keyword such as A4 or Letter, one or two <length> values, and landscape or portrait
  • @page wins over the CLI page setup options, which act as initial values
  • Text can be placed in the margin boxes, the sixteen from @top-left-corner to @bottom-right-corner, through content. Decoration such as background colours and borders is not supported there
  • counter(page) is the current page number and counter(pages) is the total page count

Limits of @page

  • size and margin cannot vary from page to page. Such declarations qualified with :first, :left, or :right are parsed but not applied; those pseudo-classes only serve to vary the contents of the margin boxes
  • Named pages, @page intro together with page: intro, are not supported
  • The margin box geometry is simplified. The four corners are fixed to where the vertical and horizontal margins meet, and the other twelve divide each edge into three equal parts; a width is ignored
  • counter(pages) is unavailable in streaming mode, because the total page count is not known in a single pass

CLI options such as --header-center are mapped internally onto these @page margin boxes. If you write both, the CSS wins.

Breaking tables across pages

A table that does not fit on one page is split row by row and flows across pages.

  • The rows of <thead> are repeated at the top of every page after the first. Multi-row headers work too, and nothing is repeated for a table that fits on one page
  • <tfoot> moves to the end of the table regardless of where it appears in the source, but it is not repeated at the bottom of every page; it appears once, on the last page
  • The caption goes with the first fragment for caption-side: top and with the last for bottom
  • Every fragment carries the table’s own background and borders, and border-collapse: collapse still merges borders within each page

As a known limitation, a cell whose rowspan crosses a break belongs to the fragment of its starting row and its lower part runs off the page without being clipped. Row-level break-inside: avoid and the equivalent of orphans and widows are not supported either.

How Flexbox and Grid are handled

LayoutPage breaks
display: flexAtomic. It is never split; if it does not fit, the whole thing moves to the next page
display: gridSplit row band by row band, except at a boundary crossed by an item that spans rows
display: tableSplit row by row, as above

When laying out large cards, a flex container can jump to the next page in one piece. Use Grid or a table where you want it split.

Common patterns

Keep a heading from being stranded at the bottom of a page:

h2, h3 {
  break-after: avoid;   /* do not break right after a heading */
  break-inside: avoid;
}

Keep a single line item from splitting across two pages:

.line-item { break-inside: avoid; }

Always start a new page for each chapter:

section.chapter + section.chapter { break-before: page; }

Note

In streaming mode, selectors that look backwards, such as :last-child, never match. The adjacent sibling combinator + used above does work.