The ultimate guide to web fonts

By Hunter Becton on February 20, 2023

Web fonts are custom fonts loaded from a web server. By using web fonts, web designers can incorporate unique and distinctive fonts into their web pages and provide a customized typographical experience for viewers.

However, loading web fonts can impact page load times and user experience if not optimized properly. As a result, understanding how to use and optimize web fonts is key to building fast, user-friendly websites.

This guide will teach you about web fonts and how to optimize and use them in your web projects.

Watch the lesson

What are fonts?

Fonts are styles of text that determine the shape and design of letters, numbers, and symbols. Each font has a distinct look and feel based on characteristics like the thickness of strokes, height and width proportions, slant, design and embellishments of letters, and more.

Fonts allow for stylistic differentiation of print or digital text and convey moods or tones through their appearance. Selecting different fonts is a key way for designers to customize the visual style of websites, print materials, signage, and more.

Let's first examine the many sorts of fonts before discussing font optimization and loading.

Types of fonts

To begin, there are three primary types of fonts: system, device, and web.

System fonts

System fonts, also known as web-safe fonts, are fonts that are built into devices by default. This means you don't have to download them. Common system fonts include Arial, Times New Roman, Georgia, Verdana, and Courier New.

System fonts are already on devices, so webpages don't need extra downloads to use them. This makes websites faster since they don't use bandwidth to download extra font files.

Device fonts

Device fonts are installed on a user's device that the operating system or hardware manufacturer provides. For example, different devices may have different default system fonts, and some devices allow users to install additional fonts.

Device fonts improve page load times since they are already installed on the user's device, eliminating the need to download font files. However, web designers have less control over typography when limited to native device fonts.

Web fonts

Web fonts are downloaded to a user's device when needed rather than pre-installed. To use web fonts, you first research and purchase font files. Then, upload the font files to your web server or from a third party like Google Fonts. Once uploaded, the font files will automatically download to users when the fonts are needed to display web content.

Because web fonts require additional bandwidth to download the font files, optimizing web fonts for fast loading and minimal impact on user experience requires careful management to ensure good website performance.

Understanding web fonts

Web fonts download custom font files from a web server to a user's device upon accessing a web page. The web page's CSS references the font files, and the user's browser downloads and loads the fonts to display the text properly. By linking to external font files instead of relying on pre-installed system fonts, web designers can incorporate distinctive, customized fonts to create a unique visual style for their websites.

However, this also means additional bandwidth is required to download the font files, which can impact page load times and user experience if not properly optimized. As a result, care must be taken to optimize web font delivery for fast performance and minimal impact.

Where do I get web fonts?

Before using free fonts, check the license terms. While free fonts can be useful for personal projects, many restrict commercial use. Some sites offer free fonts with commercial licenses, but always check the license for permissions and restrictions before downloading or using a font in your work.

Below are some of our favorite places for free and commercial fonts:

Want inspiration on fonts that pair well together? Check out some of these resources:

Different types of fonts and their browser support

There are different types of web fonts available for designers. Below are these fonts and their features:

TrueType Font (TTF)

TrueType Fonts (TTF) are vector-based fonts developed in the late 1980s through the collaboration of Apple and Microsoft. TTF fonts scale to any size without pixelation and are compatible with older browsers, especially on mobile devices. As a result, TTF fonts are a popular choice for web designers who want to support a wide range of browsers and devices.

However, there are a few downsides to using TTF fonts. First, the font files can be quite large in size, which can slow down page loading times. Second, TTF font support in older browsers like IE8 is limited or non-existent, requiring workarounds. Finally, while TTF fonts are compatible with both Mac and Windows operating systems, they require additional licensing to be used commercially.

Overall, TTF fonts are a solid choice if broad browser compatibility and scalability are priorities for your project, as long as you know the potential downsides regarding file size and licensing.

OpenType (OTF)

OpenType (OTF) is a font format developed jointly by Microsoft and Adobe Systems. OTF supports a wider range of characters and languages than TrueType fonts (TTF) and has more typographic features. OTF fonts allow users to access alternate glyphs and ligatures and have superior hinting capabilities for on-screen display at small sizes. However, OTF font files tend to be larger in size than TTF or WOFF formats, which can impact page load times.

Because of their additional features, OTF fonts are a good choice if you need broad language support or advanced typographic controls. However, for most basic web font uses, the benefits of OTF may be outweighed by the potential downsides of larger file sizes and slower page loading. It's important to consider your specific use case and audience when determining if OTF is the right format for your web fonts.

Embedded Open Type (EOT)

Microsoft created Embedded OpenType (EOT) fonts as a web font format. The goal was to allow websites to use custom fonts while addressing copyright and licensing concerns. With EOT, font files are made smaller through subsetting, which removes unused characters. The font files are also given a digital signature and encrypted, preventing easy extraction of the full font data. This was meant to deter copyright infringement.

However, EOT has some downsides. It is a proprietary format developed by Microsoft, requiring a license to be used. It is also only supported in older versions of Internet Explorer, limiting its usefulness. Because of this, EOT is not as commonly used for web fonts today relative to other formats like WOFF and WOFF2, which offer comparable or better compression and more broad browser compatibility.

Web Open Font Format 1.0 (WOFF)

Web Open Font Format (WOFF) is an open web font format developed by the W3C WebFonts Working Group. It is a web-optimized font format that uses compression to reduce file size, allowing faster download times and more efficient bandwidth use.

Almost all modern browsers, including Chrome, Firefox, Safari, and Edge, support WOFF. This broad compatibility makes WOFF a popular choice for web font use. The WOFF format includes metadata for copyright, licensing, and other information, which helps address intellectual property concerns using custom web fonts.

Web Open Font Format 2.0 (WOFF2)

The next generation of WOFF is WOFF2, which offers an additional 30-40% file size reduction over WOFF using more advanced compression algorithms. WOFF2 is supported in all modern browsers and some older browsers with a small JavaScript polyfill. The benefits of the additional compression may be worth the small overhead of the polyfill, depending on your specific use case and audience.

Overall, WOFF and WOFF2 are efficient, broadly compatible formats for delivering web fonts. The choice between WOFF and WOFF2 will depend on your priorities around file size, browser support, and resource constraints. Either format is a solid choice for web fonts, with WOFF2 being optimal if maximum compression and modern browser support are priorities.

How to load web fonts

Fonts should load as early as possible to ensure users can see the page content. Loading them efficiently is especially important for third-party fonts requiring separate connections. Following best practices for font loading will help pages display properly.

Issues with loading fonts

Below are some issues with loading fonts on your website.

Flash of Invisible Text (FOIT)

Flash of Invisible Text (FOIT) occurs when a web page loads without text before changing to the intended font once it finishes loading. Since web font files can be large even when compressed, it takes time to download the font and render the text. As a result, users may briefly see a blank page or unstyled text before the custom font is loaded and applied.

To avoid this issue, you can use a fallback system font while the custom font is loading to allow the page content to display immediately. Then, the custom font is swapped in once loaded without the "flash" of invisible or unstyled text.

Flash of Unstyled Text (FOUT)

Flash of Unstyled Text (FOUT) occurs when a web page loads with plain, default styling before the custom font finishes loading and the intended styling is applied. Since web font files can be large even when compressed, it takes time to download the font and apply the custom styling. As a result, users may briefly see unstyled text in the default system font before the custom font styling is loaded and rendered.

How font loading time impacts Core Web Vitals

Even when gzipped, custom web fonts are frequently large files that load slowly. Some websites load fonts incorrectly, even with the best font optimization method. These cause performance issues, slow loading time, blocked rendering, and swapped fonts during navigation, which affect the core web vitals.

Core Web Vitals, which are standardized metrics from Google that assist developers in understanding how users interact with a web page, are available to all website owners. Your Google ranking will increase, and your score will improve if you boost your Core Web Vitals.

There are three categories for the Core Web Vitals:

Largest Contentful Paint (LCP)

When a web font is not loaded, browsers frequently take longer to render text. The result is a delay in the largest contentful paint (LCP).

LCP is one of the Core Web Vitals. It measures how quickly a page's main content is rendered within the viewport, representing the time from when a user initiates page load to when the largest image or text block is displayed on the screen.

Websites should aim to load page content within 2.5 seconds for at least 75% of page visits to provide an optimal user experience.

First Input Delay (FID)

First Input Delay (FID) refers to the time from when a user first interacts with a web page (i.e., clicks a link) to the time when the browser can respond to that interaction. Slow font loading times can increase FID, creating a poor user experience. Websites should aim to minimize FID to provide responsive performance and a good user experience.

Cumulative Layout Shift (CLS)

Cumulative Layout Shift (CLS) measures the movement of visible elements within the viewport. It tracks the total distance that all page elements shift from their original position and provides a metric of visual stability for the page.

Slow font loading can increase CLS since visible elements may shift position noticeably once custom fonts are rendered, creating a poor user experience. Minimizing CLS scores is important for strong Core Web Vitals, so optimizing font loading to reduce layout shifts is crucial.

Loading fonts with cloud-hosted fonts

Loading cloud-hosted fonts from a provider like Google Fonts or Adobe Fonts is oftentimes the easiest solution because you can simply use the <link> they provide and drop it into the <head> of your HTML. For example, here’s a code snippet that Google Fonts provides for loading the regular, medium, and semibold font weights for Fira Sans:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;500;600&display=swap" rel="stylesheet">

The benefits of cloud-hosted fonts are that the font files are already optimized, and the service handles caching and browser support, reducing the workload for developers. However, relying on an external service means less control, and the font files must download from the cloud service before rendering the text, which can impact performance.

Also, according to the General Data Protection Regulation (GDPR), including fonts from a third-party service like Google Fonts may constitute the processing of user data that requires explicit consent. As a result, to comply with GDPR, websites should host web fonts locally or use an in-house font service rather than relying on external providers.

Read more about how a Munich, Germany court found that websites with embedded Google Fonts violate GDPR.

Loading fonts with self-hosted fonts

Self-hosting fonts allow full control over font delivery. You can optimize and configure the files and serving process to maximize performance by hosting font files on your own server.

For example, you can subset fonts only to include necessary glyphs, compress and minify the files, set cache headers, and preconnect or preload the font files. Having direct control over your font files and serving process allows tight optimization of font delivery for fast, efficient performance and minimal impact on page loading times or user experience.

We’ll cover how to deliver web fonts in the next section.

What is @font-face?

When employing any web font with CSS, a @font-face declaration is necessary. At the very least, it identifies the location of the matching font file and defines the name that will be used to refer to the font. Depending on how long a web font is to load, the @font-face specification gives developers control over how their web fonts will render (or fallback).

A @font-face declaration alone does not download a font. The font is only downloaded if it's used in the page's styling. For example, a font is downloaded when you use it to style text on the page:

@font-face {
  font-family: "Inter";
  src: url("/fonts/Inter-Regular.woff2") format("woff2");
}

h1 {
  font-family: "Inter";
}

To clarify, in the example above, Inter would only be downloaded if the page contained an <h1> element.

How to deliver web fonts

As discussed above, I recommend hosting your own web fonts. Before hosting your own fonts, you first want to consider the copyright and license of the web font and ensure you have the proper rights.

Once you’ve confirmed the copyright and license, you’ll want to consider some of the font optimization tips below.

Use WOFF and WOFF2 font formats

Earlier in this guide, we discussed the different types of font formats. As a review, WOFF and WOFF2 are the optimal formats for web fonts because they offer efficient compression, resulting in smaller file sizes that load faster, minimize bandwidth usage, and impact page performance. WOFF2 provides additional compression, and both formats have over 96% browser support, making them versatile and compatible choices for web font delivery.

Preload fonts

The browser loads resources in a specific order. CSS files are loaded first, followed by scripts and images. You can control the loading order of resources by preloading the most important assets first. Preloading critical assets allows them to load faster and speeds up page rendering.

We preload web fonts to eliminate delays. Caching the font file early allows browsers to access it immediately, removing the need to fetch it later. If implemented properly, this can improve page load times.

Below is an example of what preloading a web font in the head of your HTML document would look like:

<link
	rel="preload"
	href="/fonts/Inter-Regular.woff2"
	as="font"
	type="font/woff2"
	crossOrigin="anonymous"
/>

You'll want to keep in mind that you should only preload fonts above the fold, which means the ones visible on the initial page load. It may be tempting to preload all your fonts, but this could damage your perceived performance because your browser is waiting for unused fonts to be loaded.

Subset fonts

Font files contain many glyphs for the characters they support. To reduce file size, you can subset fonts by removing unused characters.

The @font-face declaration's Unicode-range descriptor specifies which characters a font supports. For example, the following code below subset to Latin languages:

@font-face {
  font-family: "Inter";
  src: url("/fonts/Inter-Regular.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

In the guide's next section, we'll use a font generator to subset fonts within the actual file, instead of specifying the Unicode range in CSS. Subsetting within the actual file is recommended because defining your Unicode range in CSS still downloads the entire font file.

Use a web font generator

So, optimizing your fonts is much more work than expected. That’s why I recommend using the Webfont Generator from Transfonter to assist with this process. This generator will create WOFF and WOFF2 font formats, apply basic subsetting for western languages, and automatically fix missing glyphs.

https://axcfyibnfbkmqbvnrcoa.supabase.co/storage/v1/object/public/images/30aa587d-3c79-4f66-99da-e5289bc84ba9.jpg

How to render web fonts

Now that you understand web fonts and have completed all the hard work to optimize them, it’s now time to render them on your web project.

Regarding rending fonts, there are two important concepts to understand: the block and swap period.

The block period

When a web browser requests a web font, it initiates a block period. If the font is unavailable during this block period, the text is rendered in an invisible fallback font and remains invisible to the user. Once the block period ends, if the web font is still unavailable, the text is rendered in the fallback font and becomes visible.

The swap period

When the block period completes, the swap period follows. But if the required font is not yet accessible, the fallback font is utilized. The text is viewable now and will revert to the font when it loads completely.

Types of font display options

To set how you want the browser to handle your block and swap period, you’ll use the font-display descriptor inside the @font-face declaration.

There are five options for font-display which can be summarized in the chart below:

Auto

The auto setting for font-display lets the browser determine how to handle the block and swap period. The browser will pick either block, swap, fallback, or optional behavior based on factors like the font file size and type.

Block

The block setting for font-display renders the text invisible (no fallback font) during the block period. If the web font is loaded before the block period ends, the text is rendered in the web font. The text remains invisible if the web font does not load before the block period ends.

This setting ensures the web font is used as soon as it loads for the sharpest text rendering but can result in invisible text if it takes a long time to load.

Use this option if ensuring text is displayed in a web font is a top priority.

Swap

The swap setting for font-display renders the text in the fallback font during the block period. Once the web font loads, the text is swapped to display in the web font. This setting ensures text is always visible but may result in a "flash of unstyled text" (FOUT) as the text is swapped from the fallback font to the web font.

Use this option if displaying text quickly is a top priority, but you still want to ensure the web font is used.

Fallback

The fallback setting for font-display renders the text in the fallback font for the duration of the page load. The web font is downloaded in the background, but the fallback font is always used to display the text.

This setting ensures text is always visible but may result in the web font never being used if it takes a long time to load.

Use this option if ensuring text visibility is the top priority and web font usage is secondary.

Optional

The optional setting for font-display downloads the web font in the background but does not guarantee it will be used to render the text. If the web font loads before the fallback font are used, the web font is applied. If the web font does not load quickly, the fallback font is used instead.

This setting minimizes the impact on page load times and ensures text is always visible, but the web font may never be used.

Use this option if web font usage is a secondary priority to fast page loads and consistent text visibility.

Frameworks are making font loading easier

It’s worth noting that frameworks like Next.js make font optimization much easier by providing built-in solutions. For example, @next/font will automatically optimize your fonts (including custom fonts) and remove external network requests for improved privacy and performance.

Putting it all together

Now let's take everything we’ve covered in this guide and apply it to a new project. This approach may differ depending on your framework or library, but we’ll create a simple HTML and CSS project in this example.

First, I decided to use the Aspekta font, which I discovered while browsing Uncut.

https://axcfyibnfbkmqbvnrcoa.supabase.co/storage/v1/object/public/images/1e3a3ed4-3e49-46af-bd6f-3b9e561d5875.jpg

This font is hosted on Github, so you can download the files by going to Code > Download Zip.

Unzip the project once it’s downloaded, and head to the Transfonter Webfont Generator.

https://axcfyibnfbkmqbvnrcoa.supabase.co/storage/v1/object/public/images/7bdf3e4e-fc9b-4422-b0ef-e49bd1e73fb5.jpg

Click on the Add Fonts button and select the TTF fonts by going to the fonts folder and then to the ttf folder. Make sure you only select the weights you need for your project.

You may have noticed that this project already has WOFF and WOFF2 fonts. You could use these, but Transfonter will subset the font and create compressed WOFF and WOFF2 files for us. Plus, it will generate a useful CSS file we can copy and paste into our project.

Because the font subset is within the font file, there’s no need to include an unicode-range. After optimizing your font subset, the file size decreases because unused glyphs are removed. For example, the Aspekta 800 WOFF2 font decreased from 22 kb to 14 kb.

https://axcfyibnfbkmqbvnrcoa.supabase.co/storage/v1/object/public/images/4ec4989c-e9b6-4689-9cd3-7002623f4895.jpg

Select the font-display value you want to use. In my case, I'll select optional.

The last setting is to tell the generator where your final font files will be hosted on your project. I'm using SvelteKit for my project, which uses a static folder to host static assets like fonts. Inside this folder, I'll create a new folder called fonts, which will hold the fonts generated from Transfonter. I can tell Transfonter that these files will be in the folder by setting the Fonts directory option to 'fonts'. This will be used when generating the CSS file, which will save me time from having to update the src value when defining the fonts in CSS.

Now unzip the downloaded file and place all the WOFF and WOFF2 fonts in your project.

Now open the stylesheet.css file and copy and paste everything from this file at the top of your project’s CSS file:

@font-face {
  font-family: "Aspekta";
  src: url("fonts/aspekta-400-webfont.woff2") format("woff2"),
    url("fonts/aspekta-400-webfont.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: optional;
}

@font-face {
  font-family: "Aspekta";
  src: url("fonts/aspekta-600-webfont.woff2") format("woff2"),
    url("fonts/aspekta-600-webfont.woff") format("woff");
  font-weight: 600;
  font-style: normal;
  font-display: optional;
}

@font-face {
  font-family: "Aspekta";
  src: url("fonts/aspekta-800-webfont.woff2") format("woff2"),
    url("fonts/aspekta-800-webfont.woff") format("woff");
  font-weight: 800;
  font-style: normal;
  font-display: optional;
}

Last, I need to tell my CSS to use the font. Because I want to use this font throughout my entire project, I’ll define the CSS on the body tag below where I loaded the fonts, ensuring the font family names match the ones from @font-face. I’ll also provide a list of fallbacks.

body {
	font-family: 'Aspekta', ui-sans-serif, system-ui, Arial, sans-serif,;
}

Conclusion

Delivering web fonts effectively requires careful planning and optimization. By choosing efficient file formats like WOFF and WOFF2, preloading fonts, subsetting to include only necessary glyphs, and configuring font display options, developers can balance fast page loads with optimal text rendering.

While manually optimizing and delivering web fonts provides the most control, web font frameworks are making the process increasingly straightforward. By following the best font optimization and delivery practices, websites can achieve fast performance and provide an excellent user experience.