Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Drawing text to HTML5 with @fontface does not work at the first time
Drawing text in an HTML5 canvas with a typeface loaded via @font-face often fails to display correctly on the first render. This occurs because the browser has not yet fully loaded the custom font from the network, causing it to fall back to a default system font instead.
The key issue is timing − the canvas attempts to draw text before the custom font has finished downloading and becomes available to the rendering engine.
Syntax
Following is the basic syntax for defining a custom font with @font-face −
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2'),
url('font.woff') format('woff');
}
To use the font in canvas drawing −
context.font = '16px CustomFont';
context.fillText('Hello World', x, y);
Preloading Fonts with Hidden Elements
One simple solution is to preload the font by creating a hidden element that uses the custom font. This forces the browser to download and prepare the font before canvas rendering begins.
Example
<!DOCTYPE html>
<html>
<head>
<title>Font Preloading with Hidden Div</title>
<style>
@font-face {
font-family: 'PressStart';
src: url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
}
.font-preloader {
font-family: 'PressStart', monospace;
position: absolute;
left: -9999px;
visibility: hidden;
}
</style>
</head>
<body style="font-family: Arial, sans-serif; padding: 10px;">
<div class="font-preloader">Preload font</div>
<canvas id="myCanvas" width="400" height="150" style="border: 1px solid #ccc;"></canvas>
<script>
setTimeout(function() {
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.font = '20px PressStart, monospace';
ctx.fillStyle = '#333';
ctx.fillText('Custom Font Text', 50, 80);
}, 100);
</script>
</body>
</html>
The hidden div forces the browser to load the PressStart font, making it available when the canvas draws text.
Using the FontFace API
The modern approach uses the FontFace API to programmatically load fonts and wait for them to be ready before drawing to the canvas.
Example
<!DOCTYPE html>
<html>
<head>
<title>FontFace API Example</title>
</head>
<body style="font-family: Arial, sans-serif; padding: 10px;">
<canvas id="myCanvas" width="400" height="150" style="border: 1px solid #ccc;"></canvas>
<p id="status">Loading font...</p>
<script>
var customFont = new FontFace('CustomFont', 'url(https://fonts.gstatic.com/s/pressstart2p/v8/e3t4euO8T-267oIAQAu6jDQyK3nVivM.woff2)');
customFont.load().then(function(font) {
document.fonts.add(font);
document.getElementById('status').textContent = 'Font loaded successfully!';
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.font = '16px CustomFont';
ctx.fillStyle = '#2c3e50';
ctx.fillText('FontFace API Success!', 50, 80);
}).catch(function(error) {
document.getElementById('status').textContent = 'Font loading failed: ' + error;
});
</script>
</body>
</html>
This approach ensures the font is fully loaded before attempting to draw text, preventing fallback font issues.
Using Document.fonts.ready Promise
Another reliable method is to wait for all fonts to be loaded using the document.fonts.ready promise.
Example
<!DOCTYPE html>
<html>
<head>
<title>Document Fonts Ready</title>
<style>
@font-face {
font-family: 'MyFont';
src: url('https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu4mxP.woff2') format('woff2');
}
</style>
</head>
<body style="font-family: Arial, sans-serif; padding: 10px;">
<canvas id="myCanvas" width="400" height="150" style="border: 1px solid #ccc;"></canvas>
<p id="status">Waiting for fonts...</p>
<script>
document.fonts.ready.then(function() {
document.getElementById('status').textContent = 'All fonts ready!';
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.font = '18px MyFont, sans-serif';
ctx.fillStyle = '#e74c3c';
ctx.fillText('All fonts loaded and ready!', 50, 80);
});
</script>
</body>
</html>
This method waits for all @font-face declarations to complete loading before proceeding with canvas operations.
Comparison of Methods
| Method | Pros | Cons |
|---|---|---|
| Hidden Div Preloading | Simple, works in older browsers | Less reliable, adds DOM elements |
| FontFace API | Precise control, promise-based | Limited browser support (IE not supported) |
| document.fonts.ready | Waits for all fonts, clean syntax | Modern browsers only, waits for all fonts |
Best Practices
To ensure reliable font loading for canvas text rendering −
-
Always wait for fonts − Never draw text immediately after page load without ensuring fonts are ready.
-
Provide fallbacks − Include fallback fonts in your font-family declaration (e.g.,
'CustomFont', Arial, sans-serif). -
Use font-display − Add
font-display: swap;to @font-face rules for better loading behavior. -
Test loading states − Always test how your canvas behaves during font loading periods.
Conclusion
Custom fonts in HTML5 canvas require proper loading management to avoid display issues. Use the FontFace API or document.fonts.ready promise for modern browsers, or implement hidden element preloading for broader compatibility. Always ensure fonts are fully loaded before rendering text to canvas.
