CSS Named Pages & Page Selectors

Use the page property and @page pseudo-class selectors to create documents with multiple page layouts—portrait body pages, landscape tables, distinct cover pages, and book-style left/right margins.

Named Pages

The W3C CSS Paged Media Module Level 3 introduces named pages—a mechanism that lets you define multiple @page rules with different configurations (size, margins, orientation) and assign HTML elements to those page types using the page CSS property.

The page Property

The page property is set on elements to declare which named page type they should be rendered on.

Syntax Behaviour
page: auto Default. The element uses the generic @page rule (or inherits from its parent).
page: <custom-ident> The element is rendered on a page matching the given name. A corresponding @page <custom-ident> rule defines that page’s properties.

The <custom-ident> is any author-defined name—it follows the same naming rules as CSS custom identifiers (no quotes, cannot be a CSS-wide keyword like inherit or initial).

Defining Named @page Rules

A named @page rule applies only to pages that match the given name. You define the page type inside @page using the name directly after the keyword:

@page wide {
  size: A4 landscape;
  margin: 15mm;
}

@page cover {
  size: A4 portrait;
  margin: 0;
}

@page body {
  size: A4 portrait;
  margin: 25mm 20mm;
}

Any property valid inside @page can be used: size, margin, marks, bleed, and margin box rules (@top-center, @bottom-right, etc.).

Assigning Elements to Named Pages

Use the page property on any block-level element to place it on the corresponding named page:

.landscape-section {
  page: wide;
}

.cover {
  page: cover;
}

.body-content {
  page: body;
}

Automatic Page Breaks Between Named Pages

When two adjacent sibling elements have different page values, the browser automatically inserts a page break between them. You do not need to add break-before or break-after—the break is implicit.

<div class="cover">...</div>        <!-- page: cover -->
<div class="body-content">...</div> <!-- page: body -->
<div class="landscape-section">     <!-- page: wide -->
  <table>...</table>
</div>
<div class="body-content">...</div> <!-- page: body -->

This produces four distinct page groups: the cover page, the first body section, the landscape table spread, and the remaining body content. Each transition triggers an automatic page break.

Document with Portrait and Landscape Sections

@page {
  size: A4 portrait;
  margin: 25mm 20mm;
}

@page landscape {
  size: A4 landscape;
  margin: 15mm;
}

/* All content uses portrait by default */
body {
  page: auto;
}

/* Wide tables switch to landscape */
.wide-table-wrapper {
  page: landscape;
}
<!-- Portrait pages -->
<section>
  <h2>Q3 Financial Summary</h2>
  <p>Lorem ipsum dolor sit amet...</p>
</section>

<!-- Automatically breaks to landscape -->
<div class="wide-table-wrapper">
  <table>
    <thead><tr><th>Region</th><th>Q1</th><th>Q2</th><th>Q3</th><th>Q4</th><th>Total</th></tr></thead>
    <tbody>...</tbody>
  </table>
</div>

<!-- Automatically breaks back to portrait -->
<section>
  <h2>Analysis</h2>
  <p>The data shows...</p>
</section>

Cover Page with Different Margins

@page cover-page {
  size: A4;
  margin: 0;
}

@page content-page {
  size: A4;
  margin: 25mm 20mm;
}

.cover {
  page: cover-page;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background: #1a1333;
  color: #fff;
}

.content {
  page: content-page;
}
<div class="cover">
  <div>
    <h1>Annual Report 2025</h1>
    <p>Acme Corporation</p>
  </div>
</div>

<div class="content">
  <h2>Executive Summary</h2>
  <p>...</p>
</div>

Page Selectors (Pseudo-classes)

The @page rule supports four pseudo-class selectors defined in the W3C CSS Paged Media Module Level 3. These let you target specific pages by their position or state without assigning named page types.

:first

Targets only the first page of the document (or, when combined with a named page, the first page of that named page group).

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

Common use: larger top margin on the first page to leave room for a title block, or suppressing headers/footers on page one.

:left

Targets left-hand (even-numbered) pages. In left-to-right languages, left pages are the verso (back) side of a spread.

@page :left {
  margin-left: 30mm;
  margin-right: 20mm;
}

Targets right-hand (odd-numbered) pages. In left-to-right languages, right pages are the recto (front) side of a spread.

@page :right {
  margin-left: 20mm;
  margin-right: 30mm;
}

Together, :left and :right create the asymmetric margins needed for bound documents—wider inner margins (the gutter) to accommodate binding.

:blank

Targets pages that are left blank by a forced page break. When break-before: left or break-before: right inserts a blank page to reach the correct side, that blank page matches :blank.

@page :blank {
  @top-center { content: none; }
  @bottom-center { content: none; }
}

This removes headers and footers from blank pages, which is standard practice in book publishing.

Combining Named Pages with Selectors

Named page identifiers and pseudo-class selectors can be combined to create highly specific rules:

/* First page of the "chapter" named page group */
@page chapter:first {
  margin-top: 60mm;
  @top-center { content: none; }
}

/* Left-hand chapter pages get a wider left margin */
@page chapter:left {
  margin-left: 30mm;
  margin-right: 20mm;
  @bottom-left { content: counter(page); }
}

/* Right-hand chapter pages get a wider right margin */
@page chapter:right {
  margin-left: 20mm;
  margin-right: 30mm;
  @bottom-right { content: counter(page); }
}

The specificity order is: a named page rule is more specific than an unnamed one; adding a pseudo-class increases specificity further. @page chapter:first overrides @page chapter, which overrides @page.

Practical Examples

Book-Style Layout with Different Left/Right Margins

@page {
  size: 6in 9in;
}

@page :left {
  margin: 20mm 15mm 20mm 25mm; /* top right bottom left (gutter) */
  @bottom-left {
    content: counter(page);
    font-size: 10pt;
  }
}

@page :right {
  margin: 20mm 25mm 20mm 15mm; /* top right (gutter) bottom left */
  @bottom-right {
    content: counter(page);
    font-size: 10pt;
  }
}

@page :first {
  margin: 0;
  @bottom-left { content: none; }
  @bottom-right { content: none; }
}

This creates a traditional book layout with a 25 mm gutter margin on the binding edge, page numbers on the outer corners, and a full-bleed first page.

Cover Page with No Margins + Body Pages with Margins

@page cover {
  size: A4;
  margin: 0;
}

@page body {
  size: A4;
  margin: 20mm;
  @bottom-center {
    content: counter(page);
    font-size: 9pt;
    color: #666;
  }
}

.cover-page {
  page: cover;
  width: 210mm;
  height: 297mm;
  background: linear-gradient(135deg, #1a1333, #5935dd);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.body-page {
  page: body;
}
<div class="cover-page">
  <div>
    <h1>Product Roadmap</h1>
    <p>Q1–Q4 2025</p>
  </div>
</div>

<div class="body-page">
  <h2>Vision</h2>
  <p>Our roadmap focuses on...</p>
</div>

Landscape Tables in a Portrait Document

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

@page rotated {
  size: A4 landscape;
  margin: 15mm;
  @top-center {
    content: "Data Appendix";
    font-size: 9pt;
    color: #999;
  }
}

.appendix-table {
  page: rotated;
  break-inside: avoid;
}

Every element with class="appendix-table" is rendered on landscape pages. When the document returns to a non-rotated element, it switches back to portrait automatically.

Different Header on First Page vs Subsequent Pages

@page {
  size: letter;
  margin: 25mm 20mm 20mm 20mm;

  @top-center {
    content: "Confidential — Internal Use Only";
    font-size: 8pt;
    color: #999;
  }

  @bottom-center {
    content: "Page " counter(page) " of " counter(pages);
    font-size: 8pt;
  }
}

@page :first {
  @top-center {
    content: none; /* No header on the first page */
  }

  @bottom-center {
    content: none; /* No footer on the first page */
  }
}

The first page is clean—no running header or footer. All subsequent pages display the confidentiality notice and page numbering.

Browser Support

Feature Chrome / Chromium Safari / WebKit Firefox
page property (named pages) Yes (85+) No No
Named @page rules Yes (85+) No No
Automatic breaks between named pages Yes (85+) No No
@page :first Yes Yes Yes
@page :left / :right Yes Partial Partial
@page :blank Partial No No
Combining named + pseudo-class Yes (85+) No No

Named pages are a Chromium feature. Chrome 85 (released August 2020) introduced support for the page property and named @page rules. Safari and Firefox do not support named pages. The pseudo-class selectors (:first, :left, :right) have broader support, though :left/:right handling varies. Since Doppio uses a Chromium-based rendering engine, all named page features work reliably.

Tip: If you need named-page behaviour in non-Chromium environments, consider Paged.js, which polyfills named pages and page selectors across all browsers.