What Finally Became Safe in Web Typography
Metric overrides, optical sizing, text wrap and font loading. What each feature closed, where support is still uneven, and a correct font face block to copy.
Date
Category
Writer

In 2013 I shipped a site where the headline arrived, sat there for eight hundred milliseconds in Georgia, then jumped two lines shorter as the real face loaded and every paragraph below it moved. The client saw it, said nothing, and I spent a week writing a font loader in JavaScript that preloaded, set a class on the html element, cached a flag in localStorage, and got the second page view right. That was the standard practice. It was a hundred lines of script to solve a problem that is now three CSS descriptors.
A set of typographic risks that used to require workarounds have quietly closed. Not all of them, and not evenly across browsers, so it is worth going through each one and saying precisely what it does, where it is defined and what its support actually looks like.
font-display, or choosing which failure you want
font-display is a descriptor in @font-face, defined in CSS Fonts Module Level 4. It does not make fonts load faster. It gives you control over the three periods the browser passes through while waiting, and lets you say what should happen in each.
The three periods are the block period, during which an unloaded font renders invisible fallback text; the swap period, during which it renders visible fallback text; and the failure period, after which the browser gives up and uses the fallback permanently.
Value | Block period | Swap period | What you are choosing |
|---|---|---|---|
auto | User agent defined | User agent defined | Whatever the browser prefers |
block | Short | Infinite | Invisible text now, correct type eventually |
swap | Extremely small | Infinite | Readable text now, a swap whenever it lands |
fallback | Extremely small | Short | Readable text now, a swap only if it is quick |
optional | Extremely small | None | No swap at all on this page view |
The interesting value is optional, which is the one most people never reach for. It tells the browser to use the web font only if it is already available, and otherwise to render the fallback and never swap. Katie Hempenius and Barry Pollard, in web.dev's font best practices, recommend it outright for performance: it gives minimal delay in rendering text and no font-swap layout shift at all.
The trade is honest and stark. With optional, a slow first visit sees your fallback for the entire session. Whether that is acceptable is a brand question, not a technical one, which is why the default advice of swap persists. But note what swap actually commits you to: a guaranteed reflow at an unpredictable moment, on every uncached visit, forever.
Support is not a consideration. font-display landed in Chrome 60, Firefox 58 and Safari 11.1, and MDN records it as widely available since January 2020.
The metric overrides, and the catch nobody mentions
This is the genuinely new capability, and the reason the JavaScript font loader is dead. CSS Fonts Module Level 5 defines four descriptors that let you reshape a fallback font so that it occupies the same space as the web font it stands in for.
size-adjust is defined in the spec as a descriptor that "defines a multiplier for glyph outlines and metrics associated with this font, to allow the author to harmonize the designs of various fonts when rendered at the same font-size". It scales everything, including glyph advances and baseline tables, which is what fixes horizontal fit.
Alongside it, ascent-override, descent-override and line-gap-override each "specify the ascent metric", "the descent metric" and "the line gap metric" of the font respectively, as a percentage of the effective font size after adjustment. Those three fix vertical fit, which is what determines line box height and therefore whether the paragraph below moves.
Katie Hempenius's Chrome article on font fallbacks explains the division of labour exactly: "By itself, size-adjust has limited applications for improving font fallbacks", but "combining size-adjust with font metric overrides makes it possible to make any two fonts match each other both horizontally and vertically." Get all four right and the swap is invisible. As the article puts it, the approach "can effectively eliminate font-related layout-shifts".
Here is the catch, and it is the reason I would not describe this technique as safe without qualification.
As of early 2026, Safari does not support ascent-override, descent-override or line-gap-override at all. Chrome has had them since version 87 and Firefox since 89. In Safari they are present only in Technology Preview.
I had assumed these were settled, because they have been in Chromium since 2020 and every tutorial treats them as ordinary CSS. MDN's browser compatibility data lists Safari as unsupported, and caniuse shows the descriptors unsupported across the whole stable Safari range, with support only in Technology Preview. Global coverage sits around 81 per cent, not the 95-plus that the phrase "widely available" implies.
size-adjust itself is in better shape: Chrome 92, Firefox 92, Safari 17, and MDN records it as widely available since September 2023. So on Safari you can correct the horizontal fit and not the vertical. That is a partial fix, which is better than nothing and worse than the articles suggest.
Optical sizing, and why opsz is unlike every other axis
font-optical-sizing, defined in CSS Fonts Level 4, takes auto or none. With auto, which is the initial value, the browser adjusts glyph shapes to the rendered size: thicker strokes and larger serifs at small sizes, finer strokes and more stroke contrast at large ones. It works by driving the opsz variation axis of a variable font from the computed font size. MDN records it as widely available since March 2020.
What makes opsz worth a paragraph of its own is that it is the only registered axis with a defined external meaning. Microsoft's OpenType registered axis documentation states that "The scale for the Optical size axis is designed to provide a much stronger degree of interoperability. For instance, two different fonts with an optical-size value of 20 are assumed to be best suited to text set at 20 points, because the scale is designed that way."
Weight 400 in one family is not weight 400 in another. Optical size 20 is supposed to mean the same thing everywhere, which is why the browser can set it automatically and why you almost never need to touch it. The correct action for optical sizing, in nearly every case, is to leave it alone and let auto do its work, which is only true because the axis was designed to be interoperable.
Balance and pretty
Line breaking was the last thing designers were still doing by hand, inserting non-breaking spaces into headlines to stop a one-word last line. text-wrap, from CSS Text Module Level 4, took that over.
balance evens the number of characters across lines, which is what you want for headings, pull quotes and captions. pretty uses a slower algorithm that favours better layout over speed and, in Chromium, concentrates on avoiding orphans at the end of a paragraph.
Two caveats that are easy to miss. First, balance is capped for cost: MDN records it as applying only to blocks of six lines or fewer in Chromium and ten or fewer in Firefox. It is a headline tool, not a body-copy tool, by design. Second, pretty is not one behaviour. WebKit's Safari 26.0 release notes say that "Our implementation of pretty adjusts how text wraps in an effort to even out the ragged edge, improve hyphenation, and prevent short last lines", and, pointedly, that "In WebKit, all lines of text in an element are improved by pretty, not just a select group of lines at the end of the paragraph."
So a paragraph set with text-wrap: pretty will rag differently in Safari than in Chrome. Both are conformant. Neither is wrong. If your layout depends on a specific rag, this property is not the tool.
Value | Chrome and Edge | Firefox | Safari |
|---|---|---|---|
text-wrap | 114 | 121 | 17.4 |
text-wrap: balance | 114 | 121 | 17.5 |
text-wrap: pretty | 117 | Not supported | 26 |
text-wrap-style longhand | 130 | 124 | 17.5 |
Both values fail silently and safely. An engine that does not understand them wraps normally, which is the behaviour every page had until 2023.
Variable fonts were not new in 2016
Variable fonts were announced on 14 September 2016, as part of OpenType 1.8, jointly by Google, Microsoft, Apple and Adobe. Google's announcement put the promise simply: "With variable fonts, your device can display text in myriads of weights, widths, or other stylistic variations from a single font file with less space and bandwidth."
The part that is usually left out of that story is that the mechanism was not invented then. Microsoft's own OpenType specification is explicit: "Font variation mechanisms for fonts using TrueType outlines were first introduced by Apple in 'TrueType GX'. Some of the tables used for OpenType Font Variations have been adapted from Apple's earlier specifications with some enhancements and revisions." What happened in 2016 was that four companies who had each tried this separately agreed on one format. The technology is roughly two decades older than the announcement.
For typography work the practical point is support, and support stopped being a question some time ago: Chrome 66, Edge 17, Firefox 62, Safari 11, at around 96.5 per cent of global usage. The only rule worth repeating is MDN's, which reflects W3C intent: the low-level font-variation-settings syntax should be used "only being used to set values or axes not available otherwise". Use font-weight: 375, not font-variation-settings: "wght" 375. The high-level properties inherit, animate and cascade correctly. The low-level one sets every axis at once and quietly resets the ones you left out.
A block I would actually ship
The percentages above are placeholders for a real pair of fonts. They have to be computed from the actual metrics of both faces, and the shape of that calculation is what the Chrome article demonstrates with its Poppins and Arial example, where the four values come out as a size-adjust of 60.85 per cent, an ascent-override of 164.34 per cent, a descent-override of 57.52 per cent and a line-gap-override of 16.43 per cent. Those numbers look absurd until you realise they are compensating for two typefaces with very different relationships between em square and x-height.
Feature | Problem it closed | Support position |
|---|---|---|
font-display | No control over invisible or swapped text during load | Settled since 2020 in all engines |
size-adjust | Fallback and web font differ in horizontal fit | Chrome 92, Firefox 92, Safari 17 |
ascent-override, descent-override, line-gap-override | Fallback and web font differ in line box height, causing reflow | Chrome 87, Firefox 89, absent from stable Safari |
font-optical-sizing | One outline used at every size | Widely available since 2020 |
text-wrap: balance | Manual non-breaking spaces in headlines | Chrome 114, Firefox 121, Safari 17.5 |
text-wrap: pretty | Orphans and poor rag in body copy | Chrome 117, Safari 26, no Firefox, engines differ |
Variable fonts | One file per weight and width | Universal in practice since 2018 |
What is still not safe
Three things, stated plainly, so that nobody reads the above as an all-clear.
Vertical metric matching is not cross-browser. The override descriptors are the core of the layout shift fix and Safari does not have them in a stable release. If a large part of your audience is on Safari, budget for some residual shift or choose font-display: optional and accept the fallback on cold visits.
text-wrap: pretty is a family of behaviours, not one. Chromium and WebKit have said in their own documentation that they optimise different parts of the paragraph. Treat it as a quality improvement whose exact result you do not control.
And the oldest one, which no descriptor fixes: you still have to look at it. Every feature here adjusts numbers derived from font metadata, and font metadata is frequently wrong. Metric overrides computed from a face with an inflated ascender will match the wrong thing very precisely. The block above is a starting point that a person has to check on a real page, at real sizes, on a real device, which is the same thing that was true in 2013.
Sources
W3C CSS Working Group, CSS Fonts Module Level 4, for font-display and font-optical-sizing. drafts.csswg.org/css-fonts-4/
W3C CSS Working Group, CSS Fonts Module Level 5, editor's draft, for the definitions of size-adjust, ascent-override, descent-override and line-gap-override. drafts.csswg.org/css-fonts-5/
MDN Web Docs, "font-display", for the block, swap and failure periods and the per-value table. developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display
MDN Web Docs, "size-adjust", for the definition and the widely available since September 2023 status. developer.mozilla.org/en-US/docs/Web/CSS/@font-face/size-adjust
MDN browser compatibility data, css/at-rules/font-face.json, for the version numbers of font-display, size-adjust and the three metric override descriptors. github.com/mdn/browser-compat-data
caniuse, "ascent-override @font-face descriptor", showing no support across stable Safari and Safari on iOS, with support only in Technology Preview. caniuse.com/mdn-css_at-rules_font-face_ascent-override
Katie Hempenius, "Improved font fallbacks", Chrome for Developers, for the mechanism of metric overrides and the Poppins and Arial worked example. developer.chrome.com/blog/font-fallbacks
Katie Hempenius and Barry Pollard, "Best practices for fonts", web.dev, updated 4 October 2022, for the font-display recommendations, the WOFF2 compression figure and the preload caution. web.dev/articles/font-best-practices
MDN Web Docs, "font-optical-sizing", for the auto and none behaviour and the widely available since March 2020 status. developer.mozilla.org/en-US/docs/Web/CSS/font-optical-sizing
Microsoft, "OpenType design-variation axis tag registry", for the interoperability property of the opsz axis. learn.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg
Microsoft, "OpenType Font Variations overview", for the statement that variation mechanisms were first introduced by Apple in TrueType GX. learn.microsoft.com/en-us/typography/opentype/spec/otvaroverview
MDN Web Docs, "text-wrap-style", for the value definitions and the six-line and ten-line balance limits in Chromium and Firefox. developer.mozilla.org/en-US/docs/Web/CSS/text-wrap-style
MDN browser compatibility data, css/properties/text-wrap.json and text-wrap-style.json, for the version numbers in the support table. github.com/mdn/browser-compat-data
WebKit, "WebKit Features in Safari 26.0", 15 September 2025, for WebKit's description of its text-wrap: pretty implementation. webkit.org/blog/17333/webkit-features-in-safari-26-0/
Google Open Source Blog, "Introducing OpenType Font Variations", 14 September 2016. opensource.googleblog.com/2016/09/introducing-opentype-font-variations.html
MDN Web Docs, "Variable fonts guide", for the registered axes, their CSS property mappings and the guidance to prefer high-level properties over font-variation-settings. developer.mozilla.org/en-US/docs/Web/CSS/CSS_fonts/Variable_fonts_guide
caniuse, "Variable fonts", for support from Chrome 66, Edge 17, Firefox 62 and Safari 11 at around 96.5 per cent global usage. caniuse.com/variable-fonts
Related reading
Latest Articles.
© Moc Mallen Studio
Thoughts, ideas, and perspectives on design, simplicity, and creative process.

