CSS & layout

tidy-typography.css is a reset that only touches the text

tidy-typography.css is a reset that only touches the text

You drop a heading into a 300px sidebar. Your fluid type scale runs on vw, so the heading sizes itself for the whole window. It comes out huge. It wraps onto four lines, and the last line is one word. Then the webfont arrives and the block jumps again.

Three bugs. All typography. None of them is fixed by the margin-and-box-sizing reset you already ship.

Stu Robson's new CSS-Tricks article goes after exactly that layer. He has collected the useful modern type declarations into one default stylesheet, tidy-typography.css, covering rendering and fallback rules, fluid sizing, vertical rhythm, wrapping, hyphenation and OpenType detail. Take the whole file or take the one declaration that fixes today's irritation. He is upfront that some of it is experimental and that support is uneven, so it needs guardrails rather than blind inclusion.

Size against the column

Robson's point is simple: viewport-based fluid type has no idea how wide its element is. Swap vw for cqi and the scale reads the container instead.

.article-container {
  container-type: inline-size;
}

:root {
  --step-0: clamp(1rem, 0.9rem + 1cqi, 1.125rem);
  --step-3: clamp(2rem, 1.6rem + 3cqi, 2.75rem);
}

The same heading now fits an article column and a 300px sidebar, without a media query per component.

One thing to check in devtools. A cqi length resolves against the nearest container above the element that uses it, and with no container it falls back to the small viewport size. The finished file sets font-size: var(--step-0) on body, which sits above any .article-container. So the headings inside the column get container math. Body copy gets viewport math inside a narrow clamp. That is fine. Just know which one you are looking at.

Trim the line box

line-height adds half-leading above the cap height and below the baseline. You never notice until text has to line up tightly against an icon or a box edge, and then you reach for a negative margin tuned to one font. Robson's replacement measures from the font metrics:

:is(h1, h2, h3, h4, h5, h6), p, blockquote, figcaption, li {
  text-box: trim-both cap alphabetic;
}

The article also shows the proposed :heading pseudo-class from Selectors Level 5. Robson says it has not landed in browsers and belongs behind @supports selector(:heading). Take that seriously. A plain selector list is all-or-nothing, so one selector the parser doesn't know drops the whole rule, p and li included. The finished file spells the headings out with :is(), which is the version to copy.

Wrapping, handed back to CSS

p, li, dd {
  text-wrap: pretty;
  max-width: 65ch;
}

[contenteditable="true"] {
  text-wrap: stable;
}

Headings, blockquotes and figcaptions get text-wrap: balance, which Robson says works best on blocks of up to about six lines. pretty avoids a stranded last word without rebalancing the whole paragraph. stable stops editable text from reshuffling the paragraph on every new word. Both replace the JavaScript orphan fixers. Delete them.

Hyphenation gets the same tuning. hyphens: auto needs a correct lang attribute, because without a dictionary the browser can't hyphenate anything. On top of it Robson sets hyphenate-limit-chars: 6 3 3, hyphenate-limit-lines: 2, hyphenate-limit-zone: 8% and hyphenate-limit-last: always, and adds the -webkit- equivalents because Safari needs them. Code, kbd, samp, var and headings go back to hyphens: manual. A broken code word can change its meaning.

Let the font do the fine work

This is the part I'd steal first.

  • font-synthesis: none stops the browser inventing a bold or italic the family doesn't have.
  • font-size-adjust: from-font uses font metrics to shrink the visible jump when the fallback swaps for the webfont.
  • size-adjust: 105% inside an @font-face scales a monospace face to match the x-height of the prose around it, without touching font-size.
  • A --vf-grad custom property drops to -50 under prefers-color-scheme: dark and feeds font-variation-settings: "GRAD" var(--vf-grad, 0). Light text on a dark background reads heavier, and the grade axis thins it without changing glyph width. Fonts without the axis ignore it.
  • font-variant-position: sub and super, wrapped in @supports, use the font's real sub and superscript glyphs. Robson warns that most typefaces only include numerals for these, so check your font first.

The locale quote rules sit inside :where(:lang(en)) and friends. That's zero specificity, so a project overrides them with one class. :is() keeps the specificity of its most specific argument. That's the trade between the two.

Where to draw the line

Robson's closing caveat is the honest one. Unsupported declarations are ignored, so the file can go in gradually, but that only helps when the unenhanced text already looks acceptable. He expects support to keep moving, especially for text-wrap and text-box-trim. And a news article, a marketing page and an editable product UI don't ask the same things of their text.

So don't paste all of it. Start with font-synthesis: none and text-wrap: pretty on your next project. Then open the sidebar again and see whether that heading still needs its media query.

Source: CSS-Tricks (css-tricks.com)

Related
CSS & layout

CSS random() puts a little deliberate mess back into your layout

In Smashing Magazine, Brecht De Ruyte works through the native random() function from CSS Values and Units Level 5 with demos of jittered letters, bouncing type and splayed cards, and draws a clear line around where randomness does not belong. He reports that Safari shipped it first, Chrome 156 is rolling it out, and Mozilla has sent positive signals about Firefox.

October 20, 2026
CSS & layout

Your icon is centered against the wrong thing

Ahmad Shadeed's new piece nails the icon-and-label bug that has been quietly wrong on every design system list for years, and the fix is one transform in the lh unit.

September 16, 2026
CSS & layout

The lh unit sizes to the line, not the font

Ahmad Shadeed's post on ishadeed.com tours the CSS lh unit, which resolves to the element's computed line-height. Here's where sizing against that line beats sizing against font-size.

August 1, 2026