Investigate if changing the font loading mechanism is better for users
See original GitHub issueWe currently use font-display: fallback
to load our fonts:
This is somewhere in between block and swap. The text is invisible for a short period of time (100ms). Then if the custom font hasn’t downloaded, the text is shown in a fallback font (for about 3s), then swapped after the custom font loads.
Matt’s new font work he has suggested that we change fallback
to swap
, which is also recommended by performance community members, however when testing in our development environment we have noticed that when the page is switching fonts text “jumps” more than before.
Font-display: swap
After some research I have changed the
font-display
CSS property fromfallback
toswap
. To quote from Addy Osmani:…self-hosted Web Fonts have a zero second block period and an infinite swap period. Browsers would draw text immediately with a fallback used if the font face isn’t loaded, but swap as soon as it does load.
More discussion about this change can be seen here, here and here.
We should determine what the difference is to users in the following scenarios, in order of priority:
- Users on unreliable slow network connections, with a production optimised server.
- Users on a reliable fast network connection, with a production optimised server.
Reference: https://font-display.glitch.me/
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:14 (14 by maintainers)
Top GitHub Comments
Note
This comment overrides any comments / considerations made in PR 1607. The testing method I used in that PR was flawed so the end results weren’t accurate. The method used was to run a very small number of test runs (usually 9), then base results of the median result. The limited number of runs doesn’t give an accurate representation of real-world performance, and can easily introduce large variations.
The updated testing method relies on us using our own WebPageTest instance which gives us the ability to run a lot more tests than the public instance (201 vs 9). This should give us a much more accurate representation.
Hypothesis
Changing
font-display: fallback
tofont-display: swap
will improve perceived performance for users.Reasons for Hypothesis
According to the specification:
Now although these two settings look very similar in terms of the specification, practical implementation by browsers is different:
swap
there is a 0s blocking period, meaning the fallback font is displayed immediately on first paint. So a user can start reading the content as soon as the page renders. The browser then gets unlimited time to swap out the fallback font for the web font once loaded.fallback
the browser will wait ~100ms before using the fallback font (Arial), in that time the browser will render invisible placeholder text. This 100ms delay to view any content will have a small, but noticeable impact on perceived performance. The browser is given 3 seconds to replace the fallback font with the web font once loaded, else the fallback font will be used for the lifetime of the page.Others have suggested changing
font-display
fromfallback
toswap
too. To quote from Addy Osmani:More discussion about this can be seen here, here and here.
Testing
I will be running 201 test runs over each of 4 GOV.UK pages on production:
The tests will be conducted at 3 connection speeds on Chrome:
This should give a fairly representative idea of user experience, since we have a high percentage of users on a 3G or greater effective connection type.
Results
Homepage - Cable
Test link (GDS internal only access)
Observations
swap
: full page painted with the fallback font visible immediately at 500ms. Web font loaded at 900ms.fallback
: page started paint at 600ms, invisible text for 100ms the fallback font used. Web font loaded at 900ms.Winner:
swap
Homepage - 3G
Test link (GDS internal only access)
swap
: page rendered complete with fallback font at 2.9 seconds. Web font loaded at 4.4 seconds.fallback
: page rendered complete with fallback font at 2.8 seconds. Web font loaded at 4.4 seconds.Winner:
fallback
Homepage - 3G Slow
Test link (GDS internal only access)
swap
: page rendered complete with fallback text at 5.1 seconds. Web font loaded at 9.2 seconds.fallback
: page rendered complete with fallback text at 5.2 seconds. Web font wasn’t rendered as it passed the 3 second cut-off point.Winner:
swap
Guidance page - Cable
Test link (GDS internal only access)
swap
: full page painted with the fallback font visible immediately at 600ms. Web font loaded at 1100ms.fallback
: page started paint at 600ms, invisible text for 100ms the fallback font used. Web font loaded at 1100ms.Winner:
swap
Guidance page - 3G
Test link (GDS internal only access)
swap
: complete page rendered with fallback text at 2.5 seconds. Web font loaded at 4.2 seconds.fallback
: page rendered with invisible text at 2.5 seconds. 100ms later the fallback text was rendered. Web font loaded at 4.1 seconds.Winner:
swap
Guidance page - 3G Slow
Test link (GDS internal only access)
swap
: page rendered complete with fallback font at 4.3 seconds. Web font loaded at 9.1 seconds.fallback
: page rendered with invisible text at 4.2 seconds. 100ms later fallback text rendered. Web font wasn’t rendered as it passed the 3 second cut-off point.Winner:
fallback
Start page - Cable
Test link (GDS internal only access)
swap
: at 600ms page renders with fallback text immediately visible. Web font finished loading at 800ms.fallback
: initial page renders at 400ms with invisible text. At 500ms fallback test is rendered. Web font finished loading at 700ms.Winner:
fallback
Start page - 3G
Test link (GDS internal only access)
swap
: page rendered with fallback text immediately seen at 2.8 seconds. Web font loaded at 4.2 seconds.fallback
: page rendered with invisible text at 2.8 seconds. 100ms later the fallback font was rendered. Web font loaded at 4.2 seconds.Winner:
swap
Start page - 3G Slow
Test link (GDS internal only access)
swap
: page rendered with fallback font at 4.1 seconds. Web font rendered at 8.5 seconds.fallback
: page rendered with invisible text at 5.4s. 100ms later fallback text is displayed. Web font wasn’t rendered as it passed the 3 second cut-off point.Winner:
swap
Speech page - Cable
Test link (GDS internal only access)
swap
: page renders with fallback text immediately visible at 500ms. Web font loads at 800ms.fallback
: initial page renders with invisible text at 500ms. Fallback text visible at 600ms. Web font loads at 800ms.Winner:
swap
Speech page - 3G
Test link (GDS internal only access)
swap
: page rendered with fallback text immediately seen at 2.5 seconds. Web font loaded at 4.1 seconds.fallback
: page rendered with invisible text at 2.5 seconds. 100ms later the fallback font was rendered. Web font loaded at 4.1 seconds.Winner:
swap
Speech page - 3G Slow
Test link (GDS internal only access)
swap
: page rendered with fallback text immediately at 3.9 seconds. Web font loads at 9.2 seconds.fallback
: page rendered with invisible text at 3.9 seconds. 100ms later the fallback text was rendered. Web font wasn’t rendered as it passed the 3 second cut-off point.Winner:
swap
Summary
The table below gives a summary of the results above. Which
font-display
property results in the best perceived performance:swap
fallback
swap
swap
swap
fallback
fallback
swap
swap
swap
swap
swap
Chrome performed as per the spec:
swap
: shows a 0s blocking period and shows fallback text immediately. The browser then waits as much time as needed to load the web fonts before swapping them out (as seen in the 3G Slow tests).fallback
: in almost all cases the initial page is rendered with invisible text, then 100ms later the text is replaced with the fallback text. We can see the 3 second cut-off point in action in the 3G Slow tests, where the web font is downloaded by never actually rendered.Recommendation: change the
font-display
value fromfallback
toswap
. Our users will be able to see the fallback font (Arial) immediately, without having to see FOIT for 100ms as seen withfallback
.This shouldn’t hugely effect other areas since users will already be seeing the fallback font before the web font has loaded, only after 100ms rather than immediately. This also gives slow connections the chance to render the web font. Since they are already downloading it, they may as well see it at some point. If the last point is a point of contention then we should consider using
font-display: optional
. This shows exactly the same 100ms of invisible text as seen withfallback
, only the browser has the option to choose not to download the font at all. It’s worth noting that this value is hardly used across the web, so I question its effectiveness.In regards to HTTP/1.1 vs HTTP/2, this shouldn’t really come into the decision. The use of HTTP/2 will make it more likely that the web font is delivered in a decent time, but it won’t change the upfront rendering as controlled by
swap
vsfallback
.I’ve just had an article published in this years Web Performance Calendar all about this issue.
Data shows we could have users on incredibly slow connections in the UK, for which the font loading could take large amount of time. The shift between fallback & webfont is quite significant (especially for v1) and a setting of
swap
will allow the browser to replace the fallback font with the webfont at any point in the future after the page has ‘settled’. The shift that occurs can be seen visually and detected in DevTools.fallback
allows for a maximum of 3 seconds, before the webfont isn’t swapped.To quote from the article:
So I’d say we stick with
font-display: fallback
and close this issue. Can be opened again in the future if we have significant data to prove otherwise.