Khi vẽ text lên canvas sử dụng font tải qua CSS @font-face, văn bản thường không hiển thị đúng font ở lần đầu tiên. Nguyên nhân: Trình duyệt chưa kịp tải xong font từ mạng trước khi code vẽ canvas chạy, nên nó dùng font fallback (thường là sans-serif mặc định).
Giải pháp 1: Preload font bằng thẻ <div> ẩn (Đơn giản, cũ)
Thêm một thẻ div ẩn sử dụng font đó để buộc trình duyệt tải font sớm:
<div style="font-family: 'PressStart'; position: absolute; left: -9999px; visibility: hidden;"> </div>
Đặt div này ở đầu <body>. Ký tự buộc trình duyệt render font.
Giải pháp 2: Font Loading API (Hiện đại, khuyên dùng)
Sử dụng FontFace và document.fonts để tải font và chờ sẵn sàng trước khi vẽ:
// Tạo FontFace object
var newFont = new FontFace('MyCustomFont', 'url(https://example.com/font.woff2)');
// Tải font
newFont.load().then(function(font) {
// Thêm font vào document
document.fonts.add(font);
console.log('Font tải xong, có thể vẽ canvas!');
// Bây giờ an toàn để vẽ text lên canvas
drawCanvasText();
}).catch(function(err) {
console.error('Lỗi tải font:', err);
});
// Hàm vẽ canvas
function drawCanvasText() {
var ctx = canvas.getContext('2d');
ctx.font = '24px MyCustomFont';
ctx.fillText('Hello Canvas!', 50, 50);
}
Giải pháp 3: document.fonts.ready (Đơn giản cho nhiều font)
// Chờ TẤT CẢ font trong document sẵn sàng
document.fonts.ready.then(function() {
console.log('Tất cả font đã sẵn sàng');
drawCanvasText();
});
Best Practice
- Sử dụng định dạng WOFF2 (nén tốt nhất, hỗ trợ rộng rãi).
- Khai báo
font-display: swaptrong @font-face để hiển thị font fallback ngay, swap khi font chính tải xong. - Preload font quan trọng trong
<head>:<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
- Luôn có font fallback trong CSS:
font-family: 'MyFont', Arial, sans-serif;