כלי מסגרת לחלופות של גופנים

Janicklas Ralph James
Janicklas Ralph James

באתרים שטוענים גופנים ב-font-display: exchange, יש בדרך כלל שינוי בפריסה (CLS) כשגופן האינטרנט נטען ומוחלף בגופן חלופי.

כדי למנוע CLS, אפשר לשנות את המידות של הגופן החלופי כך שיתאים לגודל הגופן הראשי. מאפיינים כמו size-adjust, ascent-override, descent-override ו-line-gap-override בכלל @font-face יכולים לעזור לבטל את המדדים של גופן חלופי כדי שלמפתחים תהיה יותר שליטה באופן הצגת הגופנים. בפוסט הזה תוכלו לקרוא מידע נוסף על חלופות גופנים ומאפייני שינוי מברירת המחדל. אפשר גם לראות איך השיטה הזו מיושמת, בהדגמה הזו.

במאמר הזה נבחן איך התאמות של גודל גופן מוטמעות ב-frameworks של Next.js ו-Nuxt.js כדי ליצור את שירות ה-CSS החלופי ולצמצם את ה-CLS. הוא גם מדגים איך אפשר ליצור גופנים חלופיים באמצעות כלי חיתוך לרוחב כמו Fontaine ו-Capsize.

רקע

font-display: Exchange משמש בדרך כלל למניעת FOIT (הבהוב של טקסט בלתי נראה) ולהצגה מהירה יותר של תכנים על המסך. הערך של swap מורה לדפדפן שהטקסט שמשתמש בגופן צריך להיות מוצג באופן מיידי באמצעות גופן מערכת, וכדי להחליף את גופן המערכת רק כשהגופן המותאם אישית מוכן.

הבעיה הגדולה ביותר ב-swap היא האפקט הבעייתי, שבו ההבדל בגודל התווים בשני הגופנים גורם לשינוי של תוכן המסך. המצב הזה מוביל לציוני CLS נמוכים, במיוחד באתרים שיש בהם הרבה טקסט.

בתמונות הבאות מוצגת דוגמה לבעיה. בתמונה הראשונה נעשה שימוש ב-font-display: swap ללא ניסיון לשנות את הגודל של הגופן החלופי. השיטה השנייה מראה איך שינוי הגודל באמצעות כלל @font-face של שירות ה-CSS משפרת את חוויית הטעינה.

בלי לשנות את גודל הגופן

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 נוסף בגרסה 13 של Next.js. הרכיב מספק ממשק API לייבוא גופנים של Google Fonts או גופנים מותאמים אישית לדפים שלך, והוא כולל אירוח עצמי מובנה של קובצי גופנים.

כשמשתמשים בו, מדדי הגופן החלופיים מחושבים באופן אוטומטי ומוחדרים לקובץ ה-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;
}

כדי לעבור ל'הבא'/'גופן':

  1. יש להעביר את הצהרת הגופן 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
    })
    
  2. ברכיב שלכם, משתמשים בשם המחלקה שנוצר: javascript export default function RootLayout({ children }: { children: React.ReactNode; }) { return ( <html lang="en" className={roboto.className}> <body>{children}</body> </html> ); }

אפשרות ההגדרה adjustFontFallback:

ב-@next/font/google: ערך בוליאני שקובע אם להשתמש בגופן חלופי אוטומטי כדי לצמצם את Cumulative Layout Shift. ברירת המחדל היא True. Next.js מגדיר אוטומטית את הגופן החלופי ל-Arial או ל-Times New Roman, בהתאם לסוג הגופן (serif לעומת San-serif בהתאמה).

עבור @next/font/local: מחרוזת או ערך בוליאני False שקובעים אם צריך להשתמש בגופן חלופי אוטומטי כדי לצמצם את המשתנה של הפריסה המצטברת. הערכים האפשריים הם Arial, Times New Roman או false. ערך ברירת המחדל הוא Arial. אם ברצונך להשתמש בגופן serif, מומלץ להגדיר את הערך הזה ל-Times New Roman.

אפשרות נוספת לגופנים של Google

אם אין אפשרות להשתמש ברכיב next/font, גישה נוספת לשימוש בתכונה הזו עם Google Fonts היא באמצעות הדגל optimizeFonts. התכונה OptimizeFonts כבר מופעלת כברירת מחדל. התכונה הזו מחילה את ה-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 או אין לכם הצהרת @font-face לגופן, אפשר להצהיר עליהם כאפשרויות נוספות.

ברוב המקרים, המודול יכול לקרוא את כללי @font-face משירות ה-CSS שלכם ולהסיק באופן אוטומטי את הפרטים, כמו משפחת הגופנים, משפחת הגופנים החלופיים וסוג התצוגה.

אם הגופן מוגדר במקום שאינו גלוי על ידי המודול, תוכלו להעביר את פרטי המדדים כפי שמוצג בקטע הקוד הבא.

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

אם אתם לא משתמשים ב-Next או ב-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
}

אם משתמשים ב-Vit, מוסיפים את הפלאגין כך: 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, שמופיע לאחר מכן ב-H האקינג Neue ולאחר מכן ב-Hello. ב-CSS, font-family: Lobster, 'Helvetica Neue', Arial.

  1. ייבוא createFontStack מחבילת הליבה:

    import { createFontStack } from '@capsizecss/core';
    
  2. מייבאים את מדדי הגופנים של כל אחד מהגופנים הרצויים (ראו למעלה בנושא מדדי גופנים): javascript import lobster from '@capsizecss/metrics/lobster'; import helveticaNeue from '@capsizecss/metrics/helveticaNeue'; import arial from '@capsizecss/metrics/arial';`

  3. יוצרים את מקבץ הגופנים ומעבירים את המדדים כמערך, לפי הסדר שבו עושים זאת דרך מאפיין ה-CSS של משפחת הגופנים. 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));

אישורים

תמונה ראשית (Hero) של Alexander Andrews ב-Unbounce.