In #4792, we agreed to add @font-face descriptors to override ascent, descent and line gap of a font, which allows us to match the line height metrics between fallback and primary font, and hence, reduce layout shift.
In https://github.com/w3c/csswg-drafts/issues/4792#issuecomment-689099191 I also proposed advance-override to override the inline spacing and further reduce layout shift. The proposal still has several problems and hence remains under discussion.
So I opened this issue to specifically discuss if we should add new descriptor(s) to @font-face to override the inline spacing for matching text widths and reducing layout shift; And if we should, how should the new descriptor(s) work.
To start, it might be useful to divide the discussion into monospace fonts and variable-width fonts.
For monospace fonts, the proposal is straightforward I think. You have a primary font, and you want the fallback font to have an identical advance so it keeps to the grid. So we can just override the advance with a manually-set value, done. (Do we want to center the glyph into the specified advance?) This also prevents fallback to things like emoji fonts from screwing up your monospace grid, at least if we do it right.
Variable-width is potentially more difficult:
i to a wide font, but characters like w are likely to be a lot more different between the two.letter-spacing, so you don't get potentially-unsightly gaps at box edges?I am not sure that "monospaced" fonts are that simple in an i18n context. For instance, I believe that for CJK, "mono-spaced" is actually "dual-spaced", with full width glyphs being typically 1em wide, and half-spaced glyphs being half that size. Adding a single measurement to all glyphs wouldn't actually work then, would it?
We've done some manual testing of two versions of adjustment:
advance-override: Add a fixed amount to all glyph advancesadvance-proportional-override: Multiply the glyph advances by a given percentage(The names are bad but I don't have a better idea...)
We found one case with legibility issues: when the font is too bold, reducing the advances may squeeze the characters together, making text hard to read. advance-override even made all the word boundaries disappear, while advance-proportional-override still preserves word boundaries.
Other cases seem fine. Anyway, it would be great if someone professional in Persian or Hindi could take a look at those test cases, as I am very unfamiliar with these scripts.
As a side note, I'm not sure how much we should be concerned about legibility issues. Our main focus is reducing CLS, so in most cases the overridden text should just appear as a flash. It's an issue only when the web font fails to load, and the fallback font differs from the web font so much that the overridden text becomes hard to read, in which case maybe it's better to use a different fallback font.
Personally, I'm unconvinced this is a good idea at all. Glyph spacing is an integral part of the font design, and arbitrarily overriding the spacing of glyphs -- not for a specific design intent such as letter-spacing but just to try and match metrics of some other font -- is never likely to look good.
To minimize layout shift, specify fallback fonts that have similar metrics to the desired webfont. If they're different enough that layout shift will be a significant problem, then they're also different enough that forcing them to match the intended font will be a distortion.
If it's more important to avoid layout shift than to use the designer's "ideal" font, then add a font-display descriptor to make it optional, and if it doesn't load quickly enough, just continue to use a fallback (with its own proper glyph spacing, not shoehorned into the metrics of the font that didn't load).
An alternative way to try and minimize layout shift if a fallback font is used would be to have a descriptor that allows a scaling factor to be applied to the font (thus improving the metrics-match by scaling the font as a whole, rather than by distorting its glyph widths).
If it's more important to avoid layout shift than to use the designer's "ideal" font, then add a font-display descriptor to make it optional, and if it doesn't load quickly enough, just continue to use a fallback (with its own proper glyph spacing, not shoehorned into the metrics of the font that didn't load).
Here we want both stable layout and the designer's ideal font, so font-display can't achieve the purpose. Instead,
we're using quality of fallback font typography as the cost of the tradeoff.
An alternative way to try and minimize layout shift if a fallback font is used would be to have a descriptor that allows a scaling factor to be applied to the font (thus improving the metrics-match by scaling the font as a whole, rather than by distorting its glyph widths).
This sounds like a viable idea. I'll do some testing with it.
Btw there's some similarity with #126, just for the record.
Here we want both stable layout and the designer's ideal font, so
font-displaycan't achieve the purpose. Instead,
we're using quality of fallback font typography as the cost of the tradeoff.
It's possible the desired font will fail to load altogether, and the user will be left looking at the fallback font; it would be sad if they're left with not just a fallback font, but a fallback font with distorted spacing.
Hmm, scaling the font size does seem to work better... See screenshots:
The CSS Working Group just discussed Reduce layout shift via @font-face descriptor(s) overriding inline spacing.
The full IRC log of that discussion
<Rossen_> Topic: Reduce layout shift via @font-face descriptor(s) overriding inline spacing
<Rossen_> github: https://github.com/w3c/csswg-drafts/issues/5533
<chris> q+ to say something that only really works on monospace is kinda suspect
<fremy> TabAtkins: we talked about this in the past, we have some updates
<Rossen_> q?
<Rossen_> ack chris
<Zakim> chris, you wanted to say something that only really works on monospace is kinda suspect
<fremy> chris: the idea was that to avoid layout shift, you would put values that would update the advance value of the font
<fremy> chris: that shift however only works if you have a monospace font
<xiaochengh> q+
<jfkthame> q+
<fremy> chris: a multiplier would work
<fremy> chris: but that would not work visually
<fremy> chris: because the glyphs will overlap each other
<fremy> chris: so my thought is that we should instead scale the glyphs
<Rossen_> ack xiaochengh
<fremy> xiaochengh: there are 3 proposals in the issue
<fremy> xiaochengh: 1 add fixed value to the advance
<fremy> xiaochengh: 2 scale the advances
<jfkthame> q-
<fremy> xiaochengh: 3 scale the font-size by some percentage
<fremy> xiaochengh: I tested all the 3
<fremy> xiaochengh: and I don't have a strong opinion
<fantasai> +1 to everything jfkthame said in the thread
<fremy> xiaochengh: I think 3 > 2 >> 1
<fremy> florian: is this meant to be tied to font-display?
<fremy> florian: so this only applies after the fallback resolves?
<fremy> xiaochengh: we put that in the font descriptor
<TabAtkins> q+
<myles> See also: https://github.com/w3c/csswg-drafts/issues/450
<fremy> xiaochengh: so if we fail to load the web font, we use the distorted version of the fallback font
<Rossen_> q?
<myles> q+
<fremy> TabAtkins: based on JonathanNeal comments
<myles> specifically: https://github.com/w3c/csswg-drafts/issues/450#issuecomment-245485065
<fremy> (issue with audio)
<fantasai> s/JonathanNeal/jfkthame/
<Rossen_> ack TabAtkins
<fremy> TabAtkins: based on the comment scaling the whole thing is similar to the font-size change
<fremy> TabAtkins: what was things comment?
<fremy> florian: I think that was its preferred option
<fantasai> Clearly nobody tried this with Arabic. Doing anything other than scaling that would be seriously broken
<fremy> TabAtkins: yeah, then let's agree with his preferred outcome
<florian> xiaocheng did try arabic
<fremy> TabAtkins: especially since we have similar things already
<fremy> xiaochengh: I agree with that
<Rossen_> ack myles
<fremy> myles: there is an issue I linked to
<fremy> myles: and there is one comment in it which I think is useful
<fremy> jason list 5 adjustments he would be interested in making
<fantasai> myles is referencing https://github.com/w3c/csswg-drafts/issues/450#issuecomment-245485065 I think
<fremy> myles: most of properties not descriptors
<fremy> myles: so I think the correct solution would not include a descriptor
<Rossen_> q?
<fremy> myles: so this is one quick fix, but a proper solution would be different I think
<fremy> myles: and interact with the 5 properties he mentioned
<fremy> myles: and since we probably don't want 2 ways of fixing this
<Rossen_> ack fantasai
<fremy> myles: I would rather not add this as a stop-gap switch
<fremy> fantasai: there are other use cases for this descriptor though
<fremy> fantasai: so we could look into this as well
<fremy> Rossen_: do you think adding this fix is a step in the wrong direction?
<fremy> myles: I think the answer is yes
<fremy> myles: because this problem is not urgent
<fantasai> s/though/though: because glyphs are often drawn at different actual sizes for the same nominal size, a scale factor could be useful in other cases/
<fremy> myles: so given that, the value of solving one little part is greater than the cost of having two competing solutions in the long term
<fremy> Rossen_: so, back to the folks who opened this
<fremy> Rossen_: any comment?
<myles> s/greater/less/
<fremy> chris: I agree with myles I think
<chris> btw we have been trying to solve this since 1997
<fremy> myles: but I want to encourage xiaochengh to look into this more
<chris> https://www.w3.org/TR/WD-font-970721#widths
<fremy> myles: there is a solution here, but it's not yet there
<fremy> xiaochengh: ok, I think I agree with myles
<fremy> chris: we had stuff in 1997 about this
<fremy> chris: I pated the link in the chat
<fremy> jfkthame: we could use the font data and use a data url as the source ^_^
According to the discussion, I think this should be marked as a dup of https://github.com//issues/450
Most helpful comment
I am not sure that "monospaced" fonts are that simple in an i18n context. For instance, I believe that for CJK, "mono-spaced" is actually "dual-spaced", with full width glyphs being typically 1em wide, and half-spaced glyphs being half that size. Adding a single measurement to all glyphs wouldn't actually work then, would it?