Margins
Set page margins with margin or padding on :host, vary them per page, and mirror them for bound documents.
A page's size is a fixed box (see Page sizes). Margins are the whitespace you carve inside it, set with margin or padding on :host. Any CSS unit works (mm, cm, in, px, %), though absolute units keep print output the most predictable.
Setting page margins
Set margin on :host to inset content from the page edge on every page:
:host {
margin: 2cm;
}Format applies this for any value you choose. Each page is a fixed-size box and :host stretches to fill it, so Format resolves the content area as the page size minus your margin. The page background still reaches the physical edge (see Margin or padding).
Give each edge its own value for an asymmetric page, for example a wider top margin for a letterhead:
:host {
margin: 3cm 2cm 2cm 2cm; /* top right bottom left */
}Margin or padding
Both margin and padding on :host inset your content by the same amount. The difference is what fills the gap.
| Property | What fills the inset band | Best for |
|---|---|---|
padding | The host still fills the whole page, so a background-image or gradient on :host reaches every edge and content sits inside the padding. | Full-bleed background images or gradients. |
margin | The host shrinks. Only the background-color, which Format lifts onto the page box, fills the band; a background-image doesn't reach it. | Solid-color or white pages (reads most naturally as a page margin). |
This is the same mechanism behind print bleed (see Bleed and trim).
Margins per page
The :host selector matches every page, so a margin set on it applies to all of them. To give one page a different margin, target it with the :host() functional selector and the attributes Format writes per page:
/* roomier top margin on the first page, e.g. for a letterhead */
:host([data-first-page]) {
margin-top: 6cm;
}
/* drop the margin on a specific page */
:host([data-page-number="3"]) {
margin: 0;
}Margins around content but not headers and footers
A margin or padding on :host insets the whole page, headers and footers included, because they all sit inside the host. When you want to inset the body but keep a header or footer flush to the page edge, lay the page out as a flex column and pad the body alone.
Set :host as a flex column with the header, body, and footer as its children. Pad main to inset the body alone, and pin the footer to the bottom edge with margin-top: auto. The header and footer span the full page, while the body content remains inset:
import { Document, Layout, Flow, css } from '@format.dev/react'
export default function ReportDocument() {
return (
<Document title="Report">
<Layout id="report" width={793.71} height={1122.52}>
<style>{css`
:host {
display: flex;
flex-direction: column;
}
main {
flex: 1;
padding: 2cm; /* inset the body only */
}
footer {
margin-top: auto; /* push the footer to the bottom edge */
}
`}</style>
<header>...</header>
<main>
<Flow>
<p>...</p>
</Flow>
</main>
<footer>...</footer>
</Layout>
</Document>
)
}Mirrored margins for bound documents
A bound document, such as a book, needs a wider margin on the binding edge, mirrored between alternating pages. The inner (binding) margin and the outer (trimmed) margin swap depending on which side a page falls.
Format marks each page as odd or even with the data-odd-page and data-even-page attributes, so you can target the two sides directly:
/* odd (right-hand) pages: binding on the left */
:host([data-odd-page]) {
padding-inline: 80px 40px;
}
/* even (left-hand) pages: binding on the right */
:host([data-even-page]) {
padding-inline: 40px 80px;
}In this case, padding-inline is deliberate. As a logical property it follows the document's writing direction, so the gutter stays on the binding edge even in right-to-left text. This assumes page one is a right-hand page; swap the two values if your binding sits on the other side.
Targeting every nth page
There are markers for odd and even pages, but not for arbitrary intervals like every third, and :nth-child does not apply because each page is styled on its own. For an interval like every third page, compute on the page number, which Format exposes as a numeric custom property, and branch with if():
:host {
--mod3: mod(var(--page-number), 3); /* 0 on pages 3, 6, 9, … */
padding-top: if(style(--mod3 = 0): 80px; else: 20px);
}Change the divisor for a different interval, and the comparison value to choose which page in the cycle is styled. The if() and style() queries are new to CSS, but Format evaluates your styles in a single rendering environment, so you can use them freely, without the cross-browser support caveats they carry on the open web.
Content margins and collapsing
Inside the page, element margins behave as they do on the web, with one guarantee: the page boundary contains margin collapse. The first element's margin-top and the last element's margin-bottom are preserved as space rather than collapsing through the page edge and disappearing. A heading with a top margin sits at the top of the page, not flush against the edge.