Narzędzia platformy do tworzenia zastępczych czcionek

Janicklas Ralph James
Janicklas Ralph James

W witrynach, które wczytują czcionki za pomocą funkcji font-display: swap, często występuje przesunięcie układu (CLS) podczas wczytywania czcionki internetowej i zastąpiona czcionką zastępczą.

Możesz zapobiec CLS, dostosowując wymiary czcionki zastępczej w celu dopasowania jej do czcionki podstawowej. Właściwości takie jak size-adjust, ascent-override, descent-override i line-gap-override w regule @font-face mogą pomóc zastąpić dane czcionki zastępczej i umożliwić deweloperom większą kontrolę nad sposobem wyświetlania czcionek. Więcej informacji o wartościach zastępczych czcionek i właściwościach ich zastępowania znajdziesz w tym poście. Możesz również zobaczyć działającą implementację tej techniki w tej prezentacji.

W tym artykule opisujemy, jak w platformach Next.js i Nuxt.js wdrażane są korekty rozmiaru czcionki w celu generowania CSS czcionki zastępczej i zmniejszania CLS. Narzędzie pokazuje też, jak generować czcionki zastępcze za pomocą narzędzi do krojenia, takich jak Fontaine i Capsize.

Wprowadzenie

Atrybut font-display: swap służy zwykle do zapobiegania FOIT (Flash of niewidocznego tekstu) i szybszego wyświetlania treści na ekranie. Wartość swap informuje przeglądarkę, że tekst, w którym użyto czcionki, powinien zostać natychmiast wyświetlony przy użyciu czcionki systemowej, a czcionka systemowa ma zastępować tylko wtedy, gdy czcionka niestandardowa będzie gotowa.

Największym problemem w elemencie swap jest problem rażący, w którym różnica w wielkości tych 2 czcionek powoduje przesuwanie się zawartości ekranu. Prowadzi to do niskich wyników CLS, zwłaszcza w przypadku witryn z dużą ilością tekstu.

Poniższe obrazy pokazują przykładowy problem. Pierwszy obraz korzysta z font-display: swap bez próby dostosowania rozmiaru czcionki zastępczej. Drugi przykład pokazuje, jak dostosowanie rozmiaru za pomocą reguły CSS @font-face poprawia wczytywanie stron.

Bez zmiany rozmiaru czcionki

body {
  font-family: Inter, serif;
}
tekst, którego nagle zmienia się czcionka i rozmiar, powodując efekt rywalizacji.

Po dostosowaniu rozmiaru czcionki

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");
}
Tekst, który płynnie przechodzi na inną czcionkę.

Dostosowanie rozmiaru czcionki zastępczej może być skuteczną strategią zapobiegania przesuwaniu się układu po załadowaniu czcionki, ale implementacja logiki od zera może być skomplikowana, co opisaliśmy w tym poście o zastępczych czcionekach. Na szczęście dostępnych jest już kilka narzędzi, które ułatwiają to podczas tworzenia aplikacji.

Jak zoptymalizować kreacje zastępcze czcionek w Next.js

Next.js udostępnia wbudowany sposób włączania zastępczej optymalizacji czcionek. Ta funkcja jest domyślnie włączona, gdy wczytujesz czcionki za pomocą komponentu @next/font.

Komponent @next/font został wprowadzony w Next.js w wersji 13. Komponent udostępnia interfejs API, który umożliwia importowanie na strony czcionek Google Fonts lub czcionek niestandardowych i zawiera wbudowany mechanizm automatycznego hostowania plików z czcionkami.

Jeśli są one używane, dane dotyczące czcionek zastępczych są automatycznie obliczane i umieszczane w pliku CSS.

Jeśli na przykład używasz czcionki Roboto, możesz zwykle zdefiniować ją w CSS w ten sposób:

@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;
}

Aby przejść do następnej/czcionki:

  1. Przenieś deklarację czcionki Roboto do kodu JavaScript, importując funkcję „Roboto” z „next/font” (następna). Zwracaną wartością funkcji będzie nazwa klasy, którą możesz wykorzystać w szablonie komponentu. Aby włączyć tę funkcję, dodaj do obiektu konfiguracji atrybut 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. W komponencie użyj wygenerowanej nazwy klasy: javascript export default function RootLayout({ children }: { children: React.ReactNode; }) { return ( <html lang="en" className={roboto.className}> <body>{children}</body> </html> ); }

Opcja konfiguracji adjustFontFallback:

W przypadku @next/font/google: wartość logiczna, która określa, czy automatyczna czcionka zastępcza ma zostać użyta do zmniejszenia skumulowanego przesunięcia układu. Wartość domyślna to true (prawda). Next.js automatycznie ustawia czcionkę zastępczą Arial lub Times New Roman w zależności od typu czcionki (odpowiednio szeryfowa lub bezszeryfowa).

W przypadku @next/font/local: ciąg znaków lub wartość logiczna false (fałsz). Określa, czy do zmniejszenia skumulowanego przesunięcia układu ma zostać użyta automatyczna czcionka zastępcza. Możliwe wartości to Arial, Times New Roman lub false. Wartość domyślna to Arial. Jeśli chcesz używać czcionki szeryfowej, rozważ ustawienie tej wartości na Times New Roman.

Inna opcja czcionek Google

Jeśli użycie komponentu next/font nie jest możliwe, możesz użyć flagi optimizeFonts, aby korzystać z tej funkcji w Google Fonts. W Next.js funkcja OptimizeFonts jest już włączona domyślnie. Ta funkcja umożliwia wbudowanie czcionki Google Font CSS w odpowiedzi HTML. Możesz też włączyć funkcję dostosowania czcionek zastępczych, ustawiając flagę experimental.adjustFontFallbacksWithSizeAdjust w pliku next.config.js, jak pokazano w tym fragmencie:

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

Uwaga: nie planujemy obsługiwania tej funkcji w nowo wprowadzonej pozycji app. W dłuższej perspektywie zalecamy używanie next/font.

Jak dostosować wartości zastępcze czcionek w Nuxt

@nuxtjs/fontaine to moduł platformy Nuxt.js, który automatycznie oblicza wartości danych czcionki zastępczej i generuje zastępczy kod CSS @font-face.

Włącz moduł, dodając element @nuxtjs/fontaine do konfiguracji modułów:

import { defineNuxtConfig } from 'nuxt'

export default defineNuxtConfig({
  modules: ['@nuxtjs/fontaine'],
})

Jeśli korzystasz z Google Fonts lub nie masz deklaracji @font-face dotyczącej czcionki, możesz zadeklarować je jako opcje dodatkowe.

W większości przypadków moduł może odczytywać reguły @font-face z Twojego arkusza CSS i automatycznie wywnioskować takie szczegóły, jak rodzina czcionek, zastępcza rodzina czcionek i typ wyświetlania.

Jeśli czcionka jest zdefiniowana w miejscu, którego moduł nie może wykryć, możesz przekazać informacje o danych w sposób pokazany poniżej.

export default defineNuxtConfig({
  modules: ['@nuxtjs/fontaine'],
  fontMetrics: {
  fonts: ['Inter', { family: 'Some Custom Font', src: '/path/to/custom/font.woff2' }],
},
})

Moduł automatycznie skanuje kod CSS, aby odczytać deklaracje @font-face, i generuje zastępcze reguły @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%;
}

Możesz teraz użyć Roboto override jako czcionki zastępczej w CSS, jak pokazano w poniższym przykładzie

:root {
  font-family: 'Roboto';
  /* This becomes */
  font-family: 'Roboto', 'Roboto override';
}

Samodzielne generowanie CSS

Samodzielne biblioteki mogą również pomóc w generowaniu kodu CSS na potrzeby zastępczych dostosowań rozmiaru czcionki.

Korzystanie z biblioteki Fontaine

Jeśli nie używasz Nuxt ani Next.js, możesz użyć Fontaine. Fontaine to podstawowa biblioteka, na której opiera się @nuxtjs/fontaine. Możesz użyć tej biblioteki w projekcie, aby automatycznie wstrzyknąć CSS czcionki zastępczej za pomocą wtyczek Vite lub Webpack.

Załóżmy, że w pliku CSS zdefiniowano czcionkę 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 udostępnia transformatory Vite i Webpack, które można łatwo podłączyć do łańcucha kompilacji i włączyć wtyczkę w sposób podany w poniższym kodzie 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
}

Jeśli korzystasz z Vite, dodaj wtyczkę w ten sposób: javascript // Vite export default { plugins: [FontaineTransform.vite(options)] }

Jeśli korzystasz z pakietu Webpack, włącz go w ten sposób:

// Webpack
export default {
  plugins: [FontaineTransform.webpack(options)]
}

Moduł automatycznie skanuje Twoje pliki, aby zmodyfikować reguły @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%; }

Teraz możesz używać Roboto override jako czcionki zastępczej w CSS. css :root { font-family: 'Roboto'; /* This becomes */ font-family: 'Roboto', 'Roboto override'; }

Korzystanie z biblioteki Capsize

Jeśli nie używasz Next.js, Nuxt, Webpack lub Vite, możesz też użyć biblioteki Capsize do wygenerowania zastępczego kodu CSS.

Nowy interfejs API createFontStack

Interfejs API jest częścią pakietu @capsize/core o nazwie createFontStack, który akceptuje tablicę danych dotyczących czcionek w tej samej kolejności, w jakiej jest określony stos czcionek (właściwość font-family).

Dokumentację na temat korzystania z funkcji Capsize znajdziesz tutaj.

Przykład

Rozważmy następujący przykład: żądaną czcionkę internetową należy zmienić na „Lobster”, zmieniającą się w Hnienia Neue i Czołowe. W CSS: font-family: Lobster, 'Helvetica Neue', Arial.

  1. Zaimportuj metodę createFontStack z pakietu podstawowego:

    import { createFontStack } from '@capsizecss/core';
    
  2. Zaimportuj dane dotyczące poszczególnych czcionek (patrz: Dane dotyczące czcionek powyżej): javascript import lobster from '@capsizecss/metrics/lobster'; import helveticaNeue from '@capsizecss/metrics/helveticaNeue'; import arial from '@capsizecss/metrics/arial';`

  3. Utwórz stos czcionek, przekazując dane w postaci tablicy, w takiej samej kolejności jak w przypadku właściwości CSS „Font-family”.javascript const { fontFamily, fontFaces } = createFontStack([ lobster, helveticaNeue, arial, ]);

Zostaną zwrócone:

{
  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%;
     }
   }
 ]
}

Musisz dodać do usługi porównywania cen kod fontFamily i fontFaces. Poniższy kod pokazuje, jak zaimplementować go w arkuszu stylów CSS lub w bloku <style>.

<style type="text/css">
  .heading {
    font-family: 
  }

  
</style>

Spowoduje to utworzenie takiego kodu 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%;
}

Możesz też użyć pakietu @capsize/metrics, aby obliczyć wartości zastępowania i samodzielnie zastosować je w 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));

Podziękowania

Baner powitalny autorstwa Alexandera Andrewsa w serwisie Unsplash.