@supports and @font-face troubles

November 3rd, 2024. Tagged: font-face, performance

I've been crafting a nice font-face fallback, something like this:

@font-face {
  font-family: fallback;
  src: local('Helvetica Neue');

  ascent-override: 85%;
  descent-override: 19.5%;
  line-gap-override: 0%;

  size-adjust: 106.74%;
}

It works well, however Safari doesn't yet support ascent-override, descent-override, nor line-gap-override in @font-face blocks. It does support size-adjust though.

Since my code requires all 4, the results with size-adjust-only look bad. Worse than no overrides. Easy-peasy I thought, I'll target Safari and not give it any of the 4.

I wanted to use @supports in CSS to keep everything nice and compact. No JavaScript, no external CSS, all this is for a font fallback, so it should be loaded as early in the page as possible, together with the @font-face.

Unfortunately, turns out that for example both

@supports (ascent-override: normal) {/* css here */}

and

@supports (size-adjust: 100%) {/* css here */}

end up with the "css here" not being used.

In fact even the amazing font-display: swap is not declared as being @support-ed.

Using the JavaScript API I get this in Chrome, Safari and Firefox:

console.log(CSS.supports('font-stretch: normal')); // true
console.log(CSS.supports('font-style: normal')); // true
console.log(CSS.supports('font-display: swap')); // false
console.log(CSS.supports('size-adjust: 100%')); // false
console.log(CSS.supports('ascent-override: normal')); // false

Huh? Am I using @supports incorrectly? Or browsers forget to update this part of the code after adding a new feature? But what are the chances that all three make the same error?

It's not like anything in @font-face is not declared @support-ed, because font-style and font-stretch are.

Clearing out my confusion

Ryan Townsend pointed out what font-style and font-stretch work because they double as properties not only as font descriptors. So turns out font descriptors are not supported by @supports. Darn!

Noam Rosenthal pointed out this github issue, open in 2018, to add support for descriptors too.

For now I came up with 2 (imperfect) solutions. One that uses JavaScript to check for a property, like

'ascentOverride' in new FontFace(1,1); // true in Chrome, FF, false in Saf

Not ideal because it's JavaScript.

The other one is to target non-Safari in CSS is with a different property to use as a "proxy". Using the wonderful Compare Browsers feature of CanIUse.com I found a good candidate:

@supports (overflow-anchor: auto) {
  @font-face {    
    /* works in Chrome, Edge, FF, but not in Safari*/ 
  }
}

It's not-ideal to test one thing (overflow-anchor) and use another (ascent-override) but at least no JavaScript is involved

Comments? Find me on BlueSky, Mastodon, LinkedIn, Threads, Twitter