I have been doing a lot of work on making Elm assets really tiny. As part of some exploratory research I did ages ago, I read this document on font loading. It is a super helpful resource, but I was confused by all the different terms: FOIT, FOUT, FOFT, etc. It reminded me of the old "how do you center things?" blog posts from before flexbox. So my instinct was that probably lots of folks are confused about how to do it well, and maybe there is a better way!
So brainstormed some some ideas to:
- Save even more bits.
- Have an ideal visual experience.
- Be really easy to set up.
I did this brainstorm maybe six months ago, so at this point, it is very clear that I cannot do it myself! So here they are, and I hope they inspire someone to get us to a better font world!
What if you could specify a dummy version of fonts that was a much smaller file?
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url(fonts/roboto.woff2);
src-placeholder: url(fonts/roboto-tiny.woff2);
}
Notice the additional src-placeholder
descriptor. The idea is that fonts/roboto-tiny.woff2
would be a tiny subset of the full font. Maybe it only has width, kerning, and ligature information, but no actual curves for the letters? Or maybe it only has the Latin1 characters? Or maybe some other trick. The point is that it'd be small enough to load quickly and let folks see things properly laid out.
But if you cut too much from roboto-tiny.woff2
then it may cause things to move around when the real thing arrives.
What if you could specify a placeholder that (1) allows you to show text really soon and (2) does not cause any reflows or text movement?
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
placeholder: url(fonts/roboto.widths) local(arial);
src: url(fonts/roboto.woff2);
}
Notice the additional placeholder
descriptor. The idea is that:
fonts/roboto.widths
would only have the width, kerning, and ligature information.local(arial)
would specify system fonts similar to what you will ultimately load.
So the browser now renders things with arial characters, but it does the layout based on roboto.widths
instead. So things will look a bit goofy, but when the real font loads, nothing will move. The letters will just be better.
Note 1: I am assuming you would put
fonts/roboto.widths
in a<link preload>
tag in the header. Or use data URLs. Whatever path you take, the main idea is that this file is the smallest possible thing that allows proper layout.Note 2: Maybe the
.widths
file can be a.woff2
instead? In case someone wants to put Latin1 in there as well as the widths? I do not know enough about the file format to know the tradeoffs here.
But what if you have many @font-face
rules, and you only want the text to change once, in one big batch?
What if you could synchronize the display of src
typefaces?
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
placeholder: url(fonts/roboto.widths) local(arial);
src: url(fonts/roboto.woff2) sync(id);
}
Notice that the src
descriptor now has lits sync(id)
.
Say you have four @font-face
rules that all specify sync(my-app-body)
. The idea is that they will all stay on placeholder
until all four my-app-body
fonts are loaded.
Note: I do not know if people would want this in practice. Perhaps it would need to be more nuanced and allow timeouts as well. Like
sync(id, 1000)
so you have a 1000 millisecond buffer where it waits for any other font with the sameid
. I do not know. My point is only that there seems to be a path to adding reasonable synchronization behavior if it is required.
It seems like idea #2 would make font loading a lot simpler for people. Just add a placeholder
, and be sure to put the placeholder in a <link preload>
.
It would be pretty easy to make tools that transform roboto.woff2
into roboto.widths
files, so supporting tools could help folks get on the right path as well. E.g. if you are into servers that set everything up for you, it could do it all automatically.
Finally, I would not personally put idea #3 in a first draft of anything. It is just to show that there exists a way to address that concern if necessary.
What if the font files first N bytes contained the layout data you seek instead of a place holder file? As soon as the browser has received those bytes it layouts. One file with a progressive streaming protocol.
Remember progressive jpegs?