-
Notifications
You must be signed in to change notification settings - Fork 711
[css-fonts] Address missing aspect of Progressive Enhancement in font loading #450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
It is. Welcome down the rabbit hole. The problem you describe sounds relevant, but as always, the devils' in the details. Leaving aside what mechanism we use to solve it for now, what would you expect/want to happen when the web font does load, but it only support some of the characters used in the page, and the fallback font is used for these. Do you want the various font related settings you've prepared for the fallback to still apply to the characters displayed using it, or is it better to discard them as long as the web font has loaded? |
Thanks @frivoal ! I think that it's sufficient to apply the style rules across the board. We can't address incomplete fonts now, so no need to complicate this issue by trying to address that as well. I think that's up to the designer to pick better fonts! I think it's better to discard the fallback styles if we know that web fonts have loaded. |
Currently, the CSS Font Loading API associates a "loading" boolean state with an @font-face block. It sounds like you're asking for some way to say in CSS: "Apply some style while a specific @font-face block is loading, and remove the style when it stops loading." (Where "apply some style" conceptually means the same thing as an @media query) Is this accurate? |
@litherum Exactly! Just would love to be able to reach it almost like an attribute selector or pseudo-selector rather than requiring JS. Between that and |
It sounds like this is a request to move logic from libraries like TypeKit down into the browser. Do you think you could describe the specific logic TypeKit uses by adding/remove classes when fonts load? How does TypeKit know which elements to add/remove classes to? |
The way it's done with the Web Font Loader (used by Typekit and Google Web Fonts, and Monotype does the same thing with Fonts.com, but with different classes) is something like this:
Additionally both methods (Web Font Loader and Fonts.com's version) supply an 'inactive' class, which is added with the 'loading' classes, and is meant to stay there in the event that the web fonts don't ever fully load. If they do, it is removed as well. While it would be great to have access to a 'loading' state for each font, the (perhaps) more helpful (and easier to set things across the board) is that general 'loading/loaded' state (all or none essentially). |
I should have clarified that this is generally done by inserting a class like 'wf-loading' on the HTML element during the loading process, and once the web fonts have loaded, removing the 'wf-loading' class and replacing it with 'wf-loaded' |
https://github.com/bramstein/fontfaceobserver has the same sort of logic. |
TypeKit / Fonts.com generate (somewhat mangled) class names from the name of each loading font. Browsers should not generate class names the same way. However, many authors don't care about each individual font loads, and simply want a big switch saying "everything is done" or "something is not done." These are done with well-known (short) class names. |
@jpamental: How does a web author know which CSS values to apply during loading? During font loading, an installed font must be selected, but every platform on the web has a different set of fonts installed (indeed, even the same font may have different metrics on different platforms). If the goal is to make the installed font better match the web font, how does a web author do this when she has no idea which installed font is used or what its metrics are? |
If the goal is to allow arbitrary properties to apply to elements during a font load, we have to be careful of what happens if these arbitrary properties trigger yet another font load. For example, we need to consider the case where, during a font download, an element is styled with "font-family," thereby causing another download. This could be mitigated by either disallowing properties consulted during font selection, or, by browsers simply detecting the above conditions and not following the chain. (Or the browsers could faithfully honor the chain, but I don't think anybody wants that.) |
There's no way to be 100% perfect, but in general the fallback stack should be fairly well supported, and you'd generally want to optimize for the most widely available (or most likely 'first alternate': Arial or Helvetica on most desktops, Droid on Android - whichever comprises the largest segment of your audience). So I generally define a set of fallbacks that will cover the basics and optimize for the first one in the stack. It's not perfect, but far better than doing nothing in terms of getting content on screen and minimizing reflow when the fonts load. If this is tied in some way to the Font Loading API, then the behavior could simply follow however that is working: if the boolean flag is in the 'loading' state for all @font-face blocks then 'loaded=false'; if they're all 'loaded' then 'loaded=true' (I'm imagining this as an attribute selector, but hopefully you get what I mean in a more general sense) |
Wouldn't this issue be better solved on a higher level, introducing a syntax for specifying font parameters like discussed in #126 and specifically in this post, which Tab Atkins thought was a good idea? For example: @font-face { /* load fonts */ }
@fallback-font-sequence --name {
/* ^ should probably be called something simpler, like `@font-stack` */
Alegreya,
Georgia { font-size: 0.975em; },
serif
}
p {
font-family: Alegreya, Georgia, serif; /* fallback for old browsers */
font-family: var(--name); /* call to the new @fallback-font-sequence rule */
} |
@aaaxx That would definitely be a better solution, because it would also address the ability to specify fallback tweaks for individual fallback fonts (i.e. 'these styles for Arial, these other styles for Droid Sans', etc) Then if it's wrapped in |
I don't see anywhere else where font-stack is discussed. Is there another discussion you could direct me to? The model of associating CSS properties with items in the font fallback list doesn't hold, because CSS properties are applied to elements, but each item in the font fallback list is applied to individual glyphs, not elements. So the associated issues would be around what to do if most of the text in an element is rendered with one item in the font-fallback list, but some of it is rendered with another. |
@litherum I was following the thread @aaaxx mentioned here: #126 (comment) but I see what you're getting at about how the fallbacks are applied, and it certainly shouldn't be applied to individual glyphs like you described. I like the simplicity of the 'pseudo-code' that @aaaxx laid out above but see that it could be really tricky in how it's applied. |
One possible idea is something like the following: @font-face {
font-family: "MyFont";
src: url("MyFont.ttf");
@loading {
#myfancydiv {
letter-spacing: -3px;
}
}
} This approach would piggyback on the CSS Font Loading API's notion of an @font-face block being "loading" or "loaded." The style rules would only apply if the block is loading. The style rules inside the @Loading block behave according to the regular priority rules (and, since order of rules within the document matters, the rules behave as if they are in the position of the @font-face block). Because selectors are present inside the @Loading block, the browser knows which elements to modify. The downside is that this requires nested at-rules, which I'm not sure have ever been done before. For browsers which don't support the nested at-rules, they would likely treat this as a parse error, and either 1) ignore the @Loading block (which is the most desirable behavior) or 2) ignore the @font-face block, which could be worked around by putting a duplicate @font-face block just before this one (but omitting the @Loading block from the earlier duplicate). Maybe there is a better solution to this problem; this is just what I've come up with off the top of my head. |
@litherum that seems to tie nicely to the existing Font Loading API and also a good way to set fallback customization per font, but doesn't give the opportunity to customize per fall-back (as outlined by @aaaxx above). I wonder if there might be a way to combine those approaches. I recognize that this is a greater length than many will go, but if we're going to propose a change we may as well see how thorough we can be! What I like about this approach is that it puts this control right in the same place where A downside to this is that it can only be utilized if you have control over the |
Background info to motivate this issue: it appears that every major font loading library allows for styling text differently during font downloads. |
Sorry, I should have called it As for the individual-glyphs issue, I think you're looking at it the wrong way. The whole point of this proposed property, as discussed in the other thread, is to visually harmonize the intended font and its fallbacks so you get the desired and consistent look, either when the main font is unavailable or when you get mixed fonts in the same element (e.g. multiple scripts, special characters, emoji). Prevention of "Flash of Unstyled Text" then is something you get for free. |
@jpamental The other thread mentions weight and size as being valuable to change depending on which item in the font fallback list is used. Are there other properties you think would be valuable to change? |
I'd generally be thinking about: I'm sure others might crop up but that would give you a ton of control. |
Nested at-rules are a thing, they exist in the Paged Media spec: https://www.w3.org/TR/css3-page/#margin-boxes |
Closing as duplicate of #126. |
Not entirely sure if this is the right place to post, but @litherum suggested this might be a place to start.
The Issue
Loading web fonts creates an uneven experience, either in waiting for fonts to load and displaying fallbacks that don't exactly match (width/height/etc) causing text reflow when the web fonts finally load. Using
font-display
helps even out loading behavior, but that only allows us to get fallback fonts in use faster; it doesn't let us style them. That's the key to mitigating FOUT: style the fallback text usingletter-spacing
font-size
line-height
etc so that the difference when the web fonts finally load is minimized. Currently we have to rely upon JS to switch classes, but if there were some way in CSS to target the state when web fonts haven't loaded we could remove the reliance upon JS and be more fully embracing the concept of Progressive Enhancement (especially since support of JS and@font-face
are not necessarily tied).For the most thorough PE approach, we should strive for:
wf-inactive
class)wf-inactive
class goes away)font-display
when supported helps show the content in the fallback fonts faster, but we’re still stuck relying on JS to either insert or remove the CSS class that would control whether or not the web fonts would be referenced and how we can target the CSS styling based on web fonts being present or not at the time.Example of using the loading class to style fallbacks:
The text was updated successfully, but these errors were encountered: