I siti che caricano i caratteri con font-display: swap spesso presentano una variazione del layout (CLS) quando il carattere web viene caricato e vengono scambiati con il carattere di riserva.
Per evitare CLS, puoi regolare le dimensioni del carattere di riserva in modo che corrispondano a quelle del carattere principale. Proprietà quali size-adjust
, ascent-override
, descent-override
e line-gap-override
nella regola @font-face
possono aiutare a sostituire le metriche di un carattere di riserva, offrendo agli sviluppatori un maggiore controllo sul modo in cui i caratteri vengono visualizzati. Puoi trovare ulteriori informazioni sui font di riserva e sulle proprietà di override in questo post. Puoi anche vedere un'implementazione funzionante di questa tecnica in questa demo.
Questo articolo spiega come vengono implementate le modifiche delle dimensioni del carattere nei framework Next.js e Nuxt.js per generare il carattere CSS di fallback e ridurre il valore CLS. Inoltre, ci spiega come generare caratteri di fallback utilizzando strumenti di taglio incrociato come Fontaine e Capsize.
Sfondo
font-display: swap viene generalmente utilizzato per evitare il flash di testo invisibile (FOIT) 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 del sistema solo quando il carattere personalizzato è pronto.
Il problema principale di swap
è l'effetto irritante, per cui la differenza nelle dimensioni dei caratteri dei due caratteri fa sì che i contenuti dello schermo si spostino. 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 regolare 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 che semplificano questa operazione durante lo sviluppo delle app.
Come ottimizzare i caratteri di riserva con Next.js
Next.js offre un modo integrato per abilitare 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 in Next.js versione 13. Il componente fornisce un'API per importare caratteri Google o caratteri personalizzati nelle tue pagine e include l'hosting automatico integrato 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 nel tuo JavaScript importando il file "Roboto" da "next/font". Il valore restituito della 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 specifica se deve essere utilizzato un carattere di riserva automatico per ridurre il valore 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 con serif e senza grazie).
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
. Next.js ha 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 aggiustamento dei caratteri di riserva impostando il flag experimental.adjustFontFallbacksWithSizeAdjust
nel file 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 la nuova directory app
. Nel lungo periodo, è consigliabile 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 della metrica del carattere 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 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 tuo CSS e dedurre automaticamente dettagli come 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 trasmettere le informazioni sulle metriche come mostrato 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 esegue automaticamente la scansione del tuo CSS per leggere le dichiarazioni @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 autonomamente il CSS
Le librerie autonome possono anche aiutarti a generare il CSS per gli aggiustamenti delle dimensioni dei caratteri di riserva.
Utilizzo della libreria Fontaine
Se non usi Nuxt o Next.js, puoi usare Fontaine. Fontaine è la libreria sottostante alla base di @nuxtjs/fontaine. Puoi utilizzare questa libreria nel tuo progetto per inserire automaticamente i caratteri CSS di fallback utilizzando i plug-in Vite o Webpack.
Immagina di avere 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 in questo modo:
javascript
// Vite
export default {
plugins: [FontaineTransform.vite(options)]
}
Se utilizzi Webpack, abilitalo 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 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 relative ai 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
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 sui caratteri per ciascuno dei caratteri desiderati (vedi Metriche sui caratteri sopra):
javascript import lobster from '@capsizecss/metrics/lobster'; import helveticaNeue from '@capsizecss/metrics/helveticaNeue'; import arial from '@capsizecss/metrics/arial';`
Crea lo stack di caratteri, passando le metriche come array, seguendo lo stesso ordine che seguiresti 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 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>
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));
Ringraziamenti
Immagine hero di Alexander Andrews su Unsplash.