{
  "product": "MostlyPDF",
  "benchmark": "html-to-pdf print-feature support",
  "engine": {
    "name": "Chromium (headless)",
    "version": "148.0.7778.96",
    "via": "playwright page.pdf()"
  },
  "scope": "SINGLE ENGINE. Not a cross-engine comparison — see the header of bench-htmltopdf.js.",
  "cases": [
    {
      "id": "break-after-page",
      "feature": "break-after: page",
      "whyItMatters": "The standard CSS Fragmentation property. If it is ignored you cannot control pagination at all.",
      "supported": true,
      "expected": "2 pages",
      "observed": "2 page(s)",
      "raw": {
        "pages": 2,
        "sizes": [
          [
            596,
            843
          ],
          [
            596,
            843
          ]
        ],
        "links": [],
        "fonts": [
          "AAAAAA+DejaVuSans"
        ]
      }
    },
    {
      "id": "page-break-after-legacy",
      "feature": "page-break-after: always (legacy)",
      "whyItMatters": "The pre-2017 spelling. Most tutorials and CMS themes still emit it, so whether it still works matters.",
      "supported": true,
      "expected": "2 pages",
      "observed": "2 page(s)",
      "raw": {
        "pages": 2,
        "sizes": [
          [
            596,
            843
          ],
          [
            596,
            843
          ]
        ],
        "links": [],
        "fonts": [
          "AAAAAA+DejaVuSans"
        ]
      }
    },
    {
      "id": "break-inside-avoid",
      "feature": "break-inside: avoid",
      "whyItMatters": "Keeping a figure, card or invoice row from being sliced across two pages — the most asked-for behaviour.",
      "supported": true,
      "expected": "card moved whole to page 2",
      "observed": "2 page(s), card on page 2",
      "raw": {
        "pages": 2,
        "sizes": [
          [
            596,
            843
          ],
          [
            596,
            843
          ]
        ],
        "links": [],
        "fonts": [
          "AAAAAA+DejaVuSans"
        ]
      }
    },
    {
      "id": "page-size-a5",
      "feature": "@page { size: A5 }",
      "whyItMatters": "Whether the document, not the caller, can choose the paper size.",
      "supported": true,
      "expected": "420x595pt (A5)",
      "observed": "420x595pt",
      "raw": {
        "pages": 1,
        "sizes": [
          [
            420,
            595
          ]
        ],
        "links": [],
        "fonts": [
          "AAAAAA+DejaVuSans"
        ]
      }
    },
    {
      "id": "page-size-landscape",
      "feature": "@page { size: A4 landscape }",
      "whyItMatters": "Orientation from CSS rather than an API flag — what a template author reaches for first.",
      "supported": true,
      "expected": "width > height",
      "observed": "842x595pt",
      "raw": {
        "pages": 1,
        "sizes": [
          [
            842,
            595
          ]
        ],
        "links": [],
        "fonts": [
          "AAAAAA+DejaVuSans"
        ]
      }
    },
    {
      "id": "thead-repeat",
      "feature": "Repeating <thead> across pages",
      "whyItMatters": "A long table whose header vanishes after page 1 is the classic broken invoice or report.",
      "supported": true,
      "expected": "header repeats on page 2",
      "observed": "3 page(s); header on page 2: true",
      "raw": {
        "pages": 3,
        "sizes": [
          [
            596,
            843
          ],
          [
            596,
            843
          ],
          [
            596,
            843
          ]
        ],
        "links": [],
        "fonts": [
          "AAAAAA+DejaVuSans-Bold",
          "BAAAAA+DejaVuSans"
        ]
      }
    },
    {
      "id": "position-fixed-running-header",
      "feature": "position: fixed as a running header",
      "whyItMatters": "The usual first attempt at a header on every page; whether it repeats decides a lot of templates.",
      "supported": true,
      "expected": "on every page",
      "observed": "on 2 of 2 page(s)",
      "raw": {
        "pages": 2,
        "sizes": [
          [
            596,
            843
          ],
          [
            596,
            843
          ]
        ],
        "links": [],
        "fonts": [
          "AAAAAA+DejaVuSans"
        ]
      }
    },
    {
      "id": "margin-box-page-number",
      "feature": "@page margin boxes (@bottom-center + counter(page))",
      "whyItMatters": "The CSS Paged Media way to number pages. Widely documented, rarely implemented in browsers.",
      "supported": false,
      "expected": "a page number drawn in the bottom margin",
      "observed": "no page number in the output",
      "raw": {
        "pages": 2,
        "sizes": [
          [
            596,
            843
          ],
          [
            596,
            843
          ]
        ],
        "links": [],
        "fonts": [
          "BAAAAA+DejaVuSans"
        ]
      }
    },
    {
      "id": "link-annotation-external",
      "feature": "<a href> preserved as a clickable PDF link",
      "whyItMatters": "A PDF whose links are dead text is a downgrade the reader notices immediately.",
      "supported": true,
      "expected": "at least one link annotation",
      "observed": "1 link annotation(s)",
      "raw": {
        "pages": 1,
        "sizes": [
          [
            596,
            843
          ]
        ],
        "links": [
          "https://mostlypdf.com/docs"
        ],
        "fonts": [
          "AAAAAA+DejaVuSans"
        ]
      }
    },
    {
      "id": "link-annotation-internal",
      "feature": "Internal anchor links (#id) as PDF destinations",
      "whyItMatters": "What makes a table of contents in a generated report actually navigable.",
      "supported": true,
      "expected": "an internal destination",
      "observed": "1 link annotation(s)",
      "raw": {
        "pages": 1,
        "sizes": [
          [
            596,
            843
          ]
        ],
        "links": [
          "(internal destination)"
        ],
        "fonts": [
          "AAAAAA+DejaVuSans",
          "BAAAAA+DejaVuSans-Bold"
        ]
      }
    },
    {
      "id": "webfont-embedded",
      "feature": "Font embedding",
      "whyItMatters": "If the font is not embedded the PDF renders differently on a machine that lacks it — the commonest fidelity complaint.",
      "supported": true,
      "expected": "the face embedded in the file",
      "observed": "AAAAAA+DejaVuSansMono",
      "raw": {
        "pages": 1,
        "sizes": [
          [
            596,
            843
          ]
        ],
        "links": [],
        "fonts": [
          "AAAAAA+DejaVuSansMono"
        ]
      }
    },
    {
      "id": "grid-across-break",
      "feature": "CSS grid fragmenting across a page break",
      "whyItMatters": "Modern layouts are grids; whether one survives pagination decides if you can use them at all.",
      "supported": false,
      "expected": "cells continue onto later pages",
      "observed": "2 page(s), cells per page: [8, 0]",
      "raw": {
        "pages": 2,
        "sizes": [
          [
            596,
            843
          ],
          [
            596,
            843
          ]
        ],
        "links": [],
        "fonts": [
          "AAAAAA+DejaVuSans"
        ]
      }
    }
  ],
  "summary": {
    "total": 12,
    "supported": 10,
    "unsupported": 2,
    "inconclusive": 0
  },
  "meta": {
    "source": "measured",
    "generatedAt": "2026-09-27T13:49:38.718Z",
    "harness": "https://mostlypdf.com/bench/bench-htmltopdf.js",
    "reproduce": "npm i playwright pdf-lib pdfjs-dist@3 && npx playwright install chromium && node bench-htmltopdf.js"
  }
}
