Skip to content
PolyFish CSS

Seven palettes, one page of markup

Two new themes, and a set of example pages that turn the framework's central claim into something you can diff.

· ~4 min read · 0.19.0 in the changelog

The claim PolyFish has made since the first release is that a theme is a stylesheet, not a fork. Components read roles — background, surface, text, accent — never colours, so redeclaring a dozen custom properties retints everything. That is easy to say. This release makes it easy to check.

One page, seven times

The examples section now has seven pages whose component markup is byte-identical. Strip the five short passages that name the palette, hash what is left, and all seven produce the same value. The only difference between them is a single <link> in the head. Open any two side by side and view source; the diff is the argument.

Two new themes

Paper is an editorial palette: warm off-white stock, a serif display face, rust and pine accents and almost no radius. It exists because the framework's main user is a publication, and long-form reading deserves a palette that gets out of the way. Mono is the opposite end: terminal black, a monospace display face, lime and cyan, square corners. Both carry their measured contrast figures in the file header — body text 14:1 and 16:1 respectively — so the next person to edit one knows what they are keeping.

A note on the site

This release also adds analytics to polyfish.org. The framework you download is unaffected and still loads nothing from anywhere; the site's Content-Security-Policy now names exactly one extra origin, and the about page explains why that script carries no integrity hash.

Update: the claim was only half true

Seven palettes producing identical markup proved the structural half. The colour half did not survive its first real test. When the suite finally ran in a browser, about sixty component declarations turned out to read palette tokens rather than roles, which meant that on five of the six themes the primary button hovered to the default green. The focus ring was a hard-coded rgba(143, 224, 106, 0.35), so every theme focused green too. Both were true for every release this post describes.

The fix was not sixty edits. Hover, wash, line and ring colours are derived from the accent now, so the interesting half of a theme is one declaration:

:root { --pf-accent: #d9734e; }

Deriving them raised a question the hand-written themes had hidden: what does "darker on hover" mean when half the palettes put dark text on a light accent? Mixing toward black cut button text contrast from 11.3:1 to 6.7:1 on slate and from 10.2:1 to 6.0:1 on dusk. Mixing toward --pf-text can only improve the pairing, because the text colour always sits on the far side of the scale from the ink that sits on the accent.

The contrast figures we published were not all right either. Measured in a browser, on every palette: cream's accent was 3.96:1 — below AA — for links and button text, its second accent 3.6:1, and the default light scheme's links 5.4:1, on a site whose home page said AAA throughout. All of them now measure at least 7:1, and the numbers come from a test that runs on every palette rather than a script someone remembered to run.

What this post does not cover

  • Colour theory. The contrast maths here is WCAG ratios, not perceptual design advice.
  • Automatic palette generation from a brand colour — the accent still has to be chosen by a person.
  • Print colour, which the print stylesheet forces to black on white regardless of theme.

Checked against color-mix(), custom properties, below AA. Code blocks are reproduced from the PolyFishCSS source files, not reconstructed from description. Figures are measured from the build they describe.

What this doesn’t cover

A palette is colour. It does not move a single component, change a measure, or alter the type scale, and no amount of retinting makes a layout suit a different kind of site. The contrast figures here are for the pairs we test — body text, links, buttons and code — not for every combination you could build from the tokens.

Sources: MDN on color-mix() and W3C on contrast minimums. The derived-token block is reproduced from PolyFishCSS-Core.css; the contrast ratios are measured in Chromium.

Theming Colour Contrast Tokens Accessibility Release CSS