Ask any LLM to style a layout and it uses CSS units like: px, rem, em, % and vh. So do you, out of habit. But CSS has grown its number of units. Ones that fit specific jobs way better than your old defaults. Here are seven your code generator has probably never suggested.
They are all baseline ready (e.g. supported by core browsers for at least 30 months), so there is no fallback excuse left. Let’s get into it.
Logical properties: think in axes (x and y)
A few of these units only make sense when you drop the ideas of “width” and “height” and think in axes instead. CSS now measures along the inline axis (the direction your text flows, left to right in, for example, English) and the block axis (the direction blocks stack, top to bottom). Once that makes sense, units like vi, vb and cqi will be less weird. 💡
Full screen height: dvh
100vh includes the space behind the browser’s address bar, so a full height hero can get clipped the moment the bar shows up. The dynamic viewport unit fixes this.
.hero { min-height: 100dvh; } 1dvh is one percent of the dynamic viewport, the size that shrinks and grows as the browser chrome moves. Its stable siblings svh (small, chrome shown) and lvh (large, chrome hidden) are there when you want a value that never moves.
Scroll offsets: vi and vb
vi is one percent of the viewport’s inline axis (again: the direction the text flows), vb the block axis (how blocks are stacked). Because they are axis based, a change in writing-mode (the direction text flows) survives.
A common use case for me, is giving anchored jumps some room to breath:
[id] { scroll-margin-top: 10vb; } Upon a page click, or when scroll-into-view fires, the heading lands 20vb below the top instead of jammed against the edge. Try doing that cleanly with vh and you are already guessing at orientations.
Container aware type: cqi
Viewport units can’t tell a card in a 300px sidebar from the same card in a 700px main column. They both see the whole window. Container query units measure the nearest container instead, which is what you actually want for reusable components.
.cards { container-type: inline-size; } .card { font-size: clamp(1rem, 4cqi, 1.5rem); padding: 3cqi; } 1cqi is one percent of the container’s inline size. The card now scales to wherever it lives, with zero media queries. The unit reads the nearest ancestor with container-type, never the element itself. And if you need cqb (block axis) you must set container-type: size and give the container a height.
Line perfect spacing: lh
1lh is exactly one line height of the current font’s size. That sounds small, but it lets you tie any spacing to your actual text rhythm instead of eyeballing em values.
.field { line-height: 1.5; } textarea { height: 3lh; } p { margin-block: 1lh; } The textarea trick is one I use all the time now. No more rows guessing or JavaScript needed. rlh is the root version, the same idea as rem versus em. Both landed Baseline in November 2023.
Text matched icons: cap
Ever tried to size an inline icon next to a label and end up nudging 1em, then 1.2em, then 0.9em? The cap unit ends the guessing. It equals the cap height of the font, the height of its capital letters.
.icon { width: 1cap; height: 1cap; vertical-align: baseline; } Now the icon lines up with the capitals in your text, in any font, at any size. Satisfying!
Reading measure: ch and ic
1ch is the advance width of the 0 glyph in the element’s own font. Because it is relative to that font’s size, 60ch means roughly sixty characters wide whether the text is 14px or 32px. The measure stays constant in character count, which is exactly what comfortable reading wants.
.prose { max-width: 60ch; } .input { width: 20ch; } Note that ch is built on the 0 glyph, so it is an approximation of average character width, not a precise count. And for wide or CJK scripts (graphemes), reach for ic instead, which measures a full width ideograph.
Edge fitting squares: vmin and vmax
vmin is one percent of the smaller viewport edge, vmax the larger. That makes them perfect for elements that must behave in any orientation without a media query.
.avatar { width: min(50vmin, 200px); aspect-ratio: 1; } The avatar is half the smaller screen edge, capped at 200px, and never overflows when you rotate the phone. Same trick works for full bleed overlays with vmax.


