I host Google fonts locally not only to load them faster but also to take advantage of font loading strategies which goes directly to the heart of creating the ultimate user experience.
Hosting Google fonts locally to boost speed is one thing. Knowing how to load them with an effective strategy that strikes a perfect balance between performance and user perception is another.
Unfortunately, browsers are not quite where we'd like them to be in terms how they handle custom fonts which leaves us to our own devices when deciding on a suitable font loading strategy.
While some of these strategies are still nowhere near perfect, one thing remains certain. You'll need to host Google fonts locally if you want to retain maximum control.
Understanding Font Loading Strategies
Without intervention font loading is primarily handled by the browser.
If your preferred font fails to load due to a slow download, the browser will mitigate this by loading a fallback (system) font.
A system font is a font used by your operating system to display text. Common system fonts include Arial, Times New Roman and Georgia.
A fallback font is basically a preferred system font that you specify.
Here is a table illustrating the behavior adopted by some of the popular browsers.
- Chrome, Opera and Firefox timeout after 3 seconds. At this point, text will be displayed using the fallback font. As soon as the primary font is available, the text will be re-rendered. Herein lies the problem of FOUT and reflows. Text rendered using the fallback font is referred to as a flash of unformatted text (FOUT). A reflow occurs when the primary font becomes available and the text is re-rendered. Not sure about you but I've experienced this often and found it to be disruptive.
- Internet Explorer renders text immediately due to a zero second timeout. A fallback font is used if the primary font is unavailable and re-rendering takes place once the primary font is ready. The benefit of FOUT is that, at very least, the user is faced with text immediately. However, this comes at the expense of a perfect user experience.
- Safari has no timeout leaving users without text until such time that the primary font is downloaded and ready for use.
Prior to the 3 second timeout with Chrome, Opera and Firefox (or no timeout in the case with Safari), a slow connection or a delay in the Google font download will likely leave users with a flash of invisible text (FOIT).
To add fuel to the fire, our font loading strategy is limited.
The relatively new
font-display: block | swap | fallback | optional | auto descriptor allows you to control how your font renders before it is fully loaded but is by no means a perfect solution.
- block - FOIT + infinite swap period. The invisible fallback text is replaced as soon as the designated font is available.
- swap - FOUT + infinite swap period. The fallback font is replaced as soon as the primary font is ready for us.
- fallback - Almost imperceptible block period (<= 100ms) + small swap period (FOUT + swap).
- optional - Almost imperceptible block period (<= 100ms) + no swap. Great for best user experience where content is preferential to aesthetics.
- auto - based on user agent (browser) strategy.
NOTE: Prior to May 2019 the use of the font-display descriptor could only be achieved when hosting Google fonts locally due to the CSS being hosted on your own server.
OK, with a very basic understanding of font loading, let's forge on.
What To Do When You Have Text Over Images
What I've learned from experience is that FOIT is not always FOIT.
Consider a scenario where a site uses white text over a dark image.
Where the internet connection is fast the text may load concurrently with, or just before, the image. No problems here.
But if the connection happens to slow down temporarily or even sometimes on first load of a site in a browser with a clean cache and/or where one's PC is also busy with some background process/es, it can appear as if the header and navigation loads before the text and image, leaving a mostly blank screen.
That said, the text may, in fact have loaded but in the absence of an image the white text is invisible on a white background. So what one may think is FOIT, may in fact have been white text on a white background.
The solution is to use a solid color overlay that will allow text to show while waiting for the image to load. The image may load after milliseconds but it's still preferable to an almost blank screen. The other option is to change the text color.
Why Poor Hosting, Bad Theme Choice And a Poorly Optimized Site Can Wreak Havoc With Font Loading.
For starters, the more HTTP requests to external sites needed to render your page/s, the slower your site will load. To exacerbate this, scripts and CSS are render blocking so poor optimization coupled with a slow server and a bloated theme could prove disastrous to user experience.
Additionally, being called by CSS, Google fonts are no exception to the render blocking conundrum.
Render blocking occurs when the parsing of HTML needed to render the page is paused (blocked) temporarily until all scripts and CSS complete their processes.
Besides a number of granular optimizations, the most important factors affecting page speed (in this order) are:
- Theme Choice
A fast site is crucial for optimal font loading and this starts with hosting.
No amount of optimizing can compensate for a lack of speed.
And because the whole objective of hosting Google fonts locally is to improve user experience, it would be counterproductive to consider unless you can outperform font delivery provided by Google's cloud servers and CDN.
A shared server is highly unlikely to outperform Google's servers.
I used to host with Siteground but because I wasn't seeing the type of speed I wanted, I switched to Cloudways. This site is served from a Digital Ocean server in New York and it's blazing fast.
On top of that, Siteground's renewal fees are crazy.
With Cloudways you can get a hosting plan for as little as $10 per month which will allow at least as many site visits as Siteground's best shared hosting plan at $35 per month.
And that gives you fully dedicated resources and the benefit of Pay-As-You-Go pricing, i.e. No Contracts.
Sign Up with PROMO CODE: WPMM25OFF for 25% OFF your first 2 months if you host with Cloudways.
A lightweight, well coded and optimized theme with a good caching plugin like WP Rocket is the next most important speed factor.
I don't venture past anything but a StudioPress theme (Genesis Framework) because there's just nothing that comes close in terms of optimization, i.e. clean coding, zero bloat plus the ability to create any type of site. And while you may expect a theme of such caliber to be pricey, they're actually cheaper.
The licence provides you with unlimited everything. So for a once off cost you get:
- Lifetime updates
- Lifetime support and ...
- You can use the theme on as many sites as you like.
Caching is absolutely crucial when it comes to font loading. While there's certainly no shortage of caching plugins, there are only two contenders in my view:
- WP Rocket.
- Swift Performance Pro.
WP Rocket is rock solid and has been around for way longer than Swift Performance Pro.
As a result, they've long since ironed out all the small bugs and it's also really simple to setup and works out of the box.
Swift Performance Pro offers more granular control. However, it's better suited to those who have a bit of knowledge and experience when it comes to caching.
If you really want to harness it's full features you'll need to know what you're doing and be prepared to experiment until you find the settings that give you the best results.
My Site Is Twice As Fast Since I Self Host Google Fonts
My speed tests reveal that my site loads twice as fast as it did when Google was serving my fonts.
Your results may differ due a number of factors including server location, user location, speed testing server location, whether you use a CDN and where the edge servers are located, server speed, internet connection etc.
- Hosting Provider: Siteground.
- Server Location: Chicago
- GTMetrix Test Location: Dallas USA.
- CDN: Cloudflare.
- Caching: Swift Performance Pro
- Server Side Caching: None
- All tests were performed at the same time of day.
- 4 speed tests were performed for each option namely:
- hosting Google fonts locally
- serving fonts from Google's servers using an enque function in my functions.php file (part of theme's coding).
- The average of each data set has been used to determine the end result.
- Other than the published tests, I performed multiple tests (including from GTMetrix's London location), all of which revealed similar results. I am certain therefore certain that the published results are indicative of everyday browsing.
|Served By||First Byte||Content Paint||Dom Int||Total Time|
The most important metrics are:
- Contentful Paint Time - the time it takes for any content to be shown. It is most representative of actual perceived load time in that it indicates when users receive consumable information such as text or images. My tests reveal that local hosting is almost twice as fast (448ms vs. 850ms).
- DOM Interactive - indicates when the browser has parsed the HTML so that it can structure and render the page. My tests reveal that locally hosting fonts is over twice as fast as serving them from Google (496ms vs. 1025ms).
- Total Load Time - the time it takes for the page to fully load after all background processes are complete. Again, locally hosting fonts is over twice as fast as Google's servers (850ms vs. 1750ms).
Added Benefits Of Hosting Google (or any other) Fonts Locally
Personally I don't chase after scores. However, some aspects of improving scores or grades will also improve speed.
One such aspect is expires headers.
You can't add expires headers to external resources so this error will always pop up in GTMetrix or Pingdom tests if you serve fonts from Google's servers. You can, however, add expires headers to fonts if you host them locally.
The advantage of this is that the user's browser will be instructed to cache those fonts for however long you specify in the headers (in your .htaccess file).
And because the fonts will then be stored in the browser cache, repeat visits to your site will be faster.
Furthermore, while your caching software can minify and concatenate CSS for installed plugins, it can't do so for external resources, Google Fonts included.
The ability to minify and concatenate CSS files makes a substantial difference to load times.
While locally hosting fonts will also fix your GTMetrix error, the most important thing is the speed boost that comes from these optimizations. This is made possible because the CSS lives in a local stylesheet on your own server.
A cache validator included in WP Rocket ensures that browsers take full advantage of all of the benefits of caching. To this end, allowing a cache validator to be specified means that the browser can perform a check to determine whether the font to be displayed already lives in its cache. If so, it will be served from there accordingly. This speeds up loading time and can only be achieved if the font is served from your local server.
The Easiest Way To Setup Local Hosting - Comprehensive Setup Guide.
If you follow the process I'm going to show you, it shouldn't take much longer than 5 minutes to get your fonts hosted locally. This process automatically converts the fonts into the formats that you choose and produces the correct CSS, making it a breeze to add to your stylesheet.
These are the steps we're going to follow:
- Go to Google webfonts helper website.
- Select font and font styles.
- Download and unzip font file.
- Upload fonts to your own server.
- Add CSS to stylesheet.
- Specify default fonts.
- Disable external calls to Google fonts server.
Head on over to Google Webfonts helper.
In the top left corner either enter the font name or select one from the list.
Select the font styles and weights you want to use on your site. Only choose the styles and weights you will use. Unused fonts add unnecessary bloat.
Download the zip file to a new directory that you create (e.g. Fonts) on your PC.
Now unzip the font file to the same destination.
I use Filezilla to FTP files to my site. You can use any ftp software you wish to achieve the same.
You can also file manager in cPanel to achieve this.
I like to upload to a "fonts" folder that lives directly under the public_html directory. This way the folder will never be overwritten with any theme or plugin updates.
Back on the Google webfonts helper site, click in the grey block to highlight all the CSS that was generated. Copy it to your clipboard and paste it into your desired stylesheet. (You could also enqueue them from functions.php).
I paste directly into my theme's style.css file (default Genesis stylesheet).
Now specify your default fonts and fallbacks to be used for body text, headings, links etc.
Make sure to disable any calls to the Google fonts server.
Depending on how the call is made for Google fonts in your environment, you may need to remove this from your html pages (possibly via header.php or theme settings) ....
.... or this from your stylesheet.
You may need to contact your theme vendor if you don't know where to access either of the above calls to Google fonts.
That's all there is to hosting Google fonts locally, but there are still a couple of optimizations you may wish to make.
Preloading For Added Speed
Instead of waiting until the CSS has been parsed and the CSS Object Model has been built, you can preload your fonts for some additional time saving. The CSSOM is similar to the DOM (document object model) but applies to CSS instead of HTML. Preloading forces the browser to fetch the font/s immediately.
Bear in mind that:
- The preload resource hint is not available in every browser. I suggest you select woff2 font files for this purpose because all browsers that support woff2 also support preload.
- If you add the resource hint to the head of all HTML pages, the resource will be preloaded whether needed or not. If the browser already has the font in it's cache, the preload is wasted. You must decide whether the benefit outweighs the risk.
Personally, I use preload. That being said, I only preload my main font style (in my case bold text) required to render the most important text for users. This not only moves the font load up the waterfall but also has a very positive effect on my contentful paint time. However, each additional preload comes at a cost to initial render. It's a fine balance.
Add the relevant code to the <head> of your document. You must do this separately for each font style you wish to preload and make sure the naming of the font is exactly the same as it appears in the public_html/fonts folder.
<link rel="preload" as="font" type="font/woff2" href="www.yourdomain.com/fonts/cormorant-garamond-v7-latin-700.woff2" crossorigin>
Inline CSS / Critical CSS To Prevent Render Blocking
CSS is a render blocking resource. This means that the parsing of HTML (and the loading of the page) is blocked / delayed until the CSS is parsed first.
Because your locally hosted Google fonts are called using the CSS
@font-face declaration, your fonts are also render blocking.
WP Rocket offers the ability to generate critical CSS for rendering of the above the fold content which enhances perceived load time and hence user experience.
With WP Rocket, when enabling CSS Optimization the critical CSS will be generated behind the scenes and added to next page load. Thereafter, this CSS will be loaded asynchronously.
Swift Performance adds a toggle to enable the critical CSS to be inlined within the <head> of the document.
If you don't use a caching plugin that generates critical CSS, simply add the CSS for your fonts into the <head> section of your document, between <style></style> tags.
Limit Characters To Reduce Size And Boost Page Loading Speed
Each web font comprises a collection of glyphs which may include Latin, Greek and Cyrillic characters.
Vast support is great but you don't want it to become an impediment to performance.
According to Ilya Grigorik, Google's Noto font aims to support the entire world's languages but the download size of the font exceeds 1.1Gb.
Unicode subsetting allows us to limit the characters to only those required to render the page thereby reducing download size while becoming more performant. This is achieved by splitting a large unicode font into smaller subsets (e.g. Latin) and downloading only the glyphs needed to render a page.
The use of Unicode range subsets and separate files for each stylistic variant of the font allows you to define a composite font family that is both faster and more efficient to download. Visitors only download the variants and subsets they need, and they aren't forced to download subsets that they may never see or use on the page.
Personally, I don't use any further subsetting. If you specify your subsets before downloading your fonts using the Google webfonts helper there's no need for any further manipulation. The file sizes are already tiny.
I mentioned subsetting for those who wish to download additional subsets and then filter out what isn't needed.
NOTE: I tried to subset further using Glyphhanger but found that some of the characters were synthesized and looked out of place. If you limit your subset before downloading then I don't believe there's any need to play around any further.
If you happen to download your font/s from Google, you can limit subsets before downloading.
How To Speed Up Font Loading If You Serve Them From Google Servers
When serving fonts from Google's servers, you lose whatever limited control over FOIT and FOUT you may have when you host them locally leaving you in the hands of the default browser behavior and Google's default swap behavior.
The only speed optimization you can effect is to preconnect to Google's servers, allowing the browser to perform the DNS lookup, TCP handshake and TLS negotiation as soon as it finds the script in the <head> section of the HTML as opposed to waiting for the normal call during the parsing process. This may only shave off some milliseconds but it's still better than nothing.
To preconnect, add the following to the head of your HTML pages. If you use a Genesis theme, add the script via theme settings. Otherwise you may need to add it to your child theme's header.php file.
You can group fonts using preconnect.
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin> <link href="https://fonts.googleapis.com/css?family=Cormorant+Garamond:400,400i,700|Raleway:700" rel="stylesheet">
I hope I've impressed upon you the importance of using the font-display descriptor as a means of avoiding FOIT and enhancing user experience, especially for those on slower connections.
It's such a big deal that Google's own Pagespeed Insights / Lighthouse will ding you for not using it.
While Google now include the font-display: swap; descriptor as a default (since May 2019) when serving fonts from their servers, the best way to retain maximum control while taking full advantage of speed and caching benefits is to host Google fonts locally.
So what do you think? Leave me a comment.
Cheers for now, Adam