Font2svg: Converting Fonts to SVG for Efficient Web Rendering
Font2svg converts large font glyphs into on‑demand SVG paths using Python’s freetype‑py and svgpathtools, dramatically shrinking download size, speeding page loads, and improving user experience, with CDN‑served SVGs, a lightweight front‑end injector, and graceful fallback, as demonstrated by a 98 % size reduction in a Bilibili case study.
In web development, special fonts often exceed 4–10 MB, which degrades loading experience, especially on mobile networks. Common solutions include using image slices, loading the original font via @font-face, or using compressed font files, each with drawbacks.
The article introduces an innovative solution called Font2svg , which converts font glyphs to SVG paths on demand, dramatically reducing the amount of data transferred for dynamic text rendering.
Font Basics
The article explains fundamental concepts such as characters, character sets, encodings, font families, font styles, glyphs, metrics, and outlines, illustrating how a glyph’s shape is defined by vector outlines composed of line segments and Bézier curves.
Implementation Details
Font parsing is implemented in Python using freetype-py . The parser iterates over each glyph, extracts outline data via outline.decompose , and converts the resulting path segments into SVG paths with svgpathtools . The relevant callback functions are shown below:
outline.decompose(
context=None,
move_to=self.callbackMoveTo,
line_to=self.callbackLineTo,
conic_to=self.callbackConicTo,
cubic_to=self.callbackCubicTo,
)
def callbackMoveTo(self, *args):
self._verbose("MoveTo ", len(args), self.vectorsToPoints(args))
self._lastX, self._lastY = args[0].x, args[0].y
def callbackLineTo(self, *args):
self._verbose("LineTo ", len(args), self.vectorsToPoints(args))
line = Line(self.lastXyToComplex(), self.vectorToComplex(args[0]))
self.svg_paths.append(line)
self._lastX, self._lastY = args[0].x, args[0].y
def callbackConicTo(self, *args):
self._verbose("ConicTo", len(args), self.vectorsToPoints(args))
curve = QuadraticBezier(self.lastXyToComplex(), self.vectorToComplex(args[0]), self.vectorToComplex(args[1]))
self.svg_paths.append(curve)
self._lastX, self._lastY = args[1].x, args[1].y
def callbackCubicTo(self, *args):
self._verbose("CubicTo", len(args), self.vectorsToPoints(args))
curve = CubicBezier(
self.lastXyToComplex(),
self.vectorToComplex(args[0]),
self.vectorToComplex(args[1]),
self.vectorToComplex(args[2]),
)
self.svg_paths.append(curve)
self._lastX, self._lastY = args[2].x, args[2].yMetrics are used to compute an appropriate viewBox for each glyph:
def calcViewBox(self, metrics):
view_box_min_x = 0
view_box_min_y = -self.face.ascender
view_box_width = metrics.horiAdvance
view_box_height = self.face.ascender - self.face.descender
return f"{view_box_min_x} {view_box_min_y} {view_box_width} {view_box_height}"After obtaining the path and viewBox, the SVG is generated. Empty glyphs (e.g., spaces) are handled by creating a transparent placeholder path.
Front‑end Component
The generated SVGs are stored on a CDN and fetched by a lightweight front‑end component that injects the SVG markup into the DOM, then applies dynamic styles (color, underline, etc.) by modifying the fill attribute or adding custom JSON metadata on the root element.
Case Study
In a Bilibili “weekly keywords” page, the original implementation loaded a 2.8 MB font file. After switching to Font2svg, the total resource size dropped to 45 KB (≈98 % reduction), first‑screen load time decreased from 2268 ms to 1791 ms (‑21 %), and page bounce rate fell from 5.47 % to 3.11 %.
Fallback Strategy
If an SVG cannot be retrieved, the component falls back to the system default font. To keep underline styling consistent, the fallback renders underlines using the same pseudo‑element technique as the SVG path.
Conclusion
Font2svg converts font glyphs to SVG, dramatically reducing download size for dynamic special‑font text, improving load performance and user experience. The approach is applicable to both web and native clients, offering designers and developers a flexible solution for artistic fonts without the penalty of large font files.
Bilibili Tech
Provides introductions and tutorials on Bilibili-related technologies.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.