Narzędzia platformy do tworzenia zastępczych czcionek

Janicklas Ralph James
Janicklas Ralph James

W witrynach, które wczytują czcionki z atrybutem font-display: swap, po załadowaniu czcionki internetowej i zastępowaniu czcionki zastępczej często występuje przesunięcie układu (CLS).

Możesz zapobiec CLS, dostosowując wymiary czcionki zastępczej do rozmiaru 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 w zastąpieniu danych czcionki zastępczej, umożliwiając deweloperom większą kontrolę nad sposobem wyświetlania czcionek. Więcej informacji o kreacjach zastępczych czcionek i właściwościach zastępowania znajdziesz w tym poście. Praktyczne wdrożenie tej metody możesz też zobaczyć w tej prezentacji.

Z tego artykułu dowiesz się, jak w platformach Next.js i Nuxt.js implementowane są korekty rozmiaru czcionki, co pozwala wygenerować zastępczy kod CSS czcionki i zmniejszyć CLS. Pokazuje też, jak generować czcionki zastępcze przy użyciu narzędzi do cięcia krzyżowego, takich jak Fontaine i Capsize.

Wprowadzenie

Parametr font-display: swap służy zwykle do zapobiegania zaburzaniu funkcji FOIT (flashowanie niewidocznego tekstu) i do szybszego wyświetlania zawartości ekranu. Wartość swap informuje przeglądarkę, że tekst korzystający z czcionki powinien być wyświetlany natychmiast z użyciem czcionki systemowej i zastąpić czcionkę systemową tylko wtedy, gdy czcionka niestandardowa będzie gotowa.

Największym problemem w usłudze swap jest efekt irytacji, w którym różnica w rozmiarach znaków w przypadku obu czcionek powoduje przesuwanie zawartości ekranu. Prowadzi to do niskich wyników CLS, zwłaszcza w przypadku witryn z dużą ilością tekstu.

Poniższe obrazy obrazują przykład problemu. Pierwszy obraz wykorzystuje atrybut 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óry nagle zmienia czcionkę i rozmiar, powodując efekt irygacji.

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 do innej czcionki.

Dostosowanie rozmiaru czcionki zastępczej może być skuteczną strategią zapobiegania zmianie układu, ale wdrożenie tej logiki od zera może być trudne, jak opisano w tym poście o kreacjach zastępczych czcionek. Na szczęście jest już kilka opcji, które ułatwiają tworzenie aplikacji.

Jak zoptymalizować zastępcze czcionki dzięki Next.js

Next.js ma wbudowany sposób włączania zastępczej optymalizacji czcionek. Ta funkcja jest domyślnie włączona podczas wczytywania czcionek za pomocą komponentu @next/font.

Komponent @next/font został wprowadzony w Next.js w wersji 13. Komponent udostępnia interfejs API umożliwiający importowanie czcionek Google lub czcionek niestandardowych na strony i wbudowany mechanizm automatycznego hostowania plików czcionek.

Jeśli dane o czcionkach zastępczych są stosowane, są one automatycznie obliczane i wstrzymywane do pliku CSS.

Na przykład jeśli używasz czcionki Roboto, zwykle zdefiniujesz ją w CSS w następujący 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”. Wartością zwrotną tej funkcji będzie nazwa klasy, której możesz użyć w szablonie komponentu. Pamiętaj, aby dodać obiekt display: swap do obiektu konfiguracji, aby włączyć tę funkcję.

     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 polu @next/font/google: wartość logiczna określająca, czy do ograniczenia skumulowanego przesunięcia układu ma być używana automatyczna czcionka zastępcza. Wartość domyślna to true (prawda). Next.js automatycznie ustawia jako czcionkę zastępczą Arial lub Times New Roman w zależności od typu czcionki (szeryfowa lub bezszeryfowa).

W przypadku @next/font/local: ciąg lub wartość logiczna fałsz, która określa, czy do ograniczenia skumulowanego przesunięcia układu ma być używana automatyczna czcionka zastępcza. Możliwe wartości to Arial, Times New Roman oraz false. Wartość domyślna to Arial. Jeśli chcesz używać czcionki szeryfowej, ustaw tę wartość na Times New Roman.

Inna opcja dla czcionek Google

Jeśli nie możesz użyć komponentu next/font, możesz też używać tej funkcji w przypadku czcionek Google Fonts za pomocą flagi optimizeFonts. Funkcja Next.js ma już domyślnie włączoną funkcję OptimizeFonts. Ta funkcja jest wbudowana w kod CSS czcionki Google w odpowiedzi HTML. Możesz też włączyć funkcję dostosowywania 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 z nowo wprowadzonym kierunkiem app. W dłuższej perspektywie najlepiej jest używać next/font.

Dostosowywanie wartości zastępczych czcionek za pomocą 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.

Aby włączyć moduł, dodaj do jego konfiguracji moduł @nuxtjs/fontaine:

import { defineNuxtConfig } from 'nuxt'

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

Jeśli używasz 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 CSS i automatycznie uzyskiwać szczegółowe informacje, takie jak rodzina czcionek, rodzina czcionek zastępczych i typ wyświetlania.

Jeśli czcionka jest zdefiniowana w miejscu, którego moduł nie wykrywa, możesz przekazywać 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 pod kątem odczytania deklaracji @font-face i generuje 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 kodu CSS

W generowaniu kodu CSS na potrzeby zastępczego dostosowania rozmiaru czcionki mogą pomóc także samodzielne biblioteki.

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 działa kod @nuxtjs/fontaine. Możesz użyć tej biblioteki w projekcie, by automatycznie wstrzykiwać zastępczy kod CSS czcionek za pomocą wtyczek Vite lub Webpack.

Załóżmy, że w pliku CSS masz zdefiniowaną 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 transformery Vite i Webpack, które umożliwiają łatwe podłączenie wtyczki do łańcucha kompilacji i włączanie wtyczki w sposób pokazany poniżej.

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 używasz Vite, dodaj tę wtyczkę w ten sposób: javascript // Vite export default { plugins: [FontaineTransform.vite(options)] }

Jeśli używasz pakietu Webpack, włącz go w następujący sposób:

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

Moduł będzie automatycznie skanować 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%; }

Możesz teraz 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 korzystasz z Next.js, Nuxt, Webpack ani Vite, możesz też użyć biblioteki Capsize, by wygenerować zastępczy kod CSS.

Nowy interfejs API createFontStack

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

Tutaj znajdziesz dokumentację dotyczącą korzystania z funkcji Capsize.

Przykład

Rozważmy następujący przykład: żądana czcionka internetowa to Lobster, której czcionka to HTOPIC Neue, a następnie {8/}. W CSS: font-family: Lobster, 'Helvetica Neue', Arial.

  1. Importuj createFontStack z pakietu podstawowego:

    import { createFontStack } from '@capsizecss/core';
    
  2. Zaimportuj dane dotyczące poszczególnych czcionek (patrz: Dane 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 formie tablicy, w tej samej kolejności co we właściwości CSS rodziny czcionek. javascript const { fontFamily, fontFaces } = createFontStack([ lobster, helveticaNeue, arial, ]);

Zwrócony wynik:

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

Do CSS musisz dodać kody fontFamily i FontFaces. Poniższy kod pokazuje, jak zastosować go w arkuszu stylów CSS lub w bloku <style>.

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

  
</style>

Spowoduje to wygenerowanie 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ąpienia i samodzielnie zastosować je w usłudze porównywania cen.

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: Alexander AndrewsUnsplash.