Optimize Fonts in Astro Apps with astro-font

Optimize local, Google, and CDN fonts in Astro with astro-font. Improve performance and manage fonts efficiently.

astro-font is an Astro integration designed to automatically optimize fonts within your Astro projects. Inspired by the font optimization techniques used in Next.js.

It handles custom fonts, local font files, fonts served via Content Delivery Networks (CDNs), and Google Fonts to improve your website’s performance. This tool draws

Features

⚙️ Automatic Optimization: Optimizes Google Fonts, local fonts, custom fonts, and fonts from CDNs.

🎨 CSS font-display Control: Allows configuration of the font-display property (e.g., swap, block).

🎯 Targeted Application: Apply fonts globally or to specific elements using CSS selectors (selector).

💾 Fallback Fonts: Automatically generates fallback font configurations.

☁️ Cloudflare Workers Support: Compatible with deployments to Cloudflare Workers with specific setup.

🔌 Multiple Font Sources: Handles various font types and sources within the same configuration.

🚀 Preloading: Supports font preloading for critical font files.

🔧 CSS Variables: Assign font families to CSS variables (cssVariable) for flexible usage.

🏷️ Custom Fallback Names: Define custom names for generated fallback font families (fallbackName).

📥 Dynamic Fetching: Option to fetch remote fonts during build time and serve them locally (fetch: true).

Use Cases

  • Edge Function Deployments: Use optimized fonts in Astro projects deployed to edge environments like Cloudflare Workers, following the provided compatibility steps.
  • Performance Improvement: Integrate astro-font to optimize font loading, reducing Cumulative Layout Shift (CLS) and improving Largest Contentful Paint (LCP) in Astro websites.
  • Self-Hosting Google Fonts: Easily download Google Fonts during the build process and self-host them for better performance or compliance requirements.
  • Local Font Management: Simplify the integration of custom local font files (.ttf, .woff2, etc.) stored within your project, complete with automatic @font-face generation and fallbacks.
  • Flexible Font Styling: Apply different fonts or font styles to various sections of your website using CSS selectors or CSS variables for precise typographic control.

Installation

# npm
npm install astro-font
# yarn
yarn add astro-font
# pnpm
pnpm add astro-font

Usage

Integrate astro-font into your Astro project by adding the AstroFont component to the <head> section of your layout or page.

Google Fonts (Direct URL)

Configure astro-font to use a Google Fonts URL directly.

---
// src/layouts/Layout.astro
import { AstroFont } from "astro-font";
---
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <title>My Astro Site</title>
  <AstroFont
    config={[
      {
        name: "Poppins",
        src: [], // Source array is empty when using googleFontsURL
        googleFontsURL: 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap',
        preload: true,
        display: "swap", // Overrides display property in Google Fonts URL if needed
        selector: "body", // Apply font to the body tag
        fallback: "sans-serif",
      },
    ]}
  />
</head>
<body>
  <slot />
</body>

Local Fonts

Reference font files stored locally within your project’s public directory or another accessible path.

---
// src/layouts/Layout.astro
import { join } from "node:path";
import { AstroFont } from "astro-font";
const isProd = import.meta.env.PROD;
// Adjust path based on environment (dev vs build) if needed, especially for SSR adapters
const fontBasePath = isProd ? '/' : join(process.cwd(), "public");
---
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <title>My Astro Site</title>
  <AstroFont
    config={[
      {
        name: "MyLocalFont",
        src: [
          {
            style: 'normal',
            weight: '400',
            // Use join for robust path construction
            path: join(fontBasePath, 'fonts', 'MyLocalFont-Regular.woff2')
          },
          {
            style: 'bold',
            weight: '700',
            path: join(fontBasePath, 'fonts', 'MyLocalFont-Bold.woff2')
          },
        ],
        preload: true,
        display: "swap",
        selector: ".content", // Apply font to elements with class 'content'
        fallback: "arial, sans-serif",
      },
    ]}
  />
</head>
<body>
  <main class="content">
    <slot />
  </main>
</body>

Multiple Fonts & Configuration

Define multiple font configurations within the config array. You can mix Google Fonts and local fonts. Use selector for applying via CSS class/selector or cssVariable for usage with CSS variables.

---
// src/layouts/Layout.astro
import { join } from "node:path";
import { AstroFont } from "astro-font";
---
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <title>My Astro Site</title>
  <AstroFont
    config={[
      {
        name: "Poppins",
        src: [],
        googleFontsURL: 'https://fonts.googleapis.com/css2?family=Poppins:wght@400&display=swap',
        preload: true,
        display: "swap",
        selector: "body", // Apply Poppins to body
        fallback: "sans-serif",
      },
      {
        name: "Inter",
        src: [
          {
            weight: '400',
            style: 'normal',
            path: join(process.cwd(), 'public', 'fonts', 'Inter-Regular.ttf')
          }
        ],
        preload: false,
        display: "swap",
        fallback: "verdana, sans-serif",
        cssVariable: "font-inter", // Define CSS variable --font-inter
        fallbackName: "Inter Fallback Custom" // Custom name for fallback font stack
      },
    ]}
  />
  <style>
    h1 {
      /* Example usage of the CSS variable */
      font-family: var(--font-inter);
    }
  </style>
</head>
<body>
  <h1>Heading uses Inter via CSS Variable</h1>
  <p>Body text uses Poppins via selector.</p>
  <slot />
</body>

Dynamic Fetching

To automatically fetch remote fonts (like Google Fonts) during the build and serve them locally, set fetch: true in the font configuration and add the astroFont integration to your astro.config.mjs.

// Example config in Layout.astro
<AstroFont
  config={[
    {
      src: [],
      name: 'Roboto',
      googleFontsURL: 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap',
      preload: true,
      display: 'swap',
      fallback: 'sans-serif',
      fetch: true, // Enable fetching
      // Optional: cacheDir: '.font-cache' // Specify cache directory
    },
  ]}
/>
// astro.config.mjs
import { defineConfig } from 'astro/config';
import { astroFont } from 'astro-font/integration';
export default defineConfig({
  // ... other config
  integrations: [
    astroFont() // Add the integration
  ]
});

This setup downloads the fonts specified in googleFontsURL into a local directory (default .fonts or specified by cacheDir) and includes them in your build output, modifying the CSS to point to these local copies.

Related Resources

FAQs

Q: How does astro-font improve website performance?
A: astro-font helps performance by automatically generating efficient @font-face rules, enabling font preloading, providing control over font-display to reduce layout shifts, and facilitating self-hosting which can improve load times compared to external font providers.

Q: Can I use astro-font with custom fonts not hosted on Google Fonts?
A: Yes, you can use astro-font with local font files (like .ttf, .otf, .woff, .woff2) stored in your project or fonts hosted on any CDN by providing the correct path or URL in the src configuration.

Q: Does astro-font work with Astro’s SSR mode on Cloudflare?
A: Yes, astro-font can work with Astro SSR on Cloudflare Pages. You need to enable the nodejs_compat flag in your Cloudflare settings and configure Vite to externalize Node.js built-ins as detailed in the astro-font documentation. For local fonts in this setup, ensure paths correctly reference the CDN URL in production builds.

Q: What is the difference between using selector and cssVariable?
A: The selector option directly applies the font family (including fallbacks) to elements matching the CSS selector you provide. The cssVariable option defines a CSS custom property (variable) containing the font family stack, which you can then apply manually using font-family: var(--your-variable-name); in your CSS.

Q: How does the fetch: true option work?
A: When fetch: true is set for a font configuration (typically used with googleFontsURL), the astro-font integration automatically downloads the specified font files during the build process. It saves them locally and updates the CSS to reference these self-hosted files instead of the original remote URLs.

rishi-raj-jain

rishi-raj-jain

Leave a Reply

Your email address will not be published. Required fields are marked *