Integrating custom typefaces into a Fabric.js environment requires managing the asynchronous nature of font loading. Since the canvas renders text immediately, accessing a font resource before it has fully downloaded will cause the browser to fall back to a default system font. To ensure visual consistency, the application must wait for the font to be available before instantiating or updating text objects.
Loading Fonts at Initialization
To apply a custom font when creating a text element, the font must be defined in CSS and loaded via JavaScript. The fontfaceobserver library provides a reliable way to detect when a font becomes available.
First, define the custom font using the standard CSS @font-face rule:
@font-face {
font-family: 'TechSans';
src: url('/static/fonts/TechSans.woff2') format('woff2');
}
Next, initialize the Fabric.js canvas and use FontFaceObserver to pause text creation until the font loads. This prevents the text from rendering with a fallback font initially.
<canvas id="design-canvas" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fontfaceobserver/2.1.0/fontfaceobserver.standalone.js"></script>
<script>
const canvas = new fabric.Canvas('design-canvas');
const fontLoader = new FontFaceObserver('TechSans');
fontLoader.load()
.then(() => {
const textElement = new fabric.IText('Hello World', {
left: 50,
top: 50,
fontFamily: 'TechSans',
fontSize: 48,
fill: '#333'
});
canvas.add(textElement);
})
.catch((error) => {
console.error('Font failed to load:', error);
});
</script>
Dynamic Font Switching
When building design editors, users often need to switch betweeen multiple typefaces dynamically. This requires ensuring the selected font is loaded before applying it to the active object.
Load the necessary fonts via CSS:
@font-face {
font-family: 'HeaderFont';
src: url('/static/fonts/HeaderFont.ttf');
}
@font-face {
font-family: 'BodyFont';
src: url('/static/fonts/BodyFont.woff');
}
The following logic handles font application. It checks if the font is ready and then updates the selected canvas object.
<button onclick="changeFont('HeaderFont')">Set Header Font</button>
<button onclick="changeFont('BodyFont')">Set Body Font</button>
<canvas id="editor-canvas" width="600" height="400"></canvas>
<script>
const editor = new fabric.Canvas('editor-canvas');
const initialText = new fabric.IText('Sample Text', {
left: 100,
top: 100,
fontSize: 32
});
editor.add(initialText);
function changeFont(fontName) {
const observer = new FontFaceObserver(fontName);
observer.load()
.then(() => {
const activeObject = editor.getActiveObject();
if (activeObject && activeObject.type === 'i-text') {
activeObject.set('fontFamily', fontName);
editor.requestRenderAll();
}
})
.catch(() => {
console.warn(`Font ${fontName} is not available.`);
});
}
</script>
Optimizing Font File Sizes
Font files can be large, wich may delay loading times and affect user experience. In scenarios where only specific characters or numbers are needed—such as a countdown timer or a specific logo—subsetting the font is a effective optimization technique.
Tools like Fontmin allow developers to extract only the necessary glyphs from a font file. By generating a minimized version containing just the required characters, the file size is drastically reduced, leading to faster load times and improved performance for the canvas application.