เครื่องมือสำหรับเฟรมเวิร์กสำหรับแบบอักษรสำรอง

Janicklas Ralph James
Janicklas Ralph James

เว็บไซต์ที่โหลดแบบอักษรโดยใช้ font-display: Swap มักพบปัญหาการเปลี่ยนเลย์เอาต์ (CLS) เมื่อเว็บฟอนต์โหลดขึ้นมาและถูกสลับกับแบบอักษรสำรอง

คุณป้องกัน CLS ได้โดยการปรับขนาดของแบบอักษรสำรองให้ตรงกับแบบอักษรหลัก พร็อพเพอร์ตี้อย่าง size-adjust, ascent-override, descent-override และ line-gap-override ในกฎ @font-face จะช่วยลบล้างเมตริกของแบบอักษรสำรองซึ่งทำให้นักพัฒนาซอฟต์แวร์ควบคุมวิธีแสดงแบบอักษรได้มากขึ้น อ่านข้อมูลเพิ่มเติมเกี่ยวกับแบบอักษรสำรองและพร็อพเพอร์ตี้การลบล้างได้ในโพสต์นี้ ดูการติดตั้งใช้งานเทคนิคนี้ได้ในการสาธิตนี้

บทความนี้จะสำรวจวิธีใช้การปรับขนาดแบบอักษรในเฟรมเวิร์ก Next.js และ Nuxt.js เพื่อสร้าง CSS แบบอักษรสำรองและลด CLS และยังแสดงวิธีการสร้างแบบอักษรสำรองโดยใช้เครื่องมือตัดข้ามกัน เช่น Fontaine และ Capsize

ข้อมูลเบื้องต้น

โดยทั่วไปแล้ว font-display: Swap จะใช้เพื่อป้องกัน FOIT (Flash ของข้อความที่มองไม่เห็น) และเพื่อแสดงเนื้อหาบนหน้าจอได้เร็วขึ้น ค่าของ swap จะบอกเบราว์เซอร์ว่าระบบควรแสดงข้อความที่ใช้แบบอักษรทันทีโดยใช้แบบอักษรของระบบ และจะแทนที่แบบอักษรของระบบเมื่อแบบอักษรที่กำหนดเองพร้อมใช้งานเท่านั้น

ปัญหาที่ใหญ่ที่สุดของ swap คือผลกระทบที่น่าสะเทือนใจ ซึ่งความแตกต่างของขนาดตัวอักษรของแบบอักษรทั้ง 2 แบบส่งผลให้เนื้อหาบนหน้าจอเปลี่ยนไปมา ซึ่งทำให้ได้คะแนน CLS ต่ำ โดยเฉพาะสำหรับเว็บไซต์ที่มีข้อความจำนวนมาก

รูปภาพต่อไปนี้แสดงตัวอย่างปัญหา ภาพแรกใช้ font-display: swap โดยไม่ต้องพยายามปรับขนาดของแบบอักษรสำรอง ส่วนที่ 2 แสดงให้เห็นว่าการปรับขนาดโดยใช้กฎ @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 ใน Next.js เวอร์ชัน 13 คอมโพเนนต์จะมี 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 กับ sans-serif ตามลำดับ)

สำหรับ @next/font/local: ค่าสตริงหรือบูลีนเท็จที่กำหนดว่าควรใช้แบบอักษรสำรองอัตโนมัติเพื่อลดการเปลี่ยนเลย์เอาต์สะสมหรือไม่ ค่าที่เป็นไปได้คือ Arial, Times New Roman หรือ false โดยมีค่าเริ่มต้นเป็น Arial หากคุณต้องการใช้แบบอักษร Serif ให้พิจารณาตั้งค่านี้เป็น Times New Roman

อีกตัวเลือกหนึ่งสำหรับ Google Fonts

หากไม่มีตัวเลือกการใช้คอมโพเนนต์ next/font อีกวิธีหนึ่งในการใช้ฟีเจอร์นี้กับ Google Fonts คือการใช้ Flag optimizeFonts Next.js เปิดใช้ฟีเจอร์ OptimizeFonts ไว้แล้วโดยค่าเริ่มต้น ฟีเจอร์นี้รองรับ Google Font CSS ในการตอบสนอง HTML นอกจากนี้ คุณยังเปิดใช้ฟีเจอร์การปรับแบบอักษรสำรองได้โดยการตั้งค่าแฟล็ก experimental.adjustFontFallbacksWithSizeAdjust ใน next.config.js ดังที่แสดงในข้อมูลโค้ดต่อไปนี้

// In next.config.js
module.exports = {
 experimental: {
   adjustFontFallbacksWithSizeAdjust: true,
 },
}

หมายเหตุ: เรายังไม่มีแผนที่จะรองรับฟีเจอร์นี้กับไดเรกทอรี app ที่เพิ่งแนะนำ คุณควรใช้ 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 และอนุมานรายละเอียดได้โดยอัตโนมัติ เช่น ชุดแบบอักษร ชุดแบบอักษรสำรอง และประเภทการแสดงผล

หากมีการกำหนดแบบอักษรไว้ในตำแหน่งที่โมดูลไม่สามารถค้นพบได้ คุณสามารถส่งข้อมูลเมตริกดังที่แสดงในข้อมูลโค้ดต่อไปนี้

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

สมมติว่าคุณมีแบบอักษร 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;
}

Fontaine กับตัวแปลงสัญญาณ Vite และ Webpack เพื่อเสียบเข้ากับห่วงโซ่บิลด์อย่างง่ายดายโดยเปิดใช้ปลั๊กอินดังที่แสดงใน 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

  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));

กิตติกรรมประกาศ

ภาพหลักโดย Alexander Andrews ใน Unsplash