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ù sui font-fallback 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. Ciò comporta punteggi CLS scadenti, in particolare 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 regola CSS @font-face
migliora l'esperienza di caricamento regolando le dimensioni.
Senza modificare le dimensioni dei caratteri
body {
font-family: Inter, serif;
}
Dopo aver modificato 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 regolazione delle dimensioni del carattere di riserva può essere una strategia efficace per evitare il cambiamento del layout durante il caricamento dei caratteri, ma l'implementazione della logica da zero può essere complicata, 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à è 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 Google Fonts o caratteri personalizzati nelle tue pagine e include l'hosting autonomo automatico dei file dei caratteri.
Se vengono utilizzate, le metriche dei caratteri di riserva vengono calcolate automaticamente e inserite 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 della funzione sarà un nome di classe che puoi utilizzare nel modello del 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
: una stringa o un valore booleano falso che imposta se deve essere utilizzato un carattere di riserva automatico per ridurre il Cumulative Layout Shift. I valori possibili sono Arial
, Times New Roman
o false
. Il valore predefinito è Arial
. Se vuoi utilizzare un carattere con grazie, valuta la possibilità di impostare questo valore su Times New Roman
.
Un'altra opzione per i caratteri Google
Se non puoi utilizzare il componente next/font
, un altro approccio per utilizzare questa funzionalità con Google Fonts è tramite il flag optimizeFonts
. In Next.js la funzionalità optimizeFonts è già attivata per impostazione predefinita. Questa funzionalità inserisce il CSS di Google Fonts 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 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 della dimensione dei caratteri di riserva.
Utilizzare la libreria Fontaine
Se non utilizzi Nuxt o Next.js, puoi utilizzare Fontaine. Fontaine è la libreria di base alla base di @nuxtjs/fontaine. Puoi utilizzare questa libreria nel tuo progetto per iniettare automaticamente il CSS del carattere di riserva 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 da collegare facilmente alla catena di build. Attiva 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, attivalo 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
Prendi in considerazione il seguente esempio: il carattere web desiderato è Lobster, con fallback su Helvetica Neue e poi Arial. In CSS, font-family: Lobster, 'Helvetica Neue', Arial
.
Importa createFontStack dal pacchetto di base:
import { createFontStack } from '@capsizecss/core';
Importa le metriche dei caratteri per ciascuno dei caratteri che ti interessano (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 autonomamente 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));