Frontend Development 15 min read

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.

Bilibili Tech
Bilibili Tech
Bilibili Tech
Font2svg: Converting Fonts to SVG for Efficient Web Rendering

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].y

Metrics 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.

frontendPythonweb performanceSVGFont Renderingfont2svg
Bilibili Tech
Written by

Bilibili Tech

Provides introductions and tutorials on Bilibili-related technologies.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.