DEV Community

Sam Sheridan
Sam Sheridan

Posted on

Shrink Your Font Awesome Bundle by 98% with Automatic Icon Subsetting

Tired of shipping 800KB+ of Font Awesome fonts when you only use a handful of icons? Here's a tool that automatically detects which icons you're actually using and creates tiny subset fonts.

The Problem

Font Awesome is brilliant, but it comes with a performance cost. When you include the full FA webfonts, browsers download the entire font file even if you only use a few icons. That means:

  • FA6 Solid: ~345KB
  • FA6 Duotone: ~458KB
  • Total payload: Often over 1MB including CSS

Your users pay this cost on every page load, especially painful on mobile connections.

The Solution: fa-subset

I built fa-subset to solve this exact problem. It's a Python tool that:

  1. Scans your codebase to find all fa-* classes you actually use
  2. Detects Font Awesome styles (solid, duotone, brands, etc.) automatically
  3. Creates tiny subset fonts containing only the icons you need
  4. Generates optimised CSS that references the subset fonts

Real Results

Here's what happened on a production site:

Before:  803 KB fonts + CSS (~1.29 MB total)
After:   14.5 KB fonts + CSS (~0.50 MB total)
Savings: 98.2% reduction in font size, 61% total payload reduction
Enter fullscreen mode Exit fullscreen mode

Key Features

Works with FA5 & FA6 (all styles: solid, regular, light, thin, duotone, brands, sharp)

Handles complex selectors like .fa-duotone.fa-house:after

Duotone support with proper dual codepoint handling

Multi-pack subsetting (separate optimised fonts per style)

Dry-run reports with detailed breakdown

Works with minified CSS and any file extensions

Quick Start

Prerequisites

pip install fonttools
Enter fullscreen mode Exit fullscreen mode

Basic Usage

  1. Dry run to see what will be optimised:
python3 bin/fa-subset.py \
  --src ./src ./templates \
  --ext .html .php .twig .js \
  --pack solid:css=./css/fontawesome.min.css,font=./fonts/fa-solid-900.ttf \
  --pack duotone:css=./css/duotone.min.css,font=./fonts/fa-duotone-900.ttf \
  --out ./optimised \
  --dry-run
Enter fullscreen mode Exit fullscreen mode
  1. Generate subset fonts (remove --dry-run):
python3 bin/fa-subset.py \
  --src ./src ./templates \
  --ext .html .php .twig .js \
  --pack solid:css=./css/fontawesome.min.css,font=./fonts/fa-solid-900.ttf \
  --pack duotone:css=./css/duotone.min.css,font=./fonts/fa-duotone-900.ttf \
  --out ./optimised
Enter fullscreen mode Exit fullscreen mode
  1. Include the optimised CSS:
<link rel="stylesheet" href="/optimised/solid/fontawesome.solid.subset.min.css">
<link rel="stylesheet" href="/optimised/duotone/fontawesome.duotone.subset.min.css">
Enter fullscreen mode Exit fullscreen mode

Smart Detection

The tool intelligently handles:

Mixed content:

<i class="fa-solid fa-house"></i>           <!-- Solid pack -->
<i class="fa-duotone fa-user"></i>          <!-- Duotone pack -->
<i class="fas fa-search"></i>               <!-- FA5 alias → solid -->
<span class="fa-brands fa-github"></span>   <!-- Brands pack -->
Enter fullscreen mode Exit fullscreen mode

Complex selectors in CSS:

.fa-duotone.fa-house:after { content: "\f015\f015"; } /* Duotone dual codepoints */
.custom-icon.fa-solid.fa-star { /* Custom styling */ }
Enter fullscreen mode Exit fullscreen mode

Dynamic content with proper fallbacks:

// The tool finds icons even in JS template strings
const iconHtml = `<i class="fa-solid fa-${iconName}"></i>`;
Enter fullscreen mode Exit fullscreen mode

Advanced Features

JSON Reports for CI/CD

--report-json ./report.json --strict-styles
Enter fullscreen mode Exit fullscreen mode

Perfect for CI pipelines to catch style conflicts:

{
  "conflicts": [
    {"file": "nav.html", "line": 42, "icon": "user", "styles": ["solid", "duotone"]}
  ],
  "packs": {
    "solid": {"icons_found": ["house", "user"], "codepoints": ["U+F015", "U+F007"]}
  }
}
Enter fullscreen mode Exit fullscreen mode

Composer Integration

Add these scripts to your composer.json:

{
  "scripts": {
    "fa-analyse": "python3 bin/fa-subset.py --src ./src --pack solid:css=./css/fontawesome.min.css,font=./fonts/fa-solid-900.ttf --out ./optimised --dry-run",
    "fa-optimise": "python3 bin/fa-subset.py --src ./src --pack solid:css=./css/fontawesome.min.css,font=./fonts/fa-solid-900.ttf --out ./optimised"
  }
}
Enter fullscreen mode Exit fullscreen mode

Then simply run:

composer fa-analyse   # See what will be optimised
composer fa-optimise  # Generate the subset fonts
Enter fullscreen mode Exit fullscreen mode

Performance Impact

The difference is dramatic:

Before (Full FA6):

  • First Contentful Paint: slower due to font loading
  • Lighthouse Performance Score: penalised for large resources
  • Mobile users: significant bandwidth usage

After (Subset):

  • Faster initial page loads
  • Better Lighthouse scores
  • Happier mobile users
  • Reduced CDN costs

Best Practices

  1. Cache aggressively: Serve subset fonts with long Cache-Control headers
  2. Use compression: Enable Brotli/gzip on your server
  3. One style per icon: Don't mix fa-solid and fa-duotone on the same element
  4. Run in CI: Use --strict-styles to catch conflicts early

Common Use Cases

WordPress themes:

--src ./wp-content/themes/mytheme --ext .php
Enter fullscreen mode Exit fullscreen mode

React/Vue projects:

--src ./src --ext .js .jsx .vue .tsx
Enter fullscreen mode Exit fullscreen mode

Laravel applications:

--src ./resources/views ./app --ext .blade.php .php
Enter fullscreen mode Exit fullscreen mode

Troubleshooting

Icons show as squares?

  • Ensure you're including the subset CSS, not the original
  • Check the Network tab - the subset .woff2 should load
  • Verify CORS headers if serving from a CDN

"No icon rules found in CSS"?

  • Use all.min.css or per-style CSS files (e.g., solid.min.css)
  • The CSS must contain icon mappings, not just variables

Why This Matters

Font optimisation often gets overlooked, but it's one of the highest-impact performance wins you can achieve. With fa-subset, you get:

  • Massive file size reductions (90%+ typical)
  • Faster page loads especially on mobile
  • Better Core Web Vitals scores
  • Reduced bandwidth costs
  • Zero maintenance once set up

Get Started

Repository: fa-subset on GitHub

Licence: BSD-2-Clause (bring your own FA licence)

The tool includes comprehensive documentation, examples, and CI integration guides. Give it a try on your next project - your users (and Lighthouse scores) will thank you!


Made by Sam Sheridan at Sheridan Internet. Not affiliated with Font Awesome/Fonticons Inc.

Tags

fontawesome #performance #webdev #optimization #fonts #css #python #opensource

Top comments (0)