Closed litherum closed 2 years ago
Yeah, it's not intentional that ch
should cause the "0"-containing subface of a composite face to be downloaded. I agree we should clarify that you can use the "not-defined" glyph if "0" isn't present.
(Is ".notdef
glyph" a widespread concept we can refer to?)
.notdef
is well-understood, well-defined, and common. (It's just glyphid 0 in every font, commonly rendered as the tofu)
I'd propose making the spec somewhat flexible here, as I can think of a few reasonable behaviors off the top of my head, and we probably shouldn't prescribe any until we can do more research:
We can make the spec say something like "if the primary font supports the '0' character, UAs must use the width of that character, otherwise, UAs should use an approximation of it using metrics from the primary font or a fallback font" and we can link to css-fonts for a definition of "supports." Given that almost all fonts support the '0' character, this is probably strong enough to be interoperable but flexible enough that we can find the best fallback.
Per the links in #3129, looks like WebKit is using (1) and Gecko is using (2). So yeah, if it's not clear one is superior to the other making the spec a bit flexible makes sense.
Blink does (1) too.
Is "
.notdef
glyph" a widespread concept we can refer to?.notdef is well-understood, well-defined, and common. (It's just glyphid 0 in every font, commonly rendered as the tofu)
.notdef
is defined in Recommendations for OpenType Fonts.
Today I discovered that a ‘ch’ unit in Font Awesome Pro (a popular icon font) is zero width in Safari. So, I think the .notdef glyph is not a reliable thing to fall back on. Average width doesn’t seem right either, as icons in an icon font tend to be much wider than a zero would be. Maybe something like 0.4em? Or use the width of an actual space character as a fallback first, if it is available?
Frankly, I don’t see why it can’t just use the next installed font from the font list (skipping past fonts that aren’t installed, or that would require a download).
We shouldn't be designing around the requirements of icon fonts. People shouldn't be using them in the first place.
People do use them. That’s the world we live in, and need to adapt to.
Also, I don’t think this is unique to icon fonts. I suspect that the one I’m connecting to (which I don’t have total control over), has been subsetted to save bandwidth, to remove characters that are not actually being used in content.
In those conditions, why not just...
use the next installed font from the font list (skipping past fonts that aren’t installed, or that would require a download).
It seems a perfectly reasonable thing to do, as it will always eventually find an already loaded (possibly system) font that has a zero in it.
I agree there are some such fonts. I've seen them before too. I don't think ch
needs to take care of such fonts.
I'd strongly say that calculating a ch
unit (or ex
, ic
, etc.) shouldn't cause a font to download, but I'm not sure that should mean giving up the use of the 0 as the reference glyph.
Consider the case of a custom font with just a few special characters (e.g., fancy ampersand) as the first font in the list, with a regular web font or system font as the next font in the stack. Using an artificially calculated value from the first font seems a poor choice if there is a font available (already downloaded or on the system) with a 0.
In most CSS environments, there will be at least a default font with a 0 in it. And if there really isn't, the spec already defines a fallback (0.5em).
Finding a system fallback font is not a cheap operation; it requires an RPC call in Blink due to sandbox, and the style recalc pauses during the RPC. I'm not very happy to bake it into the spec when no browsers do it today.
@kojiishi Is it a problem only for system fallback, or also for fallback through the list of specified fonts? E.g. if I have font-family: web font, local font, sans-serif
, is it a problem to check “local font” for '0'?
Mainly, I don't understand why there is any issue. The worries seem to be
ch is defined to use the actual font that is used for rendering. The two things noted above would only occur if:
the font actually used has no glyph for "0", AND
the font actually used has no .notdef (in this case, it would be a faulty font, or the font subsetter was faulty)
Also, falling back to another font for the width of "0" or .notdef misses the point of using the actual font.
So my preference would be an ordered list of things to try:
1) the width of the "0" glyph. if it doesn't have one, 2) the width of the .notdef glyph. if it doesn't have one (and thus, the font is broken), 3) use 0.5em
No additional webfont is ever downloaded, no additional local font is loaded either.
@svgeesus That sounds like a good start, although your wording doesn't acknowledge that there may be 2 or more active fonts (meaning loaded & being used in the document) applying for the element. Would you would search for first the 0 and then the .notdef glyph in this filtered font stack of active fonts, or only use the first active font?
PS, has anyone looked into the other font-relative units & confirmed whether browsers are matching spec as far as the "first available font" being the first one with a space character available?
IIRC @florian had committed some tests to WPT checking for first available font with space.
I don’t understand why a .notdef glyph is considered to be an acceptable fallback. It it expected to be the same width as a zero? Isn’t it commonly a square shape instead? Mightn’t it also be zero width or just a single stroke wide?
If checking the font-family list is expensive, then how about just getting the system’s default serif or sanserif proportional font?
I don’t understand why a .notdef glyph is considered to be an acceptable fallback
Because all fonts are required to have one.
Isn’t it commonly a square shape instead?
No, it is typically a rectangle (and, I think, typically uses the default advance width)
It is recommended that the shape of the .notdef glyph be either an empty rectangle, a rectangle with a question mark inside of it, or a rectangle with an “X”. Creative shapes, like swirls or other symbols, may not be recognized by users as indicating that a glyph is missing from the font and is not being displayed at that location.
your wording doesn't acknowledge that there may be 2 or more active fonts (meaning loaded & being used in the document) applying for the element
Well spotted and yes, it doesn't. Specs referring to "the font used to render" need to be tightened up.
I have to agree with @bradkemper and @AmeliaBR here. There are plenty of cases where the first available font isn't the one used to render zero and there is another font in the fallback list which both does have it and is expected to be used to render alphanumerics. And having ch
not match that zero, but be something else random is not helpful to the author trying to size their content.
It's fine to restrict ch
from triggering a font download, but I think it's less fine to pick an unrelated and potentially very wrong value because the author happened to use a more restricted-subset font as the first available font, instead of their main text font (or instead of their Latin text font, in i18n contexts).
I tend to agree with @fantasai, however stepping back a bit, it seems to me that this unit is really only something you'd want to use if you can be sure that a given mono-spaced (including CJK) font is available, and it contains a zero glyph.
Using a random fallback font's zero when falling back from a monospaced scenario is of course an even worse idea than usual, given that monospacing is all about predictable dimensions.
The particular case I'm concerned about is something like this:
@font-face {
font-family: DoesNotSupportZero;
src: url(...);
unicode-range: a range that doesn't include the '0' character
}
@font-face {
font-family: ShouldNotBeDownloaded;
src: url(...);
}
<div style="
font-family: DoesNotSupportZero, ShouldNotBeDownloaded;
border-top: 1ch;
">
Some text that doesn't have the zero character in it
</div>
I'd be happy with any solution that allows browser to not download ShouldNotBeDownloaded
.
Right, Elika's suggestion would use ShouldNotBeDownloaded
's 0 character for the ch size if something else has caused that font to download already, but would otherwise just use the fallback size. It's stateful, but accurate when there's a font being meaningfully used.
What about a slightly different case from Myles' example:
@font-face {
font-family: CompositeFont;
src: url(letters.ttf);
unicode-range: U+20, U+41-5A, U+61-7A;
}
@font-face {
font-family: CompositeFont;
src: url(digits.ttf);
unicode-range: U+30-39;
}
<div style="
font-family: CompositeFont;
border-top: 1ch solid;
">
Some text that doesn't have the zero character in it
</div>
Does the use of the ch
unit here cause digits.ttf
to be downloaded? Should it?
We should consider "not downloading digits.ttf
" as a requirement for any solution here.
No, it should again only use the 0 glyph size if it's already available. It'll never trigger a download on its own.
So, how about:
The concern I have with the argument that the ch
unit should never trigger a font download (but may use a glyph size from a downloaded font if available) is that it seems to open the door to mysterious, stateful, action-at-a-distance scenarios.
Given the example in https://github.com/w3c/csswg-drafts/issues/3135#issuecomment-960094958, suppose there's another element on the page that uses the same font-family: CompositeFont
and does happen to contain a zero character; presumably that means ch
will be derived from digits.ttf
. But perhaps that element hasn't yet been reflowed (and hence loaded the digits.ttf
resource), e.g. because it is hidden, but then it gets exposed as a result of some subsequent change.
Or the user types a zero into a similarly-styled editable field elsewhere on the page -- does that cause everything that was sized in ch
units to suddenly shift?
The CSS Working Group just discussed ch and font downloads
.
See official minutes
Is there a summary of what came from the meeting discussion? (Given the length of the discussion multiplied by the number of people who will follow this thread, it seems that a summary could save a lot of reading and synthesis time. The alternative for those of us who read at about speaking speed is basically to sit through a simulation of the meeting.)
I think the summary was:
ch
units do cause font downloads). However, given that @litherum , who raised this issue, was not present, we decided to defer trying to resolve the issue for 2 weeks. (Otherwise we probably would have resolved.)ch
units trigger font download, if the font is downloaded, then ch
units get re-resolved if the newly-downloaded font is an earlier font. (This, in turn, means that the implementation complexity of triggering downloads is merely the triggering of downloads.)ch
/ex
/ic
/etc. units).ch
unit but would not otherwise be downloaded is extremely rare. (I also argued that a big piece of what makes it rare is the "would not otherwise be used" aspect, which means triggering the download earlier when ch
/etc. units are resolved might actually be a net benefit.)Thanks @dbaron. That's really helpful.
I've created a small testcase at https://jfkthame.github.io/test/ch.html that demonstrates the sort of issues that can occur with option (3). Try it in current Safari to see the problem.
(Note that neither Chrome nor Firefox handle it correctly either, although their bugs are a bit different. As far as I can see, Chrome never uses the correct ch
width, even when the relevant font is available; Firefox does try to use it, but fails to update things at the right time.)
I would argue that the correct rendering of this example is what Safari shows after a digit has been typed into the input field, but currently no browser gets this right on initial load. (Safari may get it right on subsequent page-loads, while the relevant font is cached; reload it in a new private-browsing window to see the problem again.)
The CSS Working Group just discussed ch units shouldn't cause font downloads
, and agreed to the following:
RESOLVED: ch units can cause a font download, no change to spec
I think the conclusion is really:
leave it to the editors as to whether any clarifying notes would be helpful.
Yes, need to go through your list looking for useful things to make clear in the spec.
In particular, this point would merit an example:
I think there was consensus that, whether or not ch units trigger font download, if the font is downloaded, then ch units get re-resolved if the newly-downloaded font is an earlier font. (This, in turn, means that the implementation complexity of triggering downloads is merely the triggering of downloads.)
Migrated from https://github.com/w3c/csswg-drafts/pull/3129
Right now, Values and Units says:
It’s pretty unfortunate that ch units can cause fonts to download.
WebKit doesn’t do this; it just uses the primary font, and if the primary font doesn’t support “0” then it uses that font’s .notdef glyph. No downloads necessary.
https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/platform/graphics/Font.cpp#L123
https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/css/CSSPrimitiveValue.cpp#L661
In this comment, @emilio says that Firefox does something similar.