kenjibaheux / css-font-rendering Goto Github PK
View Code? Open in Web Editor NEWA proposal for CSS to let web developers control the behavior of font rendering
License: Apache License 2.0
A proposal for CSS to let web developers control the behavior of font rendering
License: Apache License 2.0
The CSS font-rendering proposal is an attempt to explain the bit of magic that goes on around web font rendering in browsers:
Browser timeout fallback swap Chrome 35+ 3 seconds yes yes Opera 3 seconds yes yes Firefox 3 seconds yes yes Internet Explorer 0 seconds yes yes Safari N/A N/A N/A
- Chrome and Firefox have a 3 second timeout after which the text is shown with the fallback font. Eventually, a swap occurs: the text is re-rendered with the intended font once it becomes available.
- Internet Explorer has a 0 second timeout which results in immediate text rendering: if the requested font is not yet available, fallback is used, and text is rerendered later once the requested font becomes available.
- Safari has no timeout behavior (or at least nothing beyond a baseline network timeout of 60(?) seconds)
A discussion around the adequacy of the name "font-rendering" lead to the realization that we have a hard time identifying/naming the underlying system involved here. This suggests that CSS font-rendering might not be ambitious enough or might not explain the actual magic but a specific manifestation of it. I think this is worth investigating in parallel with making progress on the proposal and adjust as we learn more.
Relation to Houdini
to/ @shans @bfgeek
To start, we should find out if Houdini (bedrock for CSS) would impact this proposal, otherwise we run the risk of turning CSS font-rendering into The Magic Trick That Fooled Houdini ಠ_ಠ
Is the CSS font-rendering use case (a specific manifestation of the magic that goes into holding paint) in scope for Houdini? Anything started in this area?
CSS font-rendering example
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url(//example.com/opensans/normal400.woff2) format('woff2');
/*
set default font-rendering strategy
- don't block text rendering on this font
- abandon progressive rendering after 2s
*/
font-rendering: swap 2s;
}
body { font-family: Open Sans; }
#header {
/* block rendering until the desired font is available (due to branding requirements).
if branding font is not ready within 500ms, use fallback */
font-rendering: block 500ms;
}
#headline {
/* immediately render the headlines, if the desired font is available, great...
and if not, use fallback and don't rerender to minimize reflow */
font-rendering: optional;
}
#main-content {
/* don't hold rendering, but rerender with the desired font once available */
/* give up on progressive strategy after 150ms due to UX+perf requirements */
font-rendering: swap 150ms;
}
#footer {
/* inherits font-rendering: swap */
}
infinite
is a keyword used by (at least) transition & animations. It's useful as a timeout here.
font-rendering: mandatory infinite;
is the equivalent of what Safari does today.
font-timeout
Pros:
Cons:
This proposal is now available in fleshed-out spec form at https://tabatkins.github.io/specs/css-font-display/. Let’s remove the contents of README.md
and just point there?
.whatever {
font-rendering: mandatory 60s;
}
.whatever .foo {
font-family: foo;
}
.whatever .bar {
font-family: bar;
}
.whatever .blah {
font-family: sans-serif;
}
Assuming:
foo
& bar
are defined in @font-face
rulesfoo
takes 5 seconds to loadbar
takes 10 seconds to loadfont-rendering
in .whatever
has precedence over rules in @font-face
)When does the text in .foo
render? As in, does it also wait for bar
as font-rendering
is set on a parent that uses both fonts? What about the text in .blah
?
If "mandatory" is renamed something more indicative of behaviour (#6), I think we need a true mandatory for icon fonts. As in:
"If this font fails to load, it's better to display nothing because a fallback would look more broken"
If mandatory uses a fallback, mandatory doesn't feel like the right word.
Maybe "wait"?
(sorry to be so bikesheddy)
I know old browsers will just ignore something like:
font-display: swap;
in the CSS, but there are cases where feature detection is useful.
For example I want to test the feature and use Bram Stein's fontfaceobserver for browsers which do not support it.
Such as
if(browsersupportsfontdisplay) { //do nothing } else { // run fontfaceobserver. }
So is there a feature detection code?
…and swap 0s
?
As pointed by Jonathan Kew, icon fonts that maps to character are doing it wrong.
The explainer shouldn't convey the idea that this is a reasonable situation.
As a developer who has spent far too much time working around browsers’ default behavior of hiding text while fonts load, and as a user who regularly experiences the problem, I love the sound of this proposal. It's simple and definitely preferable to the JavaScript alternatives.
However, I would propose that swap
is a more expected and consistent default to recommend for browsers that support the font-rendering
property, as opposed to auto
, which seems to endorse the status quo of hiding page content while fonts load (for 3 seconds or sometimes more. Except in IE, which gets this one right).
Hiding text from the user, even for a short time like 3 seconds, is an odd behavior to encourage when we're actively advocating that sites should render in less than half that time. There are probably cases where a custom typeface is so important that the content should not be available to the user without it, but that seems like the exception.
By defaulting to swap
, developers would need to opt-in to text-hiding in the cases where it is necessary, knowing that otherwise fonts will load in a non-render-blocking manner.
Thanks for considering!
We filmed a little show this morning where I spoke about this proposal. I had a hard time working out how I was going to explain what the number part of the proposal, I think that's because it's a separate thing.
How about separating it out?
@font-face {
/* ... */
font-rendering-wait-timeout: [duration];
font-rendering-swap-timeout: [duration];
/* or for short… */
font-rendering: [wait duration]/[swap-duration];
/* or for shorter… */
font-rendering: [keyword];
/* The current Firefox/Chrome/Opera behaviour: */
font-rendering: 3s/infinite;
font-rendering: timeout;
/* The current IE behaviour: */
font-rendering: 0s/infinite;
font-rendering: immediate;
/* The current Safari behaviour: */
font-rendering: infinite;
font-rendering: wait;
/* The Guardian/Smashing Mag approach */
font-rendering: 0s/0s;
font-rendering: race;
}
@tabatkins is 'infinite' and num/num appropriate here?
font-desirability: [optional | mandatory]
- optional means that the user agent should not swap with the intended font as it becomes available
- mandatory means that the user agent should swap with the intended font as it becomes available
These values don't cover all the cases:
Last policy is the current browser default in Chrome/FF/Safari. Instead of "desirability", perhaps "font-rendering" with:
(*) unless timeout is reached, at which point browser will render with fallback
From http://lists.w3.org/Archives/Public/www-style/2014Oct/0524.html
"In other words, when a "swap" or "optional" font doesn't come in before the timeout, it gets an "inactive" bool set on it, which makes the current page treat it as not usable. [...](This bit of extra state should be exposed on the FontFace object, so you can always turn the font on manually if you want, via script.)"
A key challenge in this spec space is that its poking up against an unspecified, undocumented, generally unkwown-by-anyone problem in the web: when does a browser actually decide to render its first frame? What pieces go into that choice?
I think it'd be great for someone to write an explainer doc that pulls together all the heursitics and algorithms that browsers [or failing that, at least chrome] use to determine first painting. I think by explaining the space, and making the space visible, it would help elide some of the concerns around magic...
Should this be generalized?
…or an invalid response before the timeout?
I assume it just falls back?
Here by "readily available" we mean that no network request (e.g. fetching a copy, revalidating a stale copy) is needed in order to use the font.
Intuitively, this should map to font-timeout: 0ms
The problem:
Even for fonts that are in the HTTP cache and still fresh, making it available in 0ms is impossible (or tricky).
Approaches
On the other hand, it would hide the local latency (e.g. hard disk latency).
Given that what matters is the time it took to be able to use the font, approach #2 is more appealing.
One of the fringe cases that this property does not solve is that it does not solve the use case of changing the content
property in CSS from a fallback unicode glyph to a new content
glyph after the icon font has loading. It requires you to map your icons directly to the code point of the fallback character, which isn’t always easy since most icon fonts are supplied as part of a icon font package.
For example, while the font is loading, show \2261
hamburger menu (ok, the triple bar math symbol, but whatever). Then, when the font has loaded, show the actual font-icon supplied hamburger menu (probably assigned to something other than \2261
, likely a decision not made by you).
I wrote an article about these icon font use cases awhile back:
http://www.filamentgroup.com/lab/bulletproof_icon_fonts.html
I consider this to be a edge case for sure and I hesitate to even post it in here for a couple of reasons:
So, here is the ticket for posterity (feel free to close). I don’t want this edge case to hold anything up because this property is sorely needed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.