אתרים שמטעינים גופנים באמצעות font-display: swap סובלים לעיתים קרובות מתזוזות בפריסת הדף (CLS) כשגופן ה-webfont נטען ומוחלף בגופן החלופי.
כדי למנוע CLS, אפשר לשנות את המאפיינים של גופן החלופה כך שיתאימו לאלה של הגופן הראשי. מאפיינים כמו size-adjust
, ascent-override
, descent-override
ו-line-gap-override
בכלל @font-face
יכולים לעזור לשנות את המדדים של גופן חלופי, וכך לתת למפתחים יותר שליטה על אופן הצגת הגופנים. מידע נוסף על גופנים חלופיים ועל נכסי ההחרגה זמין בפוסט הזה. אפשר גם לראות הטמעה פעילה של הטכניקה הזו בהדגמה הזו.
במאמר הזה נסביר איך מתבצעת ההטמעה של התאמות של גודל הגופן במסגרות Next.js ו-Nuxt.js כדי ליצור את קובץ ה-CSS של הגופן החלופי ולצמצם את הערך של CLS. בנוסף, תלמדו איך ליצור גופנים חלופיים באמצעות כלים חוצי-תחומים כמו Fontaine ו-Capsize.
רקע
בדרך כלל משתמשים ב-font-display: swap כדי למנוע FOIT (הבזק של טקסט בלתי נראה) ולהציג תוכן מהר יותר במסך. הערך של swap
מורה לדפדפן להציג טקסט עם הגופן באופן מיידי באמצעות גופן מערכת, ולהחליף את גופן המערכת רק כשהגופן המותאם אישית יהיה מוכן.
הבעיה הגדולה ביותר ב-swap
היא האפקט הבעייתי, שבו ההבדל בגודל התווים בשני הגופנים גורם לשינוי של תוכן המסך. המצב הזה מוביל לציוני CLS נמוכים, במיוחד באתרים שיש בהם הרבה טקסט.
בתמונות הבאות מוצגת דוגמה לבעיה. בתמונה הראשונה נעשה שימוש ב-font-display: swap
ללא ניסיון להתאים את הגודל של גופן החלופי. השנייה מראה איך שינוי הגודל באמצעות כלל ה-CSS @font-face
משפר את חוויית הטעינה.
בלי לשנות את גודל הגופן
body {
font-family: Inter, serif;
}
אחרי שינוי גודל הגופן
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");
}
התאמת הגודל של הגופן החלופי יכולה להיות אסטרטגיה יעילה למניעת שינוי הפריסה של טעינת הגופן, אבל הטמעת הלוגיקה מאפס יכולה להיות מסובכת, כפי שמתואר בפוסט הזה על חלופות של גופנים. למרבה המזל, בזמן פיתוח אפליקציות יש כמה אפשרויות לשימוש בכלים האלה.
איך לבצע אופטימיזציה של גופנים חלופיים באמצעות Next.js
ב-Next.js יש דרך מובנית להפעיל אופטימיזציה של גופן חלופי. התכונה הזו מופעלת כברירת מחדל כשאתם מעמיסים גופנים באמצעות הרכיב @next/font.
הרכיב @next/font הוצג ב-Next.js בגרסה 13. הרכיב מספק ממשק API לייבוא גופנים של Google או גופנים מותאמים אישית לדפים, וכולל אירוח עצמאי מובנה ואוטומטי של קובצי הגופנים.
כשמשתמשים במדדי הגופן החלופיים, הם מחושבים באופן אוטומטי ומוטמעים בקובץ ה-CSS.
לדוגמה, אם משתמשים בגופן Roboto, צריך להגדיר אותו ב-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;
}
body {
font-family: Roboto;
}
כדי לעבור ל-next/font:
כדי להעביר את ההצהרה על הגופן Roboto ל-JavaScript, מייבאים את הפונקציה Roboto מ-'next/font'. ערך ההחזרה של הפונקציה יהיה שם הכיתה שתוכלו להשתמש בו בתבנית הרכיב. חשוב לזכור להוסיף את
display: swap
לאובייקט התצורה כדי להפעיל את התכונה.import { Roboto } from '@next/font/google'; const roboto = Roboto({ weight: '400', subsets: ['latin'], display: 'swap' // Using display swap automatically enables the feature })
ברכיב, משתמשים בשם הכיתה שנוצר:
javascript export default function RootLayout({ children }: { children: React.ReactNode; }) { return ( <html lang="en" className={roboto.className}> <body>{children}</body> </html> ); }
אפשרות ההגדרה adjustFontFallback:
עבור @next/font/google
: ערך בוליאני שמגדיר אם המערכת תשתמש בגופן חלופי אוטומטי כדי לצמצם את המיקום המצטבר של הפריסה. ברירת המחדל היא True. מערכת Next.js מגדירה באופן אוטומטי את הגופן החלופי כ-Arial
או כ-Times New Roman
, בהתאם לסוג הגופן (serif לעומת sans-serif, בהתאמה).
עבור @next/font/local
: מחרוזת או ערך בוליאני False שקובעים אם צריך להשתמש בגופן חלופי אוטומטי כדי לצמצם את Cumulative Layout Shift (Cumulative Layout Shift). הערכים האפשריים הם Arial
, Times New Roman
או false
. ערך ברירת המחדל הוא Arial
. אם ברצונך להשתמש בגופן serif, מומלץ להגדיר את הערך הזה ל-Times New Roman
.
אפשרות נוספת לגופנים של Google
אם אי אפשר להשתמש ברכיב next/font
, אפשר להשתמש בדגל optimizeFonts
כדי להשתמש בתכונה הזו עם Google Fonts. התכונה optimizeFonts מופעלת כברירת מחדל ב-Next.js. התכונה הזו מחילה את ה-CSS של Google Font בתגובת ה-HTML. בנוסף, אפשר להפעיל את התכונה של התאמת גופנים חלופיים על ידי הגדרת הדגל experimental.adjustFontFallbacksWithSizeAdjust
בקובץ next.config.js, כפי שמוצג בקטע הקוד הבא:
// In next.config.js
module.exports = {
experimental: {
adjustFontFallbacksWithSizeAdjust: true,
},
}
הערה: לא מתוכננת תמיכה בתכונה הזו עם הגרסה החדשה של app
dir. בטווח הארוך, עדיף להשתמש ב-next/font
.
איך משנים את הגופנים החלופיים ב-Nuxt
@nuxtjs/fontaine הוא מודול למסגרת Nuxt.js שמחשב באופן אוטומטי את ערכי המדדים של גופן החלופי ויוצר את קובץ ה-CSS @font-face
החלופי.
כדי להפעיל את המודול, מוסיפים את @nuxtjs/fontaine
להגדרת המודולים:
import { defineNuxtConfig } from 'nuxt'
export default defineNuxtConfig({
modules: ['@nuxtjs/fontaine'],
})
אם אתם משתמשים ב-Google Fonts או שאין לכם הצהרה @font-face
לגבי גופן, אתם יכולים להצהיר עליהם כאפשרויות נוספות.
ברוב המקרים, המודול יכול לקרוא את הכללים של @font-face
מ-CSS ולהסיק באופן אוטומטי פרטים כמו font-family, משפחת הגופן החלופית וסוג התצוגה.
אם הגופן מוגדר במקום שלא ניתן לגילוי על ידי המודול, אפשר להעביר את פרטי המדדים כפי שמתואר בקטע הקוד הבא.
export default defineNuxtConfig({
modules: ['@nuxtjs/fontaine'],
fontMetrics: {
fonts: ['Inter', { family: 'Some Custom Font', src: '/path/to/custom/font.woff2' }],
},
})
המודול סורק את קובץ ה-CSS באופן אוטומטי כדי לקרוא את ההצהרות של @font-face וליצור את כללי ה-@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%;
}
עכשיו אפשר להשתמש ב-Roboto override
כגופן חלופי ב-CSS, כפי שמוצג בדוגמה הבאה
:root {
font-family: 'Roboto';
/* This becomes */
font-family: 'Roboto', 'Roboto override';
}
יצירת ה-CSS בעצמכם
ספריות עצמאיות יכולות גם לעזור לכם ליצור את ה-CSS לצורך התאמות של גודל הגופן החלופי.
שימוש בספרייה של Fontaine
אם אתם לא משתמשים ב-Nuxt או ב-Next.js, אתם יכולים להשתמש ב-Fontaine. Fontaine היא הספרייה הבסיסית שמפעילה את @nuxtjs/fontaine. אפשר להשתמש בספרייה הזו בפרויקט כדי להחדיר באופן אוטומטי CSS של גופן חלופי באמצעות יישומי פלאגין של Vite או Webpack.
נניח שבקובץ ה-CSS מוגדר גופן Roboto:
@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 יש טרנספורמטורים של Vite ו-Webpack שניתן לחבר בקלות לשרשרת ה-build. כדי להפעיל את הפלאגין, צריך להשתמש בקוד ה-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
}
אם אתם משתמשים ב-Vite, מוסיפים את הפלאגין כך:
javascript
// Vite
export default {
plugins: [FontaineTransform.vite(options)]
}
אם משתמשים ב-Webpack, מפעילים אותו באופן הבא:
// Webpack
export default {
plugins: [FontaineTransform.webpack(options)]
}
המודול יסרוק את הקבצים שלך באופן אוטומטי כדי לשנות את הכללים של @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%;
}
עכשיו אפשר להשתמש ב-Roboto override
כגופן חלופי ב-CSS.
css
:root {
font-family: 'Roboto';
/* This becomes */
font-family: 'Roboto', 'Roboto override';
}
שימוש בספרייה Capsize
אם אתם לא משתמשים ב-Next.js, ב-Nuxt, ב-Webpack או ב-Vite, אפשרות אחרת היא להשתמש בספריית Capsize כדי ליצור את קובץ ה-CSS החלופי.
ממשק ה-API החדש createFontStack
ה-API הוא חלק מהחבילה @capsize/core שנקראת createFontStack
, שמקבלת מערך של מדדי גופנים באותו סדר שבו אתם מציינים את מקבץ הגופנים (המאפיין font-family
).
כאן אפשר לעיין במסמכי התיעוד בנושא השימוש ב-Capsize.
דוגמה
דוגמה: גופן האינטרנט הרצוי הוא Lobster, והחלופה היא Helvetica Neue ואז Arial. ב-CSS, font-family: Lobster, 'Helvetica Neue', Arial
.
מייבאים את createFontStack מחבילת הליבה:
import { createFontStack } from '@capsizecss/core';
מייבאים את מדדי הגופן של כל אחד מהגופנים הרצויים (ראו 'מדדי גופן' למעלה):
javascript import lobster from '@capsizecss/metrics/lobster'; import helveticaNeue from '@capsizecss/metrics/helveticaNeue'; import arial from '@capsizecss/metrics/arial';`
יוצרים את מקבץ הגופנים, מעבירים את המדדים כמערך, לפי אותו סדר שבו מעבירים אותם באמצעות מאפיין ה-CSS font-family.
javascript const { fontFamily, fontFaces } = createFontStack([ lobster, helveticaNeue, arial, ]);
הפונקציה מחזירה את הערך הבא:
{
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%;
}
}
]
}
צריך להוסיף את הקוד fontFamily ו-fontFaces ל-CSS. הקוד הבא מראה איך מטמיעים אותו בגיליון סגנונות CSS או בתוך בלוק <style>
.
<style type="text/css">
.heading {
font-family:
}
</style>
הפקודה הזו תיצור את הקוד הבא ב-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%;
}
אפשר גם להשתמש בחבילה @capsize/metrics כדי לחשב את ערכי ההחרגה ולהחיל אותם על ה-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));