Introduction
Flutter web offers two renderers: HTML (default) and CanvasKit. CanvasKit provides pixel-perfect rendering that matches mobile, but it handles font loading differently. Custom fonts may fail to load in CanvasKit because the font files must be available as network resources that the Skia engine can download, and incorrect asset configuration or CORS issues can prevent fonts from rendering properly.
Symptoms
- Custom fonts display as default/Roboto on Flutter web but work on mobile
- Console error:
`- CanvasKit failed to load font: Roboto
`- Or:
`- Failed to load resource: the server responded with a status of 404 (Not Found)
- fonts/Roboto-Regular.ttf
`- Text renders as boxes or question marks
- Works with
--web-renderer=htmlbut fails with--web-renderer=canvaskit
Common Causes
- Font files not included in
pubspec.yamlassets section - Font file path case sensitivity mismatch (fonts folder vs Fonts folder)
- CORS policy blocking font file requests from CDN
- Font files are corrupted or in unsupported format
- CanvasKit font manifest not generated during build
Step-by-Step Fix
- 1.Verify font configuration in pubspec.yaml:
- 2.```yaml
- 3.flutter:
- 4.fonts:
- 5.- family: Roboto
- 6.fonts:
- 7.- asset: fonts/Roboto-Regular.ttf
- 8.- asset: fonts/Roboto-Bold.ttf
- 9.weight: 700
- 10.- asset: fonts/Roboto-Italic.ttf
- 11.style: italic
- 12.
` - 13.Verify font files exist at the specified paths:
- 14.```bash
- 15.ls fonts/
- 16.# Should show:
- 17.# Roboto-Regular.ttf
- 18.# Roboto-Bold.ttf
- 19.# Roboto-Italic.ttf
- 20.
` - 21.Build with canvaskit renderer and check output:
- 22.```bash
- 23.flutter build web --web-renderer canvaskit
- 24.# Check that fonts are in build output
- 25.ls build/web/assets/fonts/
- 26.
` - 27.If using a web server, ensure correct MIME types for fonts:
- 28.```nginx
- 29.# Nginx configuration
- 30.location ~* \.(ttf|ttc|otf|eot|woff|woff2)$ {
- 31.add_header Access-Control-Allow-Origin "*";
- 32.add_header Cache-Control "public, max-age=31536000";
- 33.}
- 34.
` - 35.Force CanvasKit renderer in index.html:
- 36.```html
- 37.<script>
- 38.var serviceWorkerVersion = null;
- 39.var scriptLoaded = false;
function loadMainDartJs() { if (scriptLoaded) return; scriptLoaded = true; const scriptTag = document.createElement('script'); scriptTag.src = 'main.dart.js'; scriptTag.type = 'application/javascript'; document.body.append(scriptTag); }
// Force CanvasKit window.flutterWebRenderer = "canvaskit"; </script> ```
- 1.Use flutter run with explicit renderer for testing:
- 2.```bash
- 3.flutter run -d chrome --web-renderer canvaskit --verbose
- 4.
` - 5.Look for font loading messages in the verbose output.
- 6.If fonts still fail, use a fallback strategy:
- 7.```dart
- 8.MaterialApp(
- 9.theme: ThemeData(
- 10.fontFamily: 'Roboto',
- 11.// Fallback font family for web
- 12.fontFamilyFallback: const ['Arial', 'Helvetica', 'sans-serif'],
- 13.),
- 14.)
- 15.
`
Prevention
- Test with both
--web-renderer=htmland--web-renderer=canvaskit - Always run
flutter build weband serve from a real server (not file://) - Configure web server with correct MIME types for font files
- Use
fontFamilyFallbackfor graceful degradation - Verify font files are not corrupted by opening them locally
- Use Google Fonts package for web-safe font loading:
- ```yaml
- dependencies:
- google_fonts: ^6.2.1
`