Пошук уроків, статей та іншого контенту
Зменшите затримки відображення тексту завдяки локальному завантаженню, subset і preload шрифтів.
Шрифт часто впливає не лише на зовнішній вигляд сторінки, а й на швидкість відображення тексту.
Під час завантаження шрифту браузер може:
чекати на файл шрифту перед відображенням тексту;
спочатку показати текст системним шрифтом, а потім замінити його;
завантажити більший файл, ніж потрібно;
витратити додатковий час на підключення до зовнішнього сервера.
У Next.js оптимізація шрифтів виконується через пакет next/font. Він:
завантажує шрифти під час складання проєкту;
зберігає їх у статичних ресурсах застосунку;
генерує потрібні @font-face;
може додати preload;
дозволяє вказати display, fallback і CSS-змінну.
Для власного файлу шрифту використовуйте next/font/local.
Розмістимо файл шрифту в проєкті:
app/
fonts/
Inter-Cyrillic-Latin.woff2
layout.tsx
page.tsx
globals.cssФайл app/fonts/Inter-Cyrillic-Latin.woff2 має містити лише потрібні набори символів. У цьому прикладі це кирилиця та латиниця.
// app/layout.tsx
import type { Metadata } from 'next';
import localFont from 'next/font/local';
import './globals.css';
const siteFont = localFont({
src: './fonts/Inter-Cyrillic-Latin.woff2',
variable: '--font-site',
display: 'swap',
preload: true,
fallback: ['system-ui', 'sans-serif'],
});
export const metadata: Metadata = {
title: 'Каталог курсів',
description: 'Навчальна платформа',
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="uk">
<body className={siteFont.variable}>{children}</body>
</html>
);
}Тепер застосуємо шрифт у CSS:
/* app/globals.css */
:root {
--font-site: system-ui, sans-serif;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: var(--font-site);
color: #171717;
background: #ffffff;
}
h1,
h2,
p {
margin-top: 0;
}Функція localFont повертає об'єкт, який містить CSS-клас. Властивість variable додає клас для CSS-змінної --font-site.
Важливо додати цей клас до елемента body або іншого кореневого елемента. Якщо цього не зробити, CSS-змінна не буде доступною.
// app/page.tsx
export default function HomePage() {
return (
<main>
<h1>Оптимізовані шрифти в Next.js</h1>
<p>
Текст використовує локальний файл шрифту та системний резервний шрифт.
</p>
</main>
);
}У цьому прикладі браузер не звертається до стороннього сервера для отримання шрифту. Шрифт є частиною ресурсів самого застосунку.
displayПараметр display визначає поведінку тексту до моменту завантаження шрифту.
const siteFont = localFont({
src: './fonts/Inter-Cyrillic-Latin.woff2',
display: 'swap',
});Найчастіше використовують:
swap — спочатку показати текст резервним шрифтом, а після завантаження замінити його основним;
optional — браузер може залишити резервний шрифт, якщо основний завантажується надто довго;
fallback — короткий період очікування, після якого використовується резервний шрифт;
block — браузер може тимчасово приховати текст.
Для основного шрифту сайту зазвичай підходить swap. Він запобігає тривалому приховуванню тексту, хоча після завантаження може відбутися помітна заміна шрифту.
Subset — це зменшена версія шрифту, яка містить лише потрібні символи.
Повний файл може містити:
латиницю;
кирилицю;
грецький алфавіт;
ієрогліфи;
спеціальні символи;
символи різних мов.
Якщо застосунок використовує лише українську та англійську, немає потреби завантажувати символи всіх мов. Зменшений файл:
швидше завантажується;
займає менше місця;
потребує менше даних для передачі;
зменшує затримку відображення тексту.
Для українського інтерфейсу зазвичай потрібні:
кирилиця для українського тексту;
латиниця для англійського тексту, URL, назв технологій і брендів;
цифри та базові розділові знаки.
Назва файлу не визначає його вміст. Переконайтеся, що підготовлений subset справді містить усі символи, які використовуються в інтерфейсі.
Якщо застосунок має багато мов, можна підготувати окремі файли, наприклад:
Inter-Latin.woff2
Inter-Cyrillic.woff2
Inter-Greek.woff2Це дає змогу не завантажувати великий універсальний файл для кожного користувача. Але окремі subset-файли потрібно правильно підключити через CSS і unicode-range. Якщо всі сторінки застосунку використовують українську та латиницю, один файл Inter-Cyrillic-Latin.woff2 часто є простішим рішенням.
next/font/googleЯкщо потрібний шрифт доступний у next/font/google, Next.js також завантажить його під час складання проєкту, а не безпосередньо з сервера Google у браузері.
// app/layout.tsx
import { Roboto } from 'next/font/google';
import './globals.css';
const siteFont = Roboto({
subsets: ['cyrillic', 'latin'],
variable: '--font-site',
display: 'swap',
preload: true,
weight: ['400', '500', '700'],
});
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="uk">
<body className={siteFont.variable}>{children}</body>
</html>
);
}Параметр subsets важливий: він визначає, які набори символів потрібно включити. Для україномовної сторінки latin без cyrillic буде недостатньо.
Вибирайте лише потрібні накреслення:
const siteFont = Roboto({
subsets: ['cyrillic', 'latin'],
weight: ['400', '700'],
});Якщо додати багато накреслень, браузеру або користувачу може знадобитися більше файлів шрифту. Наприклад, не варто додавати 300, 400, 500, 600, 700, 800 і 900, якщо інтерфейс фактично використовує лише 400 і 700.
Preload повідомляє браузеру, що файл шрифту потрібен якомога раніше.
У next/font це налаштовується параметром preload:
const siteFont = localFont({
src: './fonts/Inter-Cyrillic-Latin.woff2',
display: 'swap',
preload: true,
});Коли preload: true, Next.js генерує відповідний ресурс для попереднього завантаження шрифту.
Preload доречний, коли:
шрифт використовується на всіх сторінках;
він застосовується до тексту у верхній частині сторінки;
це основний шрифт інтерфейсу.
Для другорядних шрифтів можна вимкнути preload:
const decorativeFont = localFont({
src: './fonts/Decorative.woff2',
display: 'swap',
preload: false,
});Наприклад, декоративний шрифт може використовуватися лише в модальному вікні або в нижній частині сторінки. Немає сенсу завантажувати його з найвищим пріоритетом під час відкриття кожної сторінки.
Якщо шрифт не є variable font, кожне накреслення можна описати окремим файлом:
import localFont from 'next/font/local';
const siteFont = localFont({
src: [
{
path: './fonts/Inter-Regular.woff2',
weight: '400',
style: 'normal',
},
{
path: './fonts/Inter-Bold.woff2',
weight: '700',
style: 'normal',
},
],
variable: '--font-site',
display: 'swap',
preload: true,
fallback: ['system-ui', 'sans-serif'],
});Тоді браузер завантажуватиме відповідне накреслення залежно від CSS:
body {
font-family: var(--font-site);
font-weight: 400;
}
strong {
font-weight: 700;
}Не оголошуйте багато файлів без потреби. Якщо текст використовує лише звичайне та напівжирне накреслення, достатньо двох файлів.
Резервний шрифт використовується, якщо основний ще не завантажився або недоступний:
const siteFont = localFont({
src: './fonts/Inter-Cyrillic-Latin.woff2',
fallback: ['system-ui', 'sans-serif'],
});Резервний шрифт має бути схожим за:
шириною символів;
висотою рядка;
товщиною накреслення;
загальними пропорціями.
Чим сильніше відрізняються основний і резервний шрифти, тим помітнішою буде зміна макета після завантаження основного шрифту.
Використання одного великого файлу з усіма мовами збільшує обсяг завантаження.
Краще підготувати subset, який містить лише потрібні символи та накреслення.
Файл із subset latin не містить українських символів. У такому разі частина тексту буде показана резервним шрифтом.
Перевіряйте не лише назву файлу, а фактичний набір символів у ньому.
Preload усіх шрифтів збільшує кількість ресурсів із високим пріоритетом. Це може сповільнити завантаження CSS, JavaScript або зображень, які потрібні для першого екрана.
Використовуйте preload: true лише для основного шрифту, потрібного одразу.
display: 'swap'Без явної стратегії відображення текст може бути невидимим під час очікування шрифту або поводитися по-різному в різних браузерах.
Для звичайного тексту використовуйте display: 'swap' або, за відповідної вимоги, optional.
Кожне накреслення може бути окремим ресурсом. Додавання всіх можливих значень font-weight без реальної потреби збільшує розмір застосунку.
@font-faceЯкщо шрифт підключено через next/font, не потрібно повторно оголошувати його вручну в globals.css. Це може створити дублікати або конфлікти між правилами.
Шлях у src визначається відносно файлу, у якому викликається localFont.
Для app/layout.tsx файл за адресою app/fonts/Inter.woff2 підключається так:
src: './fonts/Inter.woff2'Після налаштування перевірте:
У мережевих запитах браузера відкрийте сторінку та знайдіть файли .woff2.
Переконайтеся, що шрифт завантажується з ресурсів вашого застосунку.
Перевірте, що не завантажуються непотрібні накреслення.
Перевірте український текст, латиницю, цифри та спеціальні символи.
Переконайтеся, що текст видимий до завершення завантаження шрифту.
Перевірте сторінку з повільним мережевим з'єднанням.
Для локальних файлів використовуйте next/font/local.
Зменшуйте шрифт за допомогою subset із потрібними мовами та символами.
Для українського інтерфейсу зазвичай потрібні cyrillic і latin.
Завантажуйте лише накреслення, які реально використовуються.
Використовуйте display: 'swap', щоб текст не залишався прихованим.
Увімкніть preload для основного шрифту першого екрана.
Для другорядних шрифтів використовуйте preload: false.
Не дублюйте оголошення шрифтів вручну, якщо їх уже підключає next/font.