Table of contents of the article:
When it comes to web performance, the focus is almost always on images, caching, CDN, HTML compression, CSS, JavaScript, database optimization, and server response times. These are all crucial aspects, of course, especially in CMS contexts like Wordpress, WooCommerce, Joomla, Drupal, Magento or PrestaShop. However, there is one element that is often ignored or treated superficially: the web fonts.
A seemingly innocuous font can weigh tens or hundreds of kilobytesIf a page loads multiple variations of the same font, such as Regular, Bold, ExtraBold, Thin, Italic, and combinations thereof, the overall weight can become significant. This problem is even more evident on WordPress and WooCommerce sites built with page builders, commercial themes, and typography customization plugins, where it's very easy to load more fonts than necessary without realizing it.
Optimizing fonts isn't simply about "using a lighter font." It means choosing the right format, eliminating obsolete formats when they're not needed, converting files to the most efficient format, reducing the set of loaded glyphs, and configuring CSS correctly so that the browser downloads only what it needs, when it needs it.
Why fonts impact web performance
Fonts are blocking or semi-blocking resources for the visual rendering of the page. The browser must download them, interpret them, and apply them to HTML elements. If the font isn't immediately available, the browser can behave in different ways: it can temporarily display a fallback font, hide the text for a short time, or cause a visual switch when the custom font is finally loaded.
These behaviors have a direct impact on the user experience and, indirectly, also on the signals measured by tools such as PageSpeed Insights, Lighthouse, WebPageTest and on Google Core Web VitalsA font that's too heavy can delay text display, increase network traffic, and degrade the overall perception of site speed.
This problem is particularly common on WordPress and WooCommerce sites, where the use of advanced themes, page builders, and font management plugins can lead to unnecessary file uploads. For example, a site might visually only use a 400 and 700 font weight, but also upload 300, 500, 600, 800, italics, and other unused variations. Each additional file represents an HTTP request and a file weight transferred to the client.
TTF, WOFF, and WOFF2: Practical Differences
To understand how to optimize fonts, we must first distinguish the most common formats: FTT, WOFF e WOFF2.
The format FTT, short for TrueType Font, is a historic format, widely used across operating systems and desktop environments. It's suitable for local installation on computers, graphics software, and operating systems, but it's not the ideal format for serving directly on the web. A TTF file contains the complete font information, but it's not specifically designed for efficient transfer via HTTP.
The format WOFF, Web Open Font Format, was introduced specifically for web use. It is essentially a compressed container for TrueType or OpenType fonts, designed to reduce the size of the source file and be easier to handle by browsers. Compared to TTF, a WOFF file is typically smaller and more suitable for online distribution.
The format WOFF2 This is the evolution of WOFF. It uses a more modern and efficient compression method based on Brotli and is now the recommended format for web fonts. In many cases, switching from TTF or OTF to WOFF2 can result in savings of approximately 30% to 50%. Switching from WOFF to WOFF2 often results in smaller but still significant savings, typically in the range of 15-30%, even before applying more advanced techniques like subsetting.
| Format | Typical use | Compression | Practical advice |
|---|---|---|---|
| TTF / OTF | Desktop, font source, local installation | Absent or not optimized for the web | Always avoid as a primary format for the web |
| WOFF | Web font compatible with older browsers | Older compression | Only useful as a fallback if legacy compatibility is needed |
| WOFF2 | Modern web fonts | Brotli compression | Preferred format for production |
The problem of font plugins in CMS
In modern CMSs, it's very common to upload custom fonts through plugins. In WordPress, for example, plugins like "Custom Fonts" allow you to upload WOFF, WOFF2, TTF, or OTF files and save them within the theme or builder. This convenience, however, can hide some problems.
The first problem is that the name visible in the CSS doesn't always match the physical file name. If we see a rule like this in the browser:
element.style {
font-family: "Managed Server Extra Bold";
font-size: 1.3rem;
font-style: normal;
font-weight: 400;
}
value it font-family: "Managed Server Extra Bold" represents the name of the typeface family registered in the CSS, not necessarily the name of the file uploaded to the server. The actual file could be called something completely different, for example Gordita-Black.woff, managed-server-extra-bold.woff2 or have been automatically renamed by the plugin.
To identify the file actually served to the browser, it's best to use the browser's developer tools, opening the Network panel and filtering font requests. Alternatively, on the server side, you can search for uploaded files in the site directory.
find . -path "*/wp-content/*" -type f ( -iname "*.woff" -o -iname "*.woff2" -o -iname "*.ttf" -o -iname "*.otf" )
Another option is to search the code or database for the name of the font family displayed in the CSS:
grep -Rni "Managed Server Extra Bold" wp-content/
Or, if you have WP-CLI:
wp db search "Managed Server Extra Bold"
This approach is useful because many plugins dynamically generate rules @font-face or save them as options in the database.
Converting fonts to WOFF2
A first optimization consists in converting the fonts available in WOFF, TTF or OTF format to WOFF2. On Linux you can use tools like FontTools, Brotli and, in some cases, the tools of the WOFF2 suite.
It is important to clarify a practical aspect: the command woff2_compress It's not always possible to directly convert a WOFF file to WOFF2. In many scenarios, it works fine when starting from TTF or OTF files, but it can fail with an already compressed WOFF, resulting in parsing errors. For this reason, a more reliable solution is to use FontTools directly, which allows you to read a WOFF and save it as WOFF2.
Installation on Debian, Ubuntu or WSL environments:
apt update apt install python3-fonttools python3-brotli
Alternatively, via pip:
pip3 install fonttools brotli
Directly converting a single WOFF file to WOFF2 with Python and FontTools:
from fontTools.ttLib import TTFont
src = "Gordita-Black.woff"
dst = "Gordita-Black.woff2"
font = TTFont(src)
font.flavor = "woff2"
font.save(dst)
print(f"{src} -> {dst}")
To convert all files .woff present in the current directory:
from fontTools.ttLib import TTFont
from pathlib import Path
for src in Path(".").glob("*.woff"):
dst = src.with_suffix(".woff2")
try:
font = TTFont(str(src))
font.flavor = "woff2"
font.save(str(dst))
print(f"OK: {src} -> {dst}")
except Exception as e:
print(f"ERRORE: {src}: {e}")
After conversion, it is always good practice to check the file size and format:
ls -lh *.woff *.woff2 file *.woff2
The real leap in quality: subsetting
Converting to WOFF2 is useful because it allows us to make academic optimizations of between 25 and 30% of the weight, but it is often not the most powerful optimization. The real leap in quality is achieved with the subsetting, that is, the creation of a font file containing only the glyphs actually needed.
A commercial or professional font can contain hundreds or thousands of glyphs: Latin letters, accents, mathematical symbols, Greek characters, Cyrillic, ligatures, arrows, icons, currency, advanced typographical signs and much more. If the site is in Italian and only uses the font for titles, buttons, and Latin text, it makes no sense to transfer the entire character set to the browser.
For an Italian or European site, a reasonable subset might include the basic ASCII block and the Latin supplement needed for accented letters. A commonly used range is:
U+0020-007E: printable ASCII characters, so basic letters, numbers and punctuation;U+00A0-00FF: Latin-1 Supplement, which includes many accented letters used in European languages.
With FontTools it is possible to generate a subsetted WOFF2 using pyftsubset:
pyftsubset Gordita-Black.woff --output-file=Gordita-Black-subset.woff2 --flavor=woff2 --layout-features='*' --unicodes="U+0020-007E,U+00A0-00FF" --with-zopfli
The same approach can be applied to all font variations actually used:
pyftsubset Gordita-Bold.woff --output-file=Gordita-Bold-subset.woff2 --flavor=woff2 --layout-features='*' --unicodes="U+0020-007E,U+00A0-00FF" --with-zopfli pyftsubset Gordita-Thin-1.woff --output-file=Gordita-Thin-1-subset.woff2 --flavor=woff2 --layout-features='*' --unicodes="U+0020-007E,U+00A0-00FF" --with-zopfli
The option --with-zopfli This can be useful when generating WOFF, while in the case of WOFF2 the actual benefit may be limited or depend on the FontTools pipeline and installed libraries. In any case, the key point is not to "compress more" a WOFF2 already compressed with Brotli, but to reduce the number of glyphs and tables included in the final file.
Real-world example: Optimizing the Gordita font
Let's take a real-world optimization case study of three variants of the Gordita font: Black, Bold, and Thin. The initial files were in WOFF format. They were first converted to WOFF2 and then subsetted, maintaining the ASCII and Latin-1 Supplement characters, sufficient for typical use in Italian and European languages.
The working directory showed this situation after conversion and subsetting:
Gordita-Black.woff 86K
Gordita-Black.woff2 66K
Gordita-Black-subset.woff2 24K
Gordita-Bold.woff 84K
Gordita-Bold.woff2 64K
Gordita-Bold-subset.woff2 23K
Gordita-Thin-1.woff 81K
Gordita-Thin-1.woff2 62K
Gordita-Thin-1-subset.woff2 22K We represent this data in tabular form:
| Font | Original WOFF | WOFF2 converted | WOFF2 subset | WOFF Savings → WOFF2 | WOFF Savings → subset |
|---|---|---|---|---|---|
| Gordita Black | 86 KB | 66 KB | 24 KB | about 23,3% | about 72,1% |
| Gordita Bold | 84 KB | 64 KB | 23 KB | about 23,8% | about 72,6% |
| Gordita Thin | 81 KB | 62 KB | 22 KB | about 23,5% | about 72,8% |
The result is extremely interesting. The simple conversion from WOFF to WOFF2 already produces a saving of about 23-24%. This is a significant improvement, achieved without altering the available character set. However, Subsetting brings the overall savings to over 72% compared to the original WOFF files.
Considering the three variants together, the overall weight goes from:
- 251 KB in original WOFF format;
- 192 KB in converted WOFF2 format;
- 69 KB in subsetted WOFF2 format.
In practice, compared to the original WOFFs, you save approximately 182 KB. Compared to non-subsetted WOFF2s, you still save about 123 KBOn a single visit, this may not seem like a huge number, but on mobile traffic, slow connections, resource-intensive pages, and thousands of daily visits, the impact becomes tangible.
Why subsetting is more effective than simple compression
When a file is already in WOFF2, looking for "even stronger compression" is limited. WOFF2 already uses Brotli, a very efficient compression. The most effective way to further reduce the file size is not to compress the same data better, but remove unnecessary data.
A full font can contain characters that the site will never use. If a site is in Italian, it might not need Cyrillic or Greek glyphs, phonetic symbols, advanced mathematical operators, or extended alphabets. If the font is used only in headlines, it might not be necessary to include every available typographic symbol. If it's used only for a text logo or a few calls to action, you can even generate a subset based on the characters actually present in those sentences.
FontTools also allows you to create subsets starting from a text file containing the fonts actually used:
pyftsubset Gordita-Black.woff --output-file=Gordita-Black-used.woff2 --flavor=woff2 --layout-features='*' --text-file=caratteri-usati.txt
This technique is very aggressive and should be used with caution. It's perfect for highly controlled elements, such as text logos, static hero titles, buttons, or specific headlines. However, it's risky for dynamic text, user-generated content, WooCommerce catalogs, multilingual blogs, or areas where content changes frequently.
How to integrate optimized fonts into CSS
After generating the optimized WOFF2 files, you need to integrate them correctly into your site. Using @font-face allows you to declare the font and tell the browser which file to download.
@font-face {
font-family: 'Gordita';
src: url('/wp-content/uploads/fonts/Gordita-Black-subset.woff2') format('woff2');
font-weight: 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Gordita';
src: url('/wp-content/uploads/fonts/Gordita-Bold-subset.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Gordita';
src: url('/wp-content/uploads/fonts/Gordita-Thin-1-subset.woff2') format('woff2');
font-weight: 100;
font-style: normal;
font-display: swap;
}
The property font-display: swap This is particularly important. It tells the browser to immediately display a fallback font and replace it with the custom font as soon as it's available. This reduces the risk of text being invisible while the font is loading.
It is equally important to correctly match the font weight. If a file is called “Black” or “ExtraBold,” it probably should be declared with a weight of 800 or 900, not 400. A mismatch between the actual file and font-weight It can cause unwanted behavior, inconsistent rendering, and loading incorrect variants.
Optimization in WordPress and WooCommerce
Font optimization can be managed in several ways in WordPress. Some themes allow you to upload custom fonts from the settings panel. Some page builders have a dedicated section for custom fonts. Plugins like "Custom Fonts" allow you to upload custom typeface families and associate them with various weights.
The recommendation is simple: load only the formats and weights you actually need. If the site only uses WOFF2, there's no point in also loading TTF, OTF, and WOFF, unless you specifically need compatibility with very old browsers. If the design only uses Regular and Bold, there's no point in registering six or seven variants.
In WooCommerce, this is even more important, as product, category, cart, and checkout pages need to be as fast and stable as possible. A heavy font may seem aesthetically pleasing, but on mobile, it can contribute to slow content display, especially when loaded alongside product images, tracking scripts, theme CSS, payment plugins, marketing widgets, and dynamic components.
The principle, however, applies regardless of the CMS. Whether it's WordPress, WooCommerce, Magento, PrestaShop, Drupal, Joomla, or a custom application developed in Laravel, Symfony, Next.js, or another stack, the browser will still need to download the fonts. The fewer unnecessary bytes transferred, the better the page will behave.
Preload critical fonts
In some cases, it can be useful to preload truly critical fonts, those needed for the above-the-fold portion of the page. Preloading should be used with caution: preloading too many fonts can degrade performance rather than improve it, as it depriors other important resources.
Preload example for a WOFF2 font:
<link rel="preload"
href="/wp-content/uploads/fonts/Gordita-Bold-subset.woff2"
as="font"
type="font/woff2"
crossorigin>
Preloading makes sense for one or two truly essential fonts, such as the font used in the main title of the home page or in the hero section. It shouldn't be used indiscriminately for all variations of the typeface family.
Beware of cache, CDN and MIME type
Once the files are optimized, you need to ensure they are served correctly by the server. Fonts should have long cache headers, especially if the filename contains a version or if it only changes during deployment. A WOFF2 file can be safely cached by the browser and a CDN for extended periods.
It's also useful to check the MIME type. For WOFF2, the correct type is:
font/woff2
For WOFF:
font/woff
Incorrect configurations can generate browser warnings or non-optimal behavior. On Nginx, for example, you can ensure that the MIME types are present in the global configuration or in the file mime.types.
Practical checklist for optimizing fonts
A good working procedure for optimizing web fonts can be the following:
- locate all font files uploaded to the site using DevTools or server-side search;
- check which variants are actually used in the CSS;
- eliminate unnecessary weights, styles and formats;
- convert files to WOFF2 when possible;
- apply subsetting to include only the necessary characters;
- configure correctly
@font-facewithfont-display: swap; - use preload only for critical fonts above the fold;
- set up adequate HTTP caching;
- test the result with PageSpeed Insights, Lighthouse and network waterfall.
To search for all fonts in a WordPress directory you can use:
find . -type f ( -iname "*.woff" -o -iname "*.woff2" -o -iname "*.ttf" -o -iname "*.otf" )
To generate WOFF2 subsets in bulk from all WOFF files in the current directory:
for f in *.woff; do
base="${f%.woff}"
pyftsubset "$f"
--output-file="${base}-subset.woff2"
--flavor=woff2
--layout-features='*'
--unicodes="U+0020-007E,U+00A0-00FF"
done
Conclusion
Font optimization is one of the most underrated web performance interventions. Unlike other, more complex tasks, such as database tuning, backend optimization, or architectural modifications, reducing font weight is often relatively simple, measurable, and immediate.
The real-world example with the Gordita files clearly demonstrates the potential of this intervention. The WOFF to WOFF2 conversion alone reduced the overall file size from 251 KB to 192 KB. Subsetting brought the total down to just 69 KB, an overall saving of over 70% compared to the original files.
This type of optimization is particularly useful on WordPress and WooCommerce sites, where themes, builders, and plugins can introduce a lot of unnecessary typographic resources. However, the principle is universal: every CMS, framework, or web application benefits from serving fewer bytes, fewer variants, and more efficient formats.
In a web increasingly oriented towards perceived speed, the quality of the user experience and Core Web VitalsFonts can no longer be considered a secondary aesthetic detail. They must be treated as truly critical resources, to be analyzed, compressed, subsetted, cached, and served as efficiently as possible.
Optimizing fonts improves loading times, reduces traffic, makes rendering more stable, and offers a better user experience. And, as the numbers show, a few Linux commands and proper CSS configuration are often enough to achieve very tangible results.