Converting SVGs into custom icon fonts sounds straightforward until you compile your first glyph set. You export ten clean icons from Figma or Illustrator, feed them into an icon font generator, and open the preview. Half the icons are upside down. Two icons have solid black fills where transparent cutouts should be. And one icon has blurry, clipped strokes.
If you have run into this, you are not alone. These issues are not random bugs in your font compiler; they stem from fundamental mathematical differences between how browser SVGs render vector coordinates and how OpenType/TrueType font engines parse glyph contours. Here is what actually breaks under the hood, and how to fix your vectors so they compile cleanly every time.
1. The Y-Axis Inversion Trap (Why Your Icons Turn Upside Down)
In modern web graphics, SVGs use a top-left origin:
(0,0) Converting SVGs into custom icon fonts sounds straightforward until you compile your first glyph set. You export ten clean icons from Figma or Illustrator, feed them into an icon font generator, and open the preview. Half the icons are upside down. Two icons have solid black fills where transparent cutouts should be. And one icon has blurry, clipped strokes.
If you have run into this, you are not alone. These issues are not random bugs in your font compiler; they stem from fundamental mathematical differences between how browser SVGs render vector coordinates and how OpenType/TrueType font engines parse glyph contours. Here is what actually breaks under the hood, and how to fix your vectors so they compile cleanly every time.
---
## 1. The Y-Axis Inversion Trap (Why Your Icons Turn Upside Down)
In modern web graphics, SVGs use a **top-left origin**:
(0,0) ------- +X
|
|
+Y
Increasing `y` values push coordinates downwards. TrueType and OpenType font systems use a **Cartesian bottom-left origin**:
+Y
|
|
(0,0) ------- +X
Increasing `y` values push coordinates upwards. When a compiler parses an SVG path like:
xml
It reads `(10, 20)` and `(50, 80)` as points in a Cartesian space unless the coordinate transform explicitly mirrors the Y-axis across the font's unit box. If your build pipeline or converter omits an affine matrix inversion (`scale(1, -1)` + `translate(0, -baseline)`), the glyph compiles upside down.
### The Fix
Before compiling, ensure your vector compiler normalizes coordinates against the standard Units Per Em (UPM) grid (typically **1000 UPM** or **1024 UPM**). If converting manually or via script, apply the vertical reflection transformation matrix:
plaintext
[x'] [1 0] [x] [ 0 ]
[y'] = [0 -1] [y] + [ascender]
---
## 2. Non-Zero Winding vs Even-Odd: The Black Cutout Problem
Ever convert a search icon or a badge with a hole in the middle, only to find the hole filled with solid black? This happens because SVGs often rely on `fill-rule="evenodd"`, whereas TrueType font interpreters rely strictly on the **Non-Zero Winding Rule**:
* **SVG `evenodd`:** Draws a ray from any point to infinity. If the ray crosses an odd number of path segments, the point is inside (filled). If even, it is outside (hollow). Path direction does not matter.
* **TrueType Non-Zero Rule:** Clockwise contours define solid shapes; counter-clockwise contours define holes (or vice versa depending on winding mode). If an inner circle and an outer circle in your SVG both travel clockwise, TrueType considers both of them solid fills. The hole disappears.
plaintext
SVG (Even-Odd) TrueType (Winding Order)
Outer: Clockwise Outer: Clockwise (+)
Inner: Clockwise Inner: Counter-Clockwise (-)
Result: Hole preserved Result: Hole preserved ONLY IF reversed!
### The Fix
In Figma or Illustrator, run **Outline Stroke** followed by **Simplify Path / Flatten**. Alternatively, run an SVG pre-processor or a dedicated client-side converter that normalizes path direction before generating TTF curves.
---
## 3. B## 3. Bezier Curve Degree Mismatch (Cubic vs Quadratic)
SVG paths use **Cubic Bezier curves** (`C` or `S` path commands): each segment has two control points (CP1 and CP2). TrueType fonts (`.ttf`) natively support **Quadratic Bezier curves**: each segment has only **one** control point (CP).
plaintext
SVG Cubic Curve: Start --- CP1 ------- CP2 --- End
TTF Quadratic Curve: Start ------- CP ------------ End
When converting Cubic to Quadratic:
1. The compiler must approximate every cubic curve by splitting it into multiple quadratic arcs.
2. If your SVG has redundant anchor points, sub-pixel curves, or complex clipping masks, this approximation explodes in size and introduces visual artifacts.
### Rules for Clean Conversion:
* Convert all strokes to outlined fills (`stroke-width` is ignored by font glyph tables).
* Keep your viewbox square (e.g., `24x24`, `32x32`, or `512x512`).
* Strip hidden `<defs>`, empty `<clipPath>`, and inline styling before compiling.
---
## 4. Production `@font-face` Integration
Once compiled to `.ttf` and converted to `.woff2` for web delivery, load your custom icon font with `font-display: block` to prevent layout shift:
css
@font-face {
font-family: 'DevOmniIcons';
src: url('/fonts/devomni-icons.woff2') format('woff2'),
url('/fonts/devomni-icons.ttf') format('truetype');
font-weight: normal;
font-style: normal;
font-display: block;
}
.icon {
font-family: 'DevOmniIcons', sans-serif;
speak: never;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Individual Glyphs mapped via Unicode PUA (Private Use Area) */
.icon-search:before { content: "\e900"; }
.icon-terminal:before { content: "\e901"; }
.icon-lock:before { content: "\e902"; }
Using the Unicode Private Use Area (`\e900` to `\f8ff`) prevents screen readers from trying to pronounce random alphanumeric characters when encountering icons.
---
## Testing Your SVGs in the Browser
If you need to batch-convert SVG icons into `.ttf` or `.woff2` without uploading your proprietary vectors to third-party cloud servers, test them directly in-browser:
-> **[SVG to Font Converter (Free & Private) - DevOmniTools](https://www.devomnitools.com/en/tools/svg-to-font/)**
It handles Y-axis inversion, path winding normalization, and 1000 UPM grid scaling entirely in client-side memory. You get instant live previews and copy-pasteable CSS code.
Top comments (0)