I siti che caricano i caratteri con font-display: swap spesso presentano una variazione del layout (CLS) quando il carattere web viene caricato e scambiato con il carattere di riserva.
Puoi evitare 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 essere utili per sostituire le metriche di un carattere di riserva, consentendo agli sviluppatori un maggiore controllo sulla modalità di visualizzazione dei caratteri. Puoi scoprire di più su font-fallbacks e sulle proprietà di override in questo post. Puoi anche vedere un'implementazione funzionante di questa tecnica in questa demo.
Questo articolo illustra come vengono implementati gli aggiustamenti delle dimensioni dei caratteri nei framework Next.js e Nuxt.js per generare il CSS del carattere di riserva e ridurre il CLS. Inoltre, mostra come generare caratteri di riserva utilizzando strumenti trasversali come Fontaine e Capsize.
Sfondo
font-display: swap viene generalmente utilizzato per evitare il FOIT (Flash of invisible text) e per visualizzare più velocemente i contenuti sullo schermo. Il valore swap
indica al browser che il testo che utilizza il carattere deve essere visualizzato immediatamente utilizzando un carattere di sistema e di sostituire il carattere di sistema solo quando il carattere personalizzato è pronto.
Il problema più grande di swap
è l'effetto visivo sgradevole, in cui la differenza nelle dimensioni dei caratteri dei due caratteri comporta lo spostamento dei contenuti sullo schermo. Questo si traduce in punteggi CLS scarsi, soprattutto per i siti web con molto testo.
Le seguenti immagini mostrano un esempio del problema. La prima immagine utilizza font-display: swap
senza alcun tentativo di modificare le dimensioni del carattere di riserva. Il secondo mostra come la regolazione delle dimensioni tramite la regola @font-face
CSS migliora l'esperienza di caricamento.
Senza modificare le dimensioni dei caratteri
body {
font-family: Inter, serif;
}
Dopo aver regolato le dimensioni dei caratteri
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");
}
La modifica delle dimensioni del carattere di riserva può essere una strategia efficace per evitare variazioni del layout del caricamento dei caratteri, ma implementare la logica da zero può essere complicato, come descritto in questo post sui caratteri di riserva. Fortunatamente, sono già disponibili diverse opzioni di 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à è attiva per impostazione predefinita quando carichi 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 Google Fonts o caratteri personalizzati nelle tue pagine e include l'hosting autonomo automatico dei file dei caratteri.
Se utilizzate, le metriche relative ai 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 a next/font:
Sposta la dichiarazione del carattere Roboto in JavaScript importando la funzione "Roboto" da "next/font". Il valore restituito dalla funzione sarà il nome di una classe che puoi utilizzare nel modello di componente. Ricorda di aggiungere
display: swap
all'oggetto di configurazione per attivare la funzionalità.import { Roboto } from '@next/font/google'; const roboto = Roboto({ weight: '400', subsets: ['latin'], display: 'swap' // Using display swap automatically enables the feature })
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 imposta se deve essere utilizzato un carattere di riserva automatico per ridurre il Cumulative Layout Shift. Il valore predefinito è true. Next.js imposta automaticamente il carattere di riserva su Arial
o Times New Roman
a seconda del tipo di carattere (rispettivamente serif o sans serif).
Per @next/font/local
: un valore di stringa o booleano false che specifica se deve essere utilizzato un carattere di riserva automatico per ridurre il valore Cumulative Layout Shift. I valori possibili sono Arial
, Times New Roman
o false
. Il valore predefinito è Arial
. Se vuoi utilizzare un carattere Serif, ti consigliamo di impostare questo valore su Times New Roman
.
Un'altra opzione per i caratteri Google
Se l'utilizzo del componente next/font
non è possibile, un altro approccio per utilizzare questa funzionalità con Google Fonts è il flag optimizeFonts
. In Next.js la funzionalità optimizeFonts è già attivata per impostazione predefinita. Questa funzionalità incorpora il CSS di Google Font nella risposta HTML. Inoltre, puoi attivare la funzionalità di regolazione dei caratteri di riserva impostando il flag experimental.adjustFontFallbacksWithSizeAdjust
in next.config.js, come mostrato nello snippet seguente:
// In next.config.js
module.exports = {
experimental: {
adjustFontFallbacksWithSizeAdjust: true,
},
}
Nota: non è previsto il supporto di questa funzionalità con il nuovo dir app
. A lungo termine, è ideale 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.
Attiva 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 hai 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 i dettagli come la famiglia di caratteri, la famiglia di caratteri di riserva e il tipo di visualizzazione.
Se il carattere è definito in un punto non rilevabile dal modulo, puoi passare le informazioni sulle metriche come mostrato nello snippet di codice seguente.
export default defineNuxtConfig({
modules: ['@nuxtjs/fontaine'],
fontMetrics: {
fonts: ['Inter', { family: 'Some Custom Font', src: '/path/to/custom/font.woff2' }],
},
})
Il modulo esegue automaticamente la scansione del codice CSS per leggere le dichiarazioni @font-face e genera le regole @font-face di riserva.
@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 il CSS autonomamente
Le librerie autonome possono anche aiutarti a generare il CSS per gli aggiustamenti delle dimensioni dei caratteri di riserva.
Utilizzare la libreria Fontaine
Se non usi Nuxt o Next.js, puoi usare Fontaine. Fontaine è la libreria di base alla base di @nuxtjs/fontaine. Puoi usare questa libreria nel tuo progetto per inserire automaticamente i caratteri CSS di fallback utilizzando i plug-in Vite o Webpack.
Immaginiamo che tu abbia un carattere Roboto definito 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 per collegarsi 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 come segue:
javascript
// Vite
export default {
plugins: [FontaineTransform.vite(options)]
}
Se utilizzi Webpack, abilitala come segue:
// Webpack
export default {
plugins: [FontaineTransform.webpack(options)]
}
Il modulo eseguirà automaticamente la scansione dei file per modificare le regole @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 utilizzare Roboto override
come carattere di riserva in CSS.
css
:root {
font-family: 'Roboto';
/* This becomes */
font-family: 'Roboto', 'Roboto override';
}
Utilizzo della libreria Capsize
Se non utilizzi Next.js, Nuxt, Webpack o Vite, un'altra opzione è utilizzare la libreria Capsize per generare il CSS di riserva.
Nuova API createFontStack
L'API fa parte del pacchetto @capsize/core denominato createFontStack
, che accetta un array di metriche dei caratteri nello stesso ordine in cui specificheresti la serie di caratteri (proprietà font-family
).
Puoi consultare la documentazione sull'utilizzo di Capsize qui.
Esempio
Considera l'esempio seguente: il carattere web desiderato è Lobster, con riferimento a HEMEA Neue e poi a Arial. In CSS, font-family: Lobster, 'Helvetica Neue', Arial
.
Importa createFontStack dal pacchetto principale:
import { createFontStack } from '@capsizecss/core';
Importa le metriche dei caratteri per ciascuno dei caratteri desiderati (vedi Metriche dei caratteri sopra):
javascript import lobster from '@capsizecss/metrics/lobster'; import helveticaNeue from '@capsizecss/metrics/helveticaNeue'; import arial from '@capsizecss/metrics/arial';`
Crea la tua serie di caratteri passando le metriche come array, utilizzando lo stesso ordine che utilizzeresti tramite la proprietà CSS font-family.
javascript const { fontFamily, fontFaces } = createFontStack([ lobster, helveticaNeue, arial, ]);
Viene restituito 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 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>
Verrà generato 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));