---
name: html-template-authoring
description: Author or repair a Portwood HTML template that renders correctly through Blob.toPdf (Flying Saucer). Use when writing a new template, converting a design to a template, or fixing one whose PDF output doesn't match the source — collapsed layout, missing images, wrong fonts, broken charts.
---
# Authoring HTML templates for Portwood
**HTML is the recommended source format.** It skips the DOCX→HTML parse and lands more
reliably in the renderer. Steer new authors here, and chart authors here without
exception.
## The renderer is CSS 2.1
`Blob.toPdf` is Flying Saucer: **CSS 2.1 plus a small CSS 3 subset**. Unsupported
properties are _silently ignored_ — the page still renders, but layout collapses to
default block flow. Nothing warns you.
### Never use
- `display: flex`, `display: grid`, `gap`
- `linear-gradient(...)` and friends
- `calc(...)`
- CSS custom properties (`var(--x)`)
- most CSS 3 layout
### Use instead
- `
`-based layout for anything multi-column
- solid background colors
- absolute lengths (`pt`, `in`) and percentages
- `display: table-cell` / `table-row` on `` where you need cell behavior without a
real table
### The `tbody` trap
```css
table > tbody > tr > td { ... } /* silently matches NOTHING */
```
The parse tree has no implied `
`. Use `td` attribute selectors or class-only
selectors:
```css
td.total { ... }
```
## Images
**URLs must be relative.** Absolute `https://…` URLs and `data:` URIs both render
broken — this is a hard constraint of the renderer, not a bug to work around.
If the same image appears at two different sizes, the renderer caches **one layout size
per URL**. Vary the URL to force a re-layout (the engine appends a size key for this
reason).
## Fonts and symbols
The base font families resolve to the base-14 PDF fonts (Helvetica / Times / Courier,
WinAnsi). **Anything outside Latin-1 renders as nothing** — not a box, not a fallback,
absent. Checkmarks, arrows, CJK, Greek, Cyrillic all disappear.
`'Arial Unicode MS'` is the one family that draws them, embedding as a subsetted CID
font. The trade-off is real and worth knowing:
| | Symbols / CJK | Bold |
| -------------------- | ------------- | ------------------------------------------------------ |
| `'Arial Unicode MS'` | ✅ | ❌ — no bold face; `font-weight: bold` renders regular |
| every other family | ❌ | ✅ |
So a symbol-heavy document gives up bold. Build hierarchy from **size, colour and fill
bands** instead — reversed white-on-dark headers, tinted totals rows, a solid band
behind the key number.
Embedding costs roughly 1.5KB → 70KB per page that uses it, and only for the glyphs
used.
## `@page` conflicts
The engine builds a `