Skip to main content

Search rules

Search all UI Guides rules by name, category, or source

contentjakubkrehel

Properties Over Raw Font Tags

MUST

MUST: Use the CSS PROPERTY whenever one exists — `font-weight: 650`, `font-optical-sizing: auto`, `font-variant-numeric: tabular-nums` — not `font-variation-settings: "wght" 650` / `font-feature-settings: "tnum" 1`. Raw-tag declarations address axes that only exist inside the variable file, so when a non-variable fallback renders they SILENTLY DO NOTHING (weight collapses to 400, no console error). And `font-feature-settings` is ONE property, so a later declaration CLOBBERS an earlier one — add `"ss01" 1` to a rule that carried `"tnum" 1` and the tabular figures leave with it. Reserve the raw tags for custom axes (`"GRAD" 80`) and niche features (`"ss01" 1`) that have no property of their own.

Reach for font-weight and font-variant-numeric, not font-variation-settings and font-feature-settings

/* ✗ inert under a non-variable fallback; "tnum" clobbered by the next rule */
.price { font-variation-settings: "wght" 650; font-feature-settings: "tnum" 1; }
/* ✓ real properties, survive the fallback, cannot clobber each other */
.price { font-weight: 650; font-variant-numeric: tabular-nums; font-feature-settings: "ss01" 1; }

Bad

Good

Why it matters

This is an API rule, not a typography rule, and it is the one people get wrong precisely because both spellings look equivalent while the variable font is loading fine. They are not. `font-variation-settings: "wght" 650` addresses an axis that only exists inside a variable file, so the moment the fallback stack renders — the file 404s, the CDN is blocked, the user is on a metered connection with fonts disabled — the declaration is not overridden, it is inert.

The weight collapses to 400, the console says nothing, and the semibold heading you designed is now body copy. `font-weight: 650` is a real property that every font stack understands: the browser picks the closest available face and the hierarchy survives. The same asymmetry applies below the surface for features: `font-feature-settings` is a single low-level property rather than a set of independent switches, so the day someone adds `"ss01" 1` to a rule that already carried `"tnum" 1`, the tabular figures leave with it and the ticker starts jittering again.

`font-variant-numeric: tabular-nums` cannot be clobbered that way, because it lives on its own property. Note this is orthogonal to content-tabular-numbers, which says *what* to apply and never *which API* — this is the rule that picks the API. Raw tags are not banned; they are the escape hatch, and the only correct use of them, for custom axes like `"GRAD" 80` and niche features like `"ss01" 1` that have no property of their own.

Built by Gleb Stroganov, design engineer at Evil Martians.

The rules come from other people's skills and guidelines — Vercel, Rauno Freiberg, @Ibelick, impeccable, Emil Kowalski, Tailwind, RAMS — each one credited on the Sources page. The work here is extraction and wiring: every rule is pulled into one corpus, given a good and a bad example you can operate, a MUST/SHOULD/NEVER rule an agent can paste, and a link back to where it came from.