Strumenti di framework per i caratteri di riserva

Gianni Ralph James
Janicklas Ralph James

I siti che caricano i caratteri con font-display: swap spesso presentano una variazione del layout (CLS) quando il carattere web viene caricato e viene sostituito con il carattere di riserva.

Puoi impedire il CLS regolando le dimensioni del carattere di riserva in modo che corrispondano a quelle del carattere principale. Proprietà come size-adjust, ascent-override, descent-override e line-gap-override nella regola @font-face possono contribuire a sostituire le metriche di un carattere di riserva, consentendo agli sviluppatori di avere un maggiore controllo sulla modalità di visualizzazione dei caratteri. Per ulteriori informazioni sui caratteri di riserva e sulle proprietà di override, consulta questo post. Puoi anche vedere un'implementazione pratica di questa tecnica in questa demo.

Questo articolo illustra come le modifiche alle dimensioni dei caratteri vengono implementate nei framework Next.js e Nuxt.js per generare il CSS del carattere di riserva e ridurre la CLS. Dimostra inoltre come generare caratteri di riserva utilizzando strumenti trasversali come Fontaine e Capsize.

Contesto

font-display: swap viene generalmente utilizzato per impedire il flash di testo invisibile (FOIT) e per visualizzare i contenuti più velocemente sullo schermo. Il valore swap indica al browser che il testo che lo utilizza deve essere visualizzato immediatamente con un carattere di sistema e di sostituire il carattere di sistema solo quando il carattere personalizzato è pronto.

Il problema maggiore di swap è l'effetto sgradevole, in cui i contenuti sullo schermo cambiano a causa della differenza di dimensioni dei due caratteri. Ciò porta a punteggi CLS bassi, in particolare per i siti web con molto testo.

Le immagini seguenti mostrano un esempio del problema. La prima immagine utilizza font-display: swap senza alcun tentativo di regolare le dimensioni del carattere di riserva. Il secondo mostra come la modifica delle dimensioni con la regola @font-face CSS migliora l'esperienza di caricamento.

Senza modificare le dimensioni dei caratteri

body {
  font-family: Inter, serif;
}
Testo che cambia improvvisamente nel carattere e nelle dimensioni, causando un effetto sgradevole.

Dopo aver modificato le dimensioni del carattere

body {
  font-family: Inter, fallback-inter, serif;
  }

@font-face {
  font-family: "fallback-inter";
  ascent-override: 90.20%;
  descent-override: 22.48%;
  line-gap-override: 0.00%;
  size-adjust: 107.40%;
  src: local("Arial");
}
Testo con transizione fluida a un carattere diverso.

La modifica delle dimensioni del carattere di riserva può essere una strategia efficace per evitare la variazione del layout del caricamento dei caratteri, ma implementare la logica da zero può essere difficoltoso, come descritto in questo post sui caratteri di riserva. Fortunatamente, sono già disponibili diversi strumenti per semplificare questa operazione durante lo sviluppo delle app.

Come ottimizzare i caratteri di riserva con Next.js

Next.js fornisce un modo integrato per attivare l'ottimizzazione dei caratteri di riserva. Questa funzionalità viene attivata per impostazione predefinita quando carichi i caratteri utilizzando il componente @next/font.

Il componente @next/font è stato introdotto nella versione 13 di Next.js. Il componente fornisce un'API per importare i caratteri Google Fonts o i caratteri personalizzati nelle tue pagine e include l'auto-hosting automatica integrata dei file dei caratteri.

Se utilizzate, le metriche dei caratteri di riserva vengono calcolate e inserite automaticamente nel file CSS.

Ad esempio, se utilizzi un carattere Roboto, in genere lo definisci in CSS come segue:

@font-face {
  font-family: 'Roboto';
  font-display: swap;
  src: url('/fonts/Roboto.woff2') format('woff2'), url('/fonts/Roboto.woff') format('woff');
  font-weight: 700;
}

body {
  font-family: Roboto;
}

Per eseguire la migrazione al carattere successivo:

  1. Sposta la dichiarazione del carattere Roboto nel codice JavaScript importando la funzione "Roboto" da "next/font". Il valore restituito dalla funzione sarà un nome di classe che puoi utilizzare nel modello del componente. Ricordati di aggiungere display: swap all'oggetto di configurazione per abilitare la funzionalità.

     import { Roboto } from '@next/font/google';
    
    const roboto = Roboto({
      weight: '400',
      subsets: ['latin'],
      display: 'swap' // Using display swap automatically enables the feature
    })
    
  2. Nel componente, utilizza il nome della classe generato: javascript export default function RootLayout({ children }: { children: React.ReactNode; }) { return ( <html lang="en" className={roboto.className}> <body>{children}</body> </html> ); }

L'opzione di configurazione adjustFontFallback:

Per @next/font/google: un valore booleano che determina se utilizzare un carattere di riserva automatico per ridurre la metrica Cumulative Layout Shift. Il valore predefinito è true. Next.js imposta automaticamente il carattere di riserva su Arial o Times New Roman in base al tipo di carattere (rispettivamente serif o senza grazie).

Per @next/font/local: una stringa o un valore booleano false che stabilisce se un carattere di riserva automatico deve essere utilizzato per ridurre la metrica Cumulative Layout Shift. I valori possibili sono Arial, Times New Roman o false. Il valore predefinito è Arial. Se desideri utilizzare un font con grazie, valuta la possibilità di impostare questo valore su Times New Roman.

Un'altra opzione per Google Fonts

Se non è possibile usare il componente next/font, puoi ricorrere a un altro approccio per usare questa funzionalità con Google Fonts tramite il flag optimizeFonts. La funzionalità optimizeFonts è già attivata per Next.js per impostazione predefinita. Questa funzionalità integra il codice CSS di Google Font nella risposta HTML. Inoltre, puoi attivare la funzionalità di regolazione dei caratteri di riserva impostando il flag experimental.adjustFontFallbacksWithSizeAdjust nel file next.config.js, come illustrato nel seguente snippet:

// In next.config.js
module.exports = {
 experimental: {
   adjustFontFallbacksWithSizeAdjust: true,
 },
}

Nota: non è previsto il supporto di questa funzionalità con la nuova directory app. A lungo termine, è preferibile utilizzare next/font.

Come regolare i caratteri di riserva con Nuxt

@nuxtjs/fontaine è un modulo per il framework Nuxt.js che calcola automaticamente i valori delle metriche dei caratteri di riserva e genera il CSS @font-face di riserva.

Abilita il modulo aggiungendo @nuxtjs/fontaine alla configurazione dei moduli:

import { defineNuxtConfig } from 'nuxt'

export default defineNuxtConfig({
  modules: ['@nuxtjs/fontaine'],
})

Se utilizzi Google Fonts o non disponi di una dichiarazione @font-face per un carattere, puoi dichiararli come opzioni aggiuntive.

Nella maggior parte dei casi, il modulo può leggere le regole @font-face dal CSS e dedurre automaticamente dettagli quali la famiglia di caratteri, la famiglia di caratteri di riserva e il tipo di visualizzazione.

Se il carattere viene definito in una posizione non rilevabile dal modulo, puoi passare le informazioni sulle metriche come illustrato nel seguente snippet di codice.

export default defineNuxtConfig({
  modules: ['@nuxtjs/fontaine'],
  fontMetrics: {
  fonts: ['Inter', { family: 'Some Custom Font', src: '/path/to/custom/font.woff2' }],
},
})

Il modulo analizza automaticamente il tuo CSS per leggere le dichiarazioni di @font-face e genera le regole di riserva @font-face.

@font-face {
  font-family: 'Roboto';
  font-display: swap;
  src: url('/fonts/Roboto.woff2') format('woff2'), url('/fonts/Roboto.woff') format('woff');
  font-weight: 700;
}
/* This will be generated. */
@font-face {
  font-family: 'Roboto override';
  src: local('BlinkMacSystemFont'), local('Segoe UI'), local('Roboto'), local('Helvetica Neue'),
    local('Arial'), local('Noto Sans');
  ascent-override: 92.7734375%;
  descent-override: 24.4140625%;
  line-gap-override: 0%;
}

Ora puoi utilizzare Roboto override come carattere di riserva nel tuo CSS, come mostrato nell'esempio seguente

:root {
  font-family: 'Roboto';
  /* This becomes */
  font-family: 'Roboto', 'Roboto override';
}

Generare personalmente il CSS

Le librerie indipendenti possono anche aiutarti a generare il codice CSS per gli aggiustamenti delle dimensioni dei caratteri di riserva.

Utilizzo della libreria Fontaine

Se non utilizzi Nuxt o Next.js, puoi utilizzare Fontaine. Fontaine è la libreria sottostante che supporta @nuxtjs/fontaine. Puoi usare questa libreria nel tuo progetto per inserire automaticamente il CSS del carattere di riserva usando i plug-in Vite o Webpack.

Immagina di avere definito un carattere Roboto nel file CSS:

@font-face {
  font-family: 'Roboto';
  font-display: swap;
  src: url('/fonts/Roboto.woff2') format('woff2'), url('/fonts/Roboto.woff') format('woff');
  font-weight: 700;
}

Fontaine fornisce trasformatori Vite e Webpack da collegare facilmente alla catena di build. Abilita il plug-in come mostrato nel seguente codice JavaScript.

import { FontaineTransform } from 'fontaine'

const options = {
  fallbacks: ['BlinkMacSystemFont', 'Segoe UI', 'Helvetica Neue', 'Arial', 'Noto Sans'],
  // You may need to resolve assets like `/fonts/Roboto.woff2` to a particular directory
  resolvePath: (id) => 'file:///path/to/public/dir' + id,
  // overrideName: (originalName) => `${name} override`
  // sourcemap: false
}

Se utilizzi Vite, aggiungi il plug-in in questo modo: javascript // Vite export default { plugins: [FontaineTransform.vite(options)] }

Se utilizzi Webpack, attivalo come segue:

// Webpack
export default {
  plugins: [FontaineTransform.webpack(options)]
}

Il modulo eseguirà automaticamente la scansione dei tuoi file per modificare le regole di @font-face: css @font-face { font-family: 'Roboto'; font-display: swap; src: url('/fonts/Roboto.woff2') format('woff2'), url('/fonts/Roboto.woff') format('woff'); font-weight: 700; } /* This will be generated. */ @font-face { font-family: 'Roboto override'; src: local('BlinkMacSystemFont'), local('Segoe UI'), local('Roboto'), local('Helvetica Neue'), local('Arial'), local('Noto Sans'); ascent-override: 92.7734375%; descent-override: 24.4140625%; line-gap-override: 0%; }

Ora puoi usare Roboto override come carattere di riserva in CSS. css :root { font-family: 'Roboto'; /* This becomes */ font-family: 'Roboto', 'Roboto override'; }

Utilizzare la libreria di dimensioni maiuscole

Se non utilizzi Next.js, Nuxt, Webpack o Vite, un'altra opzione è quella di utilizzare la libreria Capsize per generare il CSS di riserva.

Nuova API createFontStack

L'API fa parte del pacchetto @capsize/core chiamato createFontStack, che accetta un array di metriche dei caratteri nello stesso ordine in cui specificheresti lo stack di caratteri (la proprietà font-family).

Puoi consultare la documentazione sull'utilizzo di Capsize qui.

Esempio

Prendiamo in considerazione il seguente esempio: il carattere web desiderato è Lobster, facendo riferimento a Helvetica Neue e poi a Firefox. Nel CSS, font-family: Lobster, 'Helvetica Neue', Arial.

  1. Importa createFontStack dal pacchetto principale:

    import { createFontStack } from '@capsizecss/core';
    
  2. Importa le metriche relative ai caratteri per ognuno dei caratteri che preferisci (consulta la sezione Metriche relativa ai caratteri qui sopra): javascript import lobster from '@capsizecss/metrics/lobster'; import helveticaNeue from '@capsizecss/metrics/helveticaNeue'; import arial from '@capsizecss/metrics/arial';`

  3. Crea il tuo stack di caratteri, passando le metriche sotto forma di array, utilizzando lo stesso ordine che faresti tramite la proprietà CSS font-family. javascript const { fontFamily, fontFaces } = createFontStack([ lobster, helveticaNeue, arial, ]);

che restituisce quanto segue:

{
  fontFamily: Lobster, 'Lobster Fallback: Helvetica Neue', 'Lobster Fallback: Arial',
  fontFaces: [
    {
      '@font-face' {
      'font-family': '"Lobster Fallback: Helvetica Neue"';
      src: local('Helvetica Neue');
      'ascent-override': '115.1741%';
      'descent-override': '28.7935%';
      'size-adjust': '86.8251%';
      }
     '@font-face' {
       'font-family': '"Lobster Fallback: Arial"';
       src: local('Arial');
       'ascent-override': 113.5679%;
       'descent-override': 28.392%;
       'size-adjust': 88.053%;
     }
   }
 ]
}

Devi aggiungere il codice fontFamily e fontFaces al tuo CSS. Il seguente codice mostra come implementarlo in un foglio di stile CSS o all'interno di un blocco <style>.

<style type="text/css">
  .heading {
    font-family: 
  }

  
</style>

Questo produrrà il seguente CSS:

.heading {
  font-family: Lobster, 'Lobster Fallback: Helvetica Neue',
    'Lobster Fallback: Arial';
}

@font-face {
  font-family: 'Lobster Fallback: Helvetica Neue';
  src: local('Helvetica Neue');
  ascent-override: 115.1741%;
  descent-override: 28.7935%;
  size-adjust: 86.8251%;
}
@font-face {
  font-family: 'Lobster Fallback: Arial';
  src: local('Arial');
  ascent-override: 113.5679%;
  descent-override: 28.392%;
  size-adjust: 88.053%;
}

Puoi anche utilizzare il pacchetto @capsize/metrics per calcolare i valori di override e applicarli personalmente al CSS.

const fontMetrics = require(`@capsizecss/metrics/inter`);
const fallbackFontMetrics = require(`@capsizecss/metrics/arial`);
const mainFontAvgWidth = fontMetrics.xAvgWidth / fontMetrics.unitsPerEm;
const fallbackFontAvgWidth = fallbackFontMetrics.xAvgWidth / fallbackFontMetrics.unitsPerEm;
let sizeAdjust = mainFontAvgWidth / fallbackFontAvgWidth;
let ascent = fontMetrics.ascent / (unitsPerEm * fontMetrics.sizeAdjust));
let descent = fontMetrics.descent / (unitsPerEm * fontMetrics.sizeAdjust));
let lineGap = fontMetrics.lineGap / (unitsPerEm * fontMetrics.sizeAdjust));

Ringraziamenti

Immagine hero di Alexander Andrews su Unsplash.