{"id":363179,"date":"2022-02-17T07:21:41","date_gmt":"2022-02-17T15:21:41","guid":{"rendered":"https:\/\/css-tricks.com\/?p=363179"},"modified":"2022-02-17T07:21:44","modified_gmt":"2022-02-17T15:21:44","slug":"subsetting-font-awesome-to-improve-performance","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/subsetting-font-awesome-to-improve-performance\/","title":{"rendered":"Subsetting Font Awesome to Improve Performance"},"content":{"rendered":"\n
Font Awesome<\/a> is an incredibly popular icon library. Unfortunately, it\u2019s somewhat easy to use in a way that results in less-than-ideal performance. By subsetting Font Awesome, we can remove any unused glyphs from the font files it provides. This will reduce the number of bytes transmitted over the wire, and improve performance.<\/p>\n\n\n\n Let\u2019s subset fonts together in a Font Awesome project to see the difference it makes. As we go, I\u2019ll assume you\u2019re importing the CSS file Font Awesome provides, and using its web fonts to display icons.<\/p>\n\n\n\n\n\n\n For the sake of demonstration, I have nothing but an HTML file that imports Font Awesome\u2019s base CSS file<\/a>. To get a reasonable sample of icons, I\u2019ve listed out each one that I use on one of my side projects.<\/p>\n\n\n\n Here\u2019s what our HTML file looks like in the browser before subsetting fonts:<\/p>\n\n\n\n Here\u2019s a look at DevTool\u2019s Network tab to see what\u2019s coming down.<\/p>\n\n\n\n Now let\u2019s see how many bytes our font files take to render all that.<\/p>\n\n\n We want to see what the most straightforward, least performant use of Font Awesome looks like. In other words, we want the slowest possible implementation with no optimization. I\u2019m importing the As we saw above, the gzipped file weighs in at 33.4KB, which isn\u2019t bad at all. Unfortunately, when we peek into DevTool\u2019s Font tab, things get a little worse.<\/p>\n\n\n\n While font files are not as expensive a resource for your browser to handle as JavaScript<\/a>, those are still bytes your browser needs to pull down, just for some little icons. Consider that some of your users might be browsing your site on mobile, away from a strong or fast internet connection.<\/p>\n\n\n Font Awesome\u2019s main stylesheet contains definitions for literally thousands of icons. But what if we only need a few dozen at most? Surely we could trim out the unneeded stuff?<\/p>\n\n\n\n There are many tools out there that will analyze your code, and remove unused styles from a stylesheet<\/a>. I happen to be using PurifyCSS<\/a>. While this library isn\u2019t actively maintained anymore, the idea is the same, and in the end, this isn\u2019t the solution we\u2019re looking for. But let\u2019s see what happens when we trim our CSS down to only what\u2019s needed, which we can do with this script:<\/p>\n\n\n\n And when we load that newly built CSS file, our CSS bytes over the wire drop quite a bit, from 33KB to just 7.1KB!<\/p>\n\n\n\n But unfortunately, our other Font Awesome font files are unchanged.<\/p>\n\n\n\n What happened? PurifyCSS did its job. It indeed removed the CSS rules for all the unused icons. Unfortunately, it wasn\u2019t capable of reaching into the actual font files<\/strong> to trim down the glyphs, in addition to the CSS rules.<\/p>\n\n\n\n If only there was a tool like PurifyCSS that handles font files\u2026<\/p>\n\n\n There are, of course, tools that are capable of removing unused content from font files, and they\u2019re called subsetters<\/strong>. A subsetter<\/dfn> analyzes your webpage, looks at your font files, and trims out the unused characters. There are a bunch of tools for subsetting fonts out there, like Zach Leatherman\u2019s Glyphhanger<\/a>. As it turns out, subsetting Font Awesome is pretty straightforward because it ships its own built-in subsetters. Let\u2019s take a look.<\/p>\n\n\n The auto subsetting and manual subsetting tools I\u2019m about to show you require a paid Font Awesome<\/a> Pro subscription<\/a>.<\/p>\n\n\n\n Font Awesome allows you to set up what it calls kits<\/strong>, which are described in the Font Awesome docs<\/a> as a \u201cknapsack that carries all the icons and awesomeness you need in a neat little lightweight bundle you can sling on the back of your project with ease.\u201d So, rather than importing any and every CSS file, a kit gives you a single script tag you can add to your HTML file\u2019s Creating a kit takes about a minute. You\u2019re handed script tag that looks something like this:<\/p>\n\n\n\n When the script loads, we now have no CSS files at all, and the JavaScript file is a mere 4KB. Let\u2019s look again at the DevTools Fonts tab to see which font files are loaded now that we’ve done some subsetting.<\/p>\n\n\n\n We\u2019ve gone from 757KB down to 331KB. That\u2019s a more than 50% reduction<\/strong>. But we can still do better than that, especially if all we\u2019re rendering is 54 icons. That’s where Font Awesome\u2019s manual font subsetter comes into play.<\/p>\n\n\n Wouldn\u2019t it be nice if Font Awesome gave us a tool to literally pick the exact icons we wanted, and then provide a custom build for that<\/em>? Well, they do. They don\u2019t advertise this too loudly for some reason, but they actually have a desktop application exactly for subsetting fonts manually. The app is available to download from their site<\/a> \u2014 but, like the automatic subsetter, this app requires a paid Font Awesome subscription to actually use.<\/p>\n\n\n\n Search the icons, choose the family, add what you want, and then click the big blue Build<\/strong> button. That\u2019s really all it takes to generate a custom subset of Font Awesome icons.<\/p>\n\n\n\n Once you hit the button, Font Awesome will ask where it should save your custom build, then it dumps a ZIP file that contains everything you need. In fact, the structure you\u2019ll get is exactly the same as the normal Font Awesome download, which makes things especially simple. And naturally, it lets you save the custom build as a project file so you can open it back up later to add or remove icons as needed.<\/p>\n\n\n\n We\u2019ll open up DevTools to see the final size of the icons we\u2019re loading, but first, let\u2019s look at the actual font files themselves. The custom build creates many different types, depending on what your browser uses. Let\u2019s focus on the And what about the CSS file? It slims down to just 8KB. With gzip, it\u2019s only 2KB!<\/p>\n\n\n\n Here\u2019s the final tally in DevTools:<\/p>\n\n\n\n Before we go, take a quick peek at those font filenames. The That\u2019s why our CSS file looks a little bigger in the DevTools Network tab than the 2KB we saw before on disk. The tradeoff is that most of those font \u201cfiles\u201d from above aren\u2019t files at all, but rather Base64-encoded strings embedded right in this CSS file, saving us additional network requests.<\/p>\n\n\n\n All that said, Vite is inlining many different font formats that the browser will never use. But overall it\u2019s a pretty small number of bytes, especially compared to what we were seeing before.<\/p>\n\n\n\n Before leaving, if you\u2019re wondering whether that desktop font subsetting GUI tool comes in a CLI that can integrate with CI\/CD to generate these files at build time, the answer is\u2026 not yet. I emailed the Font Awesome folks, and they said something is planned. That’ll allow users to streamline their build process if and when it ships.<\/p>\n\n\n\nLet\u2019s set things up<\/h3>\n\n\n
<\/figure>\n\n\n\n
<\/figure>\n\n\n\nHere\u2019s our base case<\/h3>\n\n\n
all.min.css<\/code><\/a> file Font Awesome provides.<\/p>\n\n\n\n
First attempt using PurifyCSS<\/h3>\n\n\n
const purify = require(\"purify-css\");\n\nconst content = [\".\/dist\/**\/*.js\"]; \/\/ Vite-built content\n\npurify(content, [\".\/css\/fontawesome\/css\/all.css\"], {\n minify: true,\n output: \".\/css\/fontawesome\/css\/font-awesome-minimal-build.css\"\n});<\/code><\/pre>\n\n\n\n
<\/figure>\n\n\n\n
<\/figure>\n\n\n\nSubsetters to the rescue!<\/h3>\n\n\n
Subsetting fonts automatically<\/h3>\n\n\n
<head><\/code>, and from there, the kit only sends down the font glyphs you actually need from the font file.<\/p>\n\n\n\n<script src=\"https:\/\/kit.fontawesome.com\/xyzabc.js\" crossorigin=\"anonymous\"><\/script><\/code><\/pre>\n\n\n\n
<\/figure>\n\n\n\nSubsetting fonts manually<\/h3>\n\n\n
<\/figure>\n\n\n\n.woff2<\/code> files, which is what Chrome loads. The same light, regular, duotone, solid, and brand files that were there before are still in place, except this time no file is larger than 5KB\u2026 and that\u2019s before they\u2019re gzipped!<\/p>\n\n\n\n
<\/figure>\n\n\n\n
<\/figure>\n\n\n\nfa-light-300.woff2<\/code> font file is still there, but the others look different. That\u2019s because I\u2019m using<\/a> Vite<\/a> here, and it decided to automatically inline the font files into the CSS, since they’re so tiny.<\/p>\n\n\n\n
<\/figure>\n\n\n\n
<\/figure>\n\n\n\n
\n\n\n\n