How does icon fonts work?
Icon fonts are fonts that contain symbols and glyphs instead of letters and numbers. They work much like regular fonts but display icons instead of text characters. Here's how they work and how they're used:
Font File
An icon font is a
.ttf
,
.woff
, or
.eot
file that contains vector shapes (icons) mapped to
Unicode characters (just like how "A" maps to a
specific shape in a text font).
Character Mapping
Each icon is assigned to a character code (e.g.,
\e900
). When you type or reference that character in
HTML/CSS, the font renders the corresponding icon.
Usage in HTML
You include the font file via CSS (@font-face
) or through a service like Font Awesome. Then,
you display an icon using HTML tags like
<i>
or
<span>
and a specific class.
Styling with CSS
Since icon fonts are text, you can style them with
typical CSS properties:
color
,
font-size
,
text-shadow
,
transform
, etc.
Assume you're using Font Awesome:
html<!-- Include the icon font CSS --> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> <!-- Use an icon --> <i class="fas fa-camera"></i>
This renders a camera icon. The class
fas
tells the browser to use the solid style of Font
Awesome, and
fa-camera
refers to the camera icon mapped within the font.
Lightweight: One file can include hundreds of icons.
Scalable: Since icons are vector-based, they look sharp at any size.
Style with CSS: Easy to recolor, resize, or animate.
Accessibility: Theyβre text-based but may not be readable by screen readers unless handled properly.
Complex Mapping: Mapping icons to characters can be confusing without documentation.
Outdated: Modern alternatives like SVG icons or icon components (React, Vue) are now more popular due to better accessibility and styling flexibility.
Would you like to see how to create a custom icon font from your own SVG icons?
Creating your own icon font from a few SVG files is very doable and can be summarized in a few steps. Hereβs a step-by-step guide using free tools, including some optional enhancements.
Make sure each icon is a clean, single-path SVG (preferably with a viewBox).
Name them clearly (e.g.,
home.svg
,
user.svg
,
settings.svg
).
Go to https://icomoon.io/app
Click "Import Icons" and upload your SVG files.
Select the icons you uploaded.
Click "Generate Font" at the bottom.
Click "Download" the generated font package.
You'll get a
.zip
file containing:
.woff
,.ttf
,.eot
,.svg
font files
style.css
with class names
demo.html
to preview and test your icons
Include the CSS in your HTML:
html<link rel="stylesheet" href="fonts/style.css">
Use icons like this:
html<span class="icon-home"></span> <span class="icon-user"></span>
Class names are based on your original file names.
Since theyβre fonts, you can style with regular CSS:
css.icon-home { font-size: 24px; color: #333; }
Fontello: http://fontello.com β similar to IcoMoon
Glyphter: https://glyphter.com β drag-and-drop interface
Transfonter: https://transfonter.org β good for converting fonts, not SVGs specifically, but useful in workflow
Use
aria-hidden="true"
and
aria-label
if icons convey meaning.
html<span class="icon-user" aria-hidden="true"></span> <span class="sr-only">User Settings</span>
Would you like help creating an actual icon font set if you send me some SVG files?
To create an icon font programmatically from SVG files, you can use Node.js tools that automate the process. The most popular tool is:
webfont
This is a Node.js library that takes SVG files and
generates font files (.woff
, .ttf
,
.eot
,
etc.) along with optional CSS/HTML.
bashnpm init -y npm install webfont --save-dev
generate-font.js
)
jsconst webfont = require('webfont').default; const fs = require('fs'); webfont({ files: 'icons/*.svg', // your SVG icons fontName: 'custom-icons', dest: 'dist/fonts', template: 'css', // can also be 'html', 'scss', etc. }).then((result) => { // Write font files for (const [filename, content] of Object.entries(result)) { if (filename !== 'config') { fs.writeFileSync(`dist/fonts/${filename}`, content); } } console.log('Icon font generated successfully!'); }).catch((err) => { console.error('Error:', err); });
/icons - home.svg - user.svg - settings.svg
bashnode generate-font.js
This will output:
/dist/fonts - custom-icons.woff - custom-icons.ttf - custom-icons.css - etc.
You can now use it in HTML:
html<link rel="stylesheet" href="fonts/custom-icons.css"> <i class="icon-home"></i>
You can pass options like:
jsfontName: 'my-icons', templateClassName: 'icon', templateFontPath: './fonts/', cssFontsUrl: 'fonts/'
fantasticon
β CLI/Node.js tool with config support
svgicons2svgfont
+
svg2ttf
β Lower-level control
Would you like a ready-to-run example project (zip or GitHub-style structure)?
Yes, you heard right β icon fonts struggle with stroke-only SVG icons, and this is a well-known limitation. Here's a clear explanation of why this happens and what to do about it:
Icon fonts (like all fonts) render only filled vector paths. They do not preserve stroke properties like:
stroke-width
stroke-linecap
stroke-linejoin
stroke
color
If your SVG icon is composed only of strokes (lines), once converted into a font glyph:
The strokes disappear
Or get converted into very thin filled paths, often invisible
You need to convert strokes to filled paths (also called "expand stroke" or "outline stroke").
Open the SVG
Select the stroke
Go to
Path
>
Stroke to Path
Save/export the modified SVG
Select stroke paths
Choose
Object
>
Path
>
Outline Stroke
This turns strokes into filled shapes, which will work in font glyphs.
When designing icons for use as fonts:
Use filled shapes or combine strokes with fills
Flatten/expand strokes before generating fonts
Modern setups often favor SVG icons over icon fonts because:
SVG preserves strokes and styles
Better accessibility and styling control
You can inline SVG or use it via
<img>
or as a background
Feature | Icon Font | Inline SVG |
---|---|---|
Preserves strokes | β | β |
Fully styleable in CSS | β (limited) | β |
Accessibility-friendly | β οΈ | β |
Easy scaling | β | β |
Would you like a script or tool suggestion to batch-convert all your stroke-based SVGs to filled shapes?
Great! Here's how you can batch-convert stroke-only SVG icons into filled paths using Inkscape CLI β a reliable and scriptable tool that works on macOS, Linux, and Windows.
macOS (Homebrew):
bashbrew install --cask inkscape
Ubuntu/Linux:
bashsudo apt install inkscape
Windows:
Download from:
https://inkscape.org/release/
Hereβs a simple shell script that:
Takes all
.svg
files in a folder
Converts strokes to paths
Saves them in a new folder (out/
)
bash#!/bin/bash mkdir -p out for file in *.svg; do inkscape "$file" \ --actions="select-all;object-to-path;stroke-to-path;export-filename:out/$file;export-do" \ --export-type=svg done echo "Conversion complete. Output in ./out/"
Save as
convert-strokes.sh
, then:
bashchmod +x convert-strokes.sh ./convert-strokes.sh
select-all
β selects all elements
object-to-path
β converts shapes to path
stroke-to-path
β turns strokes into filled outlines
export-filename
and
export-do
β saves to output folder
If you need a cross-platform Node-based script, I can provide one using Puppeteer and Inkscape in headless mode β let me know.
In the GUI:
Use Inkscape > Extensions > Modify Path > Stroke to Path
Apply to all, save, repeat for each β slower but good for testing
Would you like me to package the shell script into a complete working folder for you?
Awesome β hereβs Option 2, a fully scriptable Node.js solution to batch convert stroke-only SVGs into filled-paths using Puppeteer (a headless Chromium browser) and Inkscapeβs GUI logic simulated.
Since Inkscape CLI doesn't always support detailed stroke manipulation across OSes, this method mimics user actions in a headless browser.
bashmkdir svg-stroke-converter cd svg-stroke-converter npm init -y npm install puppeteer
convert-svg-strokes.js
jsconst fs = require('fs'); const path = require('path'); const puppeteer = require('puppeteer'); const inputDir = path.resolve(__dirname, 'input'); const outputDir = path.resolve(__dirname, 'output'); if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir); (async () => { const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); const files = fs.readdirSync(inputDir).filter(f => f.endsWith('.svg')); for (const file of files) { const inputPath = path.join(inputDir, file); const outputPath = path.join(outputDir, file); const svg = fs.readFileSync(inputPath, 'utf8'); await page.setContent(svg); await page.evaluate(() => { const svg = document.querySelector('svg'); const ns = "http://www.w3.org/2000/svg"; function strokeToPath(el) { const bbox = el.getBBox(); const clone = el.cloneNode(true); // Convert stroke to outline approximation (basic fallback) clone.setAttribute('fill', el.getAttribute('stroke') || '#000'); clone.removeAttribute('stroke'); clone.removeAttribute('stroke-width'); svg.replaceChild(clone, el); } const paths = svg.querySelectorAll('[stroke]'); paths.forEach(el => strokeToPath(el)); }); const finalSvg = await page.content(); const cleanSvg = finalSvg .replace(/<!DOCTYPE[^>]*>/, '') .replace(/<html.*?>.*?<body.*?>/, '') .replace(/<\/body><\/html>/, '') .trim(); fs.writeFileSync(outputPath, cleanSvg); console.log(`Converted: ${file}`); } await browser.close(); })();
svg-stroke-converter/ βββ input/ β βββ your-stroke-icons.svg βββ output/ β generated icons βββ convert-svg-strokes.js
Put your SVG icons in the
input/
folder.
bashnode convert-svg-strokes.js
Output will be saved in the
output/
folder, with strokes replaced by filled shapes.
This uses a
visual approximation
method β not 100% precise like Illustrator or
Inkscape's
Stroke to Path
, but works well for simple icons.
If you want pixel-perfect conversion, I still recommend batch automating Inkscape or Illustrator with CLI access.
Would you like a downloadable
.zip
project with this setup ready to run?
Yes β there
is a Node.js package
for converting
strokes to paths
in SVGs more reliably and natively: π οΈ
svg-path-stroker
, plus a few supporting libraries.
However, there is
no single Node.js package that fully replicates
Inkscape's
stroke-to-path
precision
(e.g., variable stroke caps, joins, dash arrays). That
said, here are the best realistic options:
svg-path-stroker
Converts an
SVG
path
element with a stroke
into
two filled paths
approximating the stroke.
Designed for icon/font generation (used in Fontello).
Only works with
<path>
elements (not
<circle>
,
<line>
,
<rect>
, etc.)
No support for advanced stroke styles (e.g., round caps, dashes)
bashnpm install svg-path-stroker svgpath
jsconst stroker = require('svg-path-stroker'); const SvgPath = require('svgpath'); // Example stroke path const originalPath = new SvgPath('M10 10 H 90 V 90 H 10 Z'); const strokeWidth = 10; const outlined = stroker(originalPath.abs().toString(), strokeWidth, { join: 'miter', cap: 'butt', }); // `outlined` is a filled path string console.log('Outlined Path:', outlined);
svg2ttf
or
svgicons2svgfont
These libraries are used internally in icon font generators to flatten strokes into glyph-compatible filled paths, but they:
Expect already-clean path data
Work best after strokes are converted manually
As mentioned before,
Inkscapeβs CLI
(stroke-to-path
) is
still the most accurate method. You can call it from Node.js:
child_process
:
jsconst { execSync } = require('child_process'); const input = 'icons/home.svg'; const output = 'converted/home.svg'; execSync(`inkscape "${input}" --actions="select-all;stroke-to-path;export-filename:${output};export-do"`);
This gives you 100% accurate results with all SVG shapes and stroke styles.
Package/Method | Stroke-to-Path Quality | Shapes Supported | Ideal For |
---|---|---|---|
svg-path-stroker
|
Basic | Paths only | Icon fonts |
Inkscape CLI | β Best (full SVG spec) | All | Precision icons |
Puppeteer/DOM tricks | Medium (approximation) | Most | Lightweight fallback |
svgicons2svgfont
|
Indirect | After stroke fix | Font pipeline only |
Would you like a full working Node.js project that
wraps the
svg-path-stroker
logic for batch conversion?