Load fonts progressively
Problem
Right now, the Typekit font bundle significantly slows page-load times. In limited local testing, it adds >1 second to load time on a simulated "average" 3G connection. This number increases significantly on lower-quality simulated connections, leading to average load times >5 seconds on "regular 2G" simulations.
Since a significant number of users browse the web on their phones, we should do our best to load these fonts progressively, so that they do not block user interaction on the page.
Proposal
Use Filament Group's LoadCSS library to bring support for link rel="preload" to all browsers.
With lazy-loading established, we can use it in the future for other non-critical styles that we may write for the app.
Benefits & trade-offs
➕ Page load time will decrease; user will be able to read, interact with our content sooner
➖ Browser may re-paint if there's a significant delay in loading the typekit bundle
Thanks, @dengeist ! Sounds good.
I'm also wondering if as a multi-fold approach we can also upload/locally load the fonts as well and font-display: swap as well.
This crossed my mind as well! All current browsers but IE 11 support the font-display property (source: caniuse), so we would have pretty good coverage if we moved to local font files. Additionally, hosting the fonts ourselves would cut out any reliance on TypeKit's servers. We might even get a bit of a site performance boost since we'd be minimizing requests to other domains.
Lazy-loading would still come in handy for users on older browsers that do not support font-display!
Perfect! Would you be able to make those adjustments if I got you all the woffs? I haven't interacted with Typekit in a moment, but I believe that's all possible. Otherwise I will figure something out as a substitute.
Also when you say lazy-loading here do you mean preloading? (Or am I confuse?)
I would be able to implement this if you got all the raw .woff files, yeah! If you can't, using rel="preload" and ensuring support for it should be a serviceable alternative!
(yes, by "lazy-loading", I do mean "preloading" here. preloading is lazy-loading in the context of CSS files.)
Bad news is that Adobe Typekit does not allow download of .woff files. I can open up a cost to purchase directly from the foundry using funds from the Open Collective, but that will take time. In the meantime, do you have bandwidth to open a PR for what we discussed? (Apologies for the back and forth)
Are you set on the current font? There are some great, open-source variable fonts out there that come with woff files. I've got some experience splitting up variable fonts to be speedy - I use Recursive on my personal site. It has a ton of variability.
https://www.recursive.design/
While I love the spirit of Recursive, I'm not sure it encapsulates the vintage/brutish aesthetic I'm hoping to maintain.
Generally I'd be open to open-source fonts (heh) but I'd like that to be part of a broader examination of the full identity of the site (including logo/logomark/colours), which I'm in the process of exploring with a designer.
With that said for now, I'd like to proceed with the preload strategy @dengeist as we explore more comprehensive, branded solutions in the future.
Gotcha, that definitely makes sense! Happy to help out however I can, regardless!
Awesome! Thanks! Would you like to open a pull request per what @dengeist itemised above?
@tatianamac, @wuz:
I was mistaken. I would like to propose that we close this issue as wontfix.
I was network-testing some unrelated work, and realized that the way Chrome labels its network-throttling settings is misleading: its "Regular 3G" profile is somehow several orders of magnitude slower than Firefox's "Regular 2G." I could not find concrete bandwidth settings for Chrome's default network profiles, but I could find Firefox's profiles.
I made a custom profile on Chrome based on Firefox's "Regular 2G", to ensure parity, then tested the current live SelfDefined site. On this setting, both browsers hit the DOMContentLoaded stage at ~1.2s and full Load at ~2.2s. This, I think, is an acceptable speed for a 2G environment. Performing the same test with rel="preload" and polyfills in place, load time is actually worse, averaging ~5s for full load.
I'm not sure why these numbers are so different from my original report. It could be that loading typekit as a link really helped us out, since @import blocks the rendering thread and link tags do not. I did not test speeds again after making that change!
All this to say that if everyone here thinks the current speeds are acceptable, we can leave fonts alone until such a time as we can utilize display=swap. I apologize for taking up folks' time with my mistake.
All this to say that if everyone here thinks the current speeds are acceptable, we can leave fonts alone until such a time as we can utilize display=swap.
The good news is: Adobe is probably working on bringing font-display: swap to Adobe Fonts. The bad news: There is no update since January.
See: https://community.adobe.com/t5/adobe-fonts/possible-to-set-font-display-swap/m-p/10730659?page=1#
Edit: Asked on Twitter. No ETA. https://twitter.com/AdobeFonts/status/1245744051825127424
@dengeist @ovlb Thanks for looking into this so intently!
I went ahead and purchased the fonts for this. Attached is the zip file of all the fonts .woff and .woff2 files. That way, we can avoid TypeKit altogether.
Why didn’t I get a mail that something happened here? Can I grab this issue and implement the fonts locally?
There might be an issue with copyright though. I think the MyFonts terms forbid to host the files in a public repo.
What I do with my personal sites that use commercial fonts: put them in a separate, private repo, add this to Netlify as static.domain.com and use this URL in the @font-face declaration.
@ovlb Yes, you can grab the issue. 💙 Is it possible to just .gitignore the font-files themselves so that they're hosted but not published on the repo?
@tatianamac From my understanding of the .gitignore they will not leave my computer once I add them there. And as as such also not end up on Netlify
@ovlb keep in mind that, however we choose to approach this problem, using @font-face to load fonts is a render-blocking operation, where assets in <link /> tags aren't. We'd be back to the perf problem that inspired this change
@tatianamac I think I found a solution for the font hosting problem by staring at the Internet long enough. Netlify recently introduced build plugins and there is one to encrypt files, which Netlify can decrypt. I will give it a whirl :) https://github.com/sw-yx/netlify-plugin-encrypted-files
Can't wait!
(Also I hope you're able to take care of yourself during these weird times. 💙)
@tatianamac I gave it a try with a demo project and it works fine. But I think it isn’t the solution we want. As the fonts are hosted encrypted in the repo, we would have to hand out the secret key to everyone working on the project, or they will see no web fonts. If we do this, we are back at the issue that distributing the font files is illegal.
My proposal for hosting them is to create a private repo (maybe selfdefined/static in a selfdefined GitHub org?) to which only people directly working with these files have access. As GitHub made private repos free for orgs, this isn’t a cost factor anymore.
Once done we can reference the files in our font-face declaration by using something like url('https://static.selfdefined.app/fonts/xyz.woff2). This way all contributors can enjoy the web fonts, and we don’t have to worry about MyFonts going after you.
@ovlb ! Thanks for looking into this.
I feel like as I'm in the midst of a branding project, I this forces a compelling reason to switch to fonts with a licence more amenable to our needs.
For now, I think your solution makes sense! If we'd like to migrate to a private repo/org, it also might be good to consider migrating to a selfdefined specific GitHub org? I'm curious if you've ever done this sort of a migration. Also I can open up a new ticket so we can have this discussion there and make that a block for this issue.
@tatianamac Discussing this in a separate ticket makes sense. :)
Repinging this thread now that we have selfdefined on its own repo