← All posts

CSS print page styling

• Written by Alex Turchyn

1. Page Sizes

First and foremost, it’s essential to define the basic page settings. The CSS @page attribute allows you to specify page sizes, margins, background color, and more. Additionally, you can configure individual pages, such as the first, last, or odd pages.

You can use standard absolute page sizes:

  • A5 (148mm x 210mm)
  • A4 (210mm x 297mm) - the default size
  • A3 (297mm x 420mm)
  • B3 (353mm x 500mm)
  • B4 (250mm x 353mm)
  • JIS-B4 (257mm x 364mm)
  • letter (8.5in x 11in)
  • legal (8.5in x 14in)
  • ledger (11in x 17in)

Alternatively, you can use custom page sizes:

@media print {
  @page {
    size: 8.5in 11in;
  }
}

To set the page orientation, use the orientation attribute:

  • portrait - portrait orientation (default)
  • landscape - landscape orientation.
@media print {
  @page {
    size: A4 landscape;
  }
}

2. Page Margins

Page margins can be defined using the margin attribute and its variants: margin-top, margin-bottom, margin-left, and margin-right. Margins can be specified both relative to the page size (using units like em, rem, vw, vh) and in absolute units (px, mm, cm, in, pt, pc). Absolute units are typically used for designs with fixed dimensions that shouldn’t change based on viewing conditions. This is a preferable approach for creating PDF files as they have fixed sizes.

Here’s an example of defining page margins in absolute units:

@media print {
  @page {
    margin: 1in; /* 1 inch margin for all sides */
  }

  /* Specific margins for different sides */
  @page {
    margin-top: 0.5in;
    margin-bottom: 0.75in;
    margin-left: 1.25in;
    margin-right: 1in;
  }
}

In this example, we set a 1-inch margin for all sides of the page in the first @page rule. In the second @page rule, we specify different margins for each side of the page.

If you need to set different margins for the left and right pages in a double-sided document, you can use the :left and :right pseudo-classes with the @page rule. Here’s how you can do it:

@media print {
  /* Left page margin */
  @page :left {
    margin-left: 1.5in;
    margin-right: 0.5in;
  }

  /* Right page margin */
  @page :right {
    margin-left: 0.5in;
    margin-right: 1.5in;
  }
}

3. Page Breaks

When a page has more content than can fit on a single page, browsers automatically break the content into multiple pages. However, this automatic page breaking might not always align with your desired layout. For example, you may want sections to start on new pages or headers of sections to appear at the beginning of new pages. To address this issue, you can use the page-break-before, page-break-after, and page-break-inside attributes to control how content should be divided across pages.

Here are the available values for these attributes:

  • auto - Default behavior, where the browser decides whether to break the content into pages.
  • always - Always break the content into pages.
  • avoid - Never break the content into pages, except when it doesn’t fit on one page.
  • left - Start a new page by breaking the content from the left side.
  • right - Start a new page by breaking the content from the right side.
  • recto - Start a new page from the first page.
  • verso - Start a new page from the second page.

For creating PDF files, the always and avoid values are most useful. Let’s look at an example of using the page-break-before attribute to break content using the <h1> tag. This allows you to place section headers on new pages as the page break occurs before the <h1> element. page-break-after works similarly but places the page break after the <section> element.

@media print {
  h1 {
    page-break-before: always; /* Start a new page before <h1> elements */
  }

  section {
    page-break-after: always; /* Start a new page after <section> elements */
  }
}

However, there are situations where you want to prevent content from breaking across pages, such as avoiding a table or graphic splitting across two pages. In such cases, you can use the page-break-inside attribute with the value avoid.

For example, if you have a <table> element and you want to ensure that it stays together on one page, you can use the following CSS rule:

@media print {
  table, figure {
    page-break-inside: avoid; /* Prevent the table from breaking across pages */
  }
}

This will instruct the browser to avoid breaking the <table> element across multiple pages, ensuring it stays intact on a single page. You can apply similar rules to other elements as needed to control page breaks within your content.

If a table cannot fit on a single page, and you want to ensure readability by moving table headers to the next page, you don’t necessarily need to use CSS styles. Properly structuring your HTML tables with <thead> and <tbody> elements can achieve this effect. Your tables should include <thead> elements with child <tr> and <th> tags, as well as <tbody> elements with child <tr> and <td> tags.

By structuring your tables in this way, the browser will automatically break the table into pages, ensuring that the table headers are repeated on each page for readability. Here’s an example of how to structure your table:

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>John</td>
      <td>45</td>
    </tr>
    <tr>
      <td>Mike</td>
      <td>40</td>
    </tr>
    <tr>
      <td>Alice</td>
      <td>29</td>
    </tr>
  </tbody>
</table>

By following this structure, the browser will handle the pagination automatically, ensuring that the table headers are correctly displayed on each page where the table is split.

4. Page Numbers

CSS provides a powerful mechanism for customizing page numbering in printed documents. You can define which elements should be included in the page numbering, where the page numbers should be located, and their format. The counter() function is commonly used to display the correct page number in page numbering.

Here are the available rules for page numbering placement:

  • @top-left-corner - Top left corner
  • @top-left - Top left
  • @top-center - Top center
  • @top-right - Top right
  • @top-right-corner - Top right corner
  • @bottom-left-corner - Bottom left corner
  • @bottom-left - Bottom left
  • @bottom-center - Bottom center
  • @bottom-right - Bottom right
  • @bottom-right-corner - Bottom right corner
  • @left-top - Left top
  • @left-middle - Left middle
  • @left-bottom - Left bottom
  • @right-top - Right top
  • @right-middle - Right middle
  • @right-bottom - Right bottom

To display the correct page number in the page numbering, you can use the counter(page) function. This function allows you to show the current page number and create more complex expressions. Here’s an example of how to use it:

@media print {
  @page :right {
    @bottom-right {
      content: counter(page);
    }
  }

  @page :right {
    @bottom-right {
      content: "Page " counter(page) " of " counter(pages);
    }
  }
}

5. Special Pages

In any document, there can be pages that differ from the others. Previously, using pseudo-classes, it was possible to access the first, last, and empty pages. However, in the latest CSS versions, support for pseudo-classes like @page :last and @page :blank has been removed. Various tutorials may mention them, but they are no longer supported.

Currently, only the @page :first pseudo-class is supported. This pseudo-class allows you to define styles for the first page of the document, such as the document cover.

If you have further questions or need additional information, please feel free to ask.

@media print {
  @page :first {
    margin: 1.5in 1in 1in 1in;
  }
}

6. Useful Tips

If you attempt to print a PDF file, you may notice that links are not displayed. To make them accessible in print, you can use the :after pseudo-class along with the content function. In this case, links will be displayed in the format: “Link (https://example.com)”, significantly improving readability.

@media print {
  a::after {
    content: " (" attr(href) ")";
  }
}

6.2. .no-print class

Instead of individually specifying whether each HTML element should be displayed when printing, you can create a .no-print class to be used for elements that should not be printed. This class allows for a more efficient and consistent way to manage which elements should be excluded from the printed version of the document.

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

7. Instead of Conclusions

In this article, we have covered the most basic CSS styles for creating PDF files. In reality, you can create much more complex styles. You can format entire books using just HTML and CSS.