Using CSS target-counter for Print Page References

The CSS target-counter() function is a specialized feature defined in the CSS Paged Media and Generated Content specifications designed to generate dynamic cross-references and page numbers in print documents. By referencing the destination of an internal hyperlink, this function automatically retrieves the exact page number where the target element resides, making it indispensable for creating printed tables of contents, indexes, and inline cross-references without manual pagination.

How target-counter() Works

In print-oriented CSS rendering engines (such as PrinceXML, WeasyPrint, or Vivliostyle), documents are divided into distinct pages. Because dynamic content changes where specific sections fall across pages, authors cannot hardcode page numbers.

The target-counter() function solves this by looking up the current value of a counter at the location of an anchor link. It evaluates the target element's position after the document has been fully paginated and outputs that value as generated content via the content property.

Syntax and Parameters

The basic syntax for the function is:

target-counter( <url> , <counter-name> [, <counter-style>]? )
  • <url>: The reference to the target element. In most cross-references, this is dynamically pulled from an anchor tag's href attribute using the attr() function (e.g., attr(href, url)).
  • <counter-name>: The specific CSS counter to retrieve. For page numbers, this is typically set to the built-in page counter.
  • <counter-style> (optional): Defines the formatting of the counter, such as decimal, lower-roman, upper-alpha, etc. If omitted, it defaults to decimal.

Practical Implementation

The most common use case is creating an automated Table of Contents (TOC) or inline cross-reference that displays the page number alongside the section title.

/* Inline cross-reference example */
a.cross-ref::after {
  content: " (see page " target-counter(attr(href, url), page) ")";
}

/* Table of contents leader and page number */
.toc a::after {
  content: leader('.') " " target-counter(attr(href, url), page);
}

In the HTML, standard fragment identifiers are used:

<p>For more details, refer to the installation guide <a href="#installation" class="cross-ref">here</a>.</p>

<!-- Rendered in print as: -->
<!-- For more details, refer to the installation guide here (see page 42). -->

Browser and Tool Support

Standard web browsers (such as Chrome, Firefox, and Safari) focus on continuous screen media and do not natively support target-counter() in standard print stylesheets. Consequently, the function is primarily utilized in specialized HTML-to-PDF converters, publishing pipelines, and polyfills like Paged.js, which implement the full W3C Paged Media Module specifications.