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=html but fails with --web-renderer=canvaskit

Common Causes

  • Font files not included in pubspec.yaml assets 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. 1.Verify font configuration in pubspec.yaml:
  2. 2.```yaml
  3. 3.flutter:
  4. 4.fonts:
  5. 5.- family: Roboto
  6. 6.fonts:
  7. 7.- asset: fonts/Roboto-Regular.ttf
  8. 8.- asset: fonts/Roboto-Bold.ttf
  9. 9.weight: 700
  10. 10.- asset: fonts/Roboto-Italic.ttf
  11. 11.style: italic
  12. 12.`
  13. 13.Verify font files exist at the specified paths:
  14. 14.```bash
  15. 15.ls fonts/
  16. 16.# Should show:
  17. 17.# Roboto-Regular.ttf
  18. 18.# Roboto-Bold.ttf
  19. 19.# Roboto-Italic.ttf
  20. 20.`
  21. 21.Build with canvaskit renderer and check output:
  22. 22.```bash
  23. 23.flutter build web --web-renderer canvaskit
  24. 24.# Check that fonts are in build output
  25. 25.ls build/web/assets/fonts/
  26. 26.`
  27. 27.If using a web server, ensure correct MIME types for fonts:
  28. 28.```nginx
  29. 29.# Nginx configuration
  30. 30.location ~* \.(ttf|ttc|otf|eot|woff|woff2)$ {
  31. 31.add_header Access-Control-Allow-Origin "*";
  32. 32.add_header Cache-Control "public, max-age=31536000";
  33. 33.}
  34. 34.`
  35. 35.Force CanvasKit renderer in index.html:
  36. 36.```html
  37. 37.<script>
  38. 38.var serviceWorkerVersion = null;
  39. 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. 1.Use flutter run with explicit renderer for testing:
  2. 2.```bash
  3. 3.flutter run -d chrome --web-renderer canvaskit --verbose
  4. 4.`
  5. 5.Look for font loading messages in the verbose output.
  6. 6.If fonts still fail, use a fallback strategy:
  7. 7.```dart
  8. 8.MaterialApp(
  9. 9.theme: ThemeData(
  10. 10.fontFamily: 'Roboto',
  11. 11.// Fallback font family for web
  12. 12.fontFamilyFallback: const ['Arial', 'Helvetica', 'sans-serif'],
  13. 13.),
  14. 14.)
  15. 15.`

Prevention

  • Test with both --web-renderer=html and --web-renderer=canvaskit
  • Always run flutter build web and serve from a real server (not file://)
  • Configure web server with correct MIME types for font files
  • Use fontFamilyFallback for 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
  • `