Есть ли проблема при загрузке шрифта в течение десяти секунд?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Есть ли проблема при загрузке шрифта в течение десяти секунд
Да, это серьёзная проблема для UX и SEO. 10 секунд — это неприемлемо долго. Давайте разберёмся, почему это плохо и как это исправить.
Проблема: Invisible Text Flash (FOIT) и Flash of Unstyled Text (FOUT)
FOIT — Invisible Text Flash
// Пример: шрифт загружается 10 секунд
<link href="https://fonts.googleapis.com/css2?family=Roboto" rel="stylesheet" />
// Что происходит:
// 1-9 секунд: текст НЕВИДИМ (браузер ждет загрузки шрифта)
// 10 секунда: шрифт загружен, текст появляется
// Результат: пользователь видит пустой экран, думает, что сайт сломан
FOUT — Flash of Unstyled Text
/* Альтернатива: показать fallback шрифт, потом заменить */
body {
font-family: 'MyCustomFont', Arial, sans-serif; /* Falls back to Arial while loading */
}
/* Что происходит: */
/* 1-9 сек: текст видим (Arial) */
/* 10 сек: текст меняется на MyCustomFont */
/* Результат: видимый скачок текста (jerky experience) */
Почему это проблема
1. Плохой UX
Пользователь:
0 сек: нажимает на ссылку, ждет
5 сек: "Что-то не работает?"
10 сек: "Наконец-то!" (текст появляется)
Впечатление: сайт медленный и неотзывчивый
2. Cumulative Layout Shift (CLS)
Это метрика Core Web Vitals, которая влияет на SEO ранжирование Google.
// Когда шрифт меняется с Arial на Roboto, размеры букв меняются
// До загрузки: 16px Arial
// После загрузки: 16px Roboto (другая ширина!)
// Результат: текст прыгает на экране (CLS > 0)
// Google штрафует такие сайты в поиске!
3. High First Input Delay (FID)
Если шрифт загружается, браузер занят, и JavaScript блокируется.
// Пока браузер скачивает шрифт, JavaScript замораживается
// Кликнул на кнопку → ждешь 3 секунды → наконец сработает
// Пользователь: "Кнопка не работает!"
Приемлемые времена загрузки
< 100ms — Не замечает (идеально)
100-300ms — Замечает небольшое замедление
300-1000ms — Заметно замедление, но терпимо
1-3 сек — Начинает раздражать
3+ сек — Плохо, пользователи уходят
10 сек — Критически плохо!
Решение 1: Preload шрифт (критически важно)
<!-- Скажи браузеру: "Эй, мне нужен этот шрифт, загрузи его в приоритете" -->
<link
rel="preload"
href="/fonts/roboto-regular.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<link
rel="preload"
href="/fonts/roboto-bold.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<!-- Затем используй шрифт -->
<link rel="stylesheet" href="/fonts/styles.css" />
Результат: шрифт начнет загружаться на 1-2 секунды раньше.
Решение 2: Используй font-display: swap
/* В @font-face ОБЯЗАТЕЛЬНО указывай font-display */
@font-face {
font-family: 'Roboto';
src: url('/fonts/roboto.woff2') format('woff2');
font-display: swap; /* <-- ОЧЕНЬ ВАЖНО */
}
Значения:
font-display: block → Ждет 3 сек, потом fallback (FOIT)
font-display: swap → Сразу fallback, потом заменяет (FOUT)
font-display: fallback → Очень короткое ожидание, потом fallback
font-display: optional → Может вообще не загружать, если слишком медленно
Рекомендация: используй swap
@font-face {
font-family: 'MyFont';
src: url('/fonts/my-font.woff2') format('woff2');
font-display: swap; /* Показать Arial сразу, потом заменить */
font-weight: normal;
font-style: normal;
}
Решение 3: Используй переменный шрифт (Variable Font)
/* Вместо скачивания 4 файлов (normal, bold, italic, bold italic) */
/* Скачай 1 файл, который содержит всё */
@font-face {
font-family: 'Roboto Flex';
src: url('/fonts/roboto-flex.woff2') format('woff2-variations');
font-weight: 100 900; /* Диапазон весов */
font-display: swap;
}
Размер файла:
Обычные шрифты:
- roboto-regular.woff2 = 30KB
- roboto-bold.woff2 = 32KB
- roboto-italic.woff2 = 31KB
- roboto-bold-italic.woff2 = 33KB
Итого: 126KB
Переменный шрифт:
- roboto-flex.woff2 = 70KB
Итого: 70KB (экономия 56KB!)
Решение 4: Self-hosted шрифты (вместо Google Fonts)
<!-- ПЛОХО: зависит от google.com -->
<link href="https://fonts.googleapis.com/css2?family=Roboto" rel="stylesheet" />
<!-- DNS lookup: 100ms, загрузка CSS: 200ms, загрузка шрифта: ? -->
<!-- ХОРОШО: со своего сервера -->
<link rel="stylesheet" href="/fonts/roboto.css" />
Файл /public/fonts/roboto.css:
@font-face {
font-family: 'Roboto';
src: url('/fonts/roboto-regular.woff2') format('woff2');
font-display: swap;
}
@font-face {
font-family: 'Roboto';
src: url('/fonts/roboto-bold.woff2') format('woff2');
font-weight: 700;
font-display: swap;
}
Выигрыш: избегаешь отдельного DNS lookup для google.com, все грузится с одного сервера.
Решение 5: Subset шрифтов (загружай только нужные буквы)
<!-- ПЛОХО: загружаешь все 3000+ символов китайского, а используешь только английский -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP" rel="stylesheet" />
<!-- Размер: 200KB+ -->
<!-- ХОРОШО: загружай только latin буквы -->
<link href="https://fonts.googleapis.com/css2?family=Roboto&subset=latin" rel="stylesheet" />
<!-- Размер: 30KB -->
Инструмент для subsetting:
# Использование pyftsubset (Python tool)
pyftsubset roboto.woff2 --unicodes=U+0020-007E # Only ASCII
# Или используй tool.glyphrange.com
Решение 6: Async загрузка с timeout
<!-- Загружай шрифт асинхронно, чтобы не блокировать рендер -->
<link
rel="stylesheet"
href="/fonts/custom-font.css"
media="print"
onload="this.media='all'"
crossorigin
/>
<!-- Fallback: если загрузка прервется -->
<noscript>
<link rel="stylesheet" href="/fonts/custom-font.css" />
</noscript>
Решение 7: System fonts (самое быстрое)
/* Используй системные шрифты, ноль задержки */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', sans-serif;
}
/* Если нужен custom шрифт, загружай его после */
.special {
font-family: 'MyCustomFont', -apple-system, BlinkMacSystemFont, sans-serif;
}
Полный оптимальный пример (Next.js)
// app/layout.tsx
import { Inter, Roboto } from 'next/font/google';
// Next.js оптимизирует автоматически
const inter = Inter({
subsets: ['latin'],
display: 'swap', // Автоматически добавляет font-display
preload: true, // Автоматически preload
});
const roboto = Roboto({
weight: ['400', '700'],
subsets: ['latin'],
display: 'swap',
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<head>
{/* Preload критичные шрифты */}
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
</head>
<body className={inter.className}>
{children}
</body>
</html>
);
}
Проверка скорости загрузки шрифтов
# 1. DevTools → Network → фильтр на font
# Смотри сколько времени загружается
# 2. Lighthouse (DevTools → Lighthouse)
# Проверь Core Web Vitals (CLS, LCP, FID)
# 3. PageSpeed Insights
# Раствори https://pagespeed.web.dev
Чеклист оптимизации шрифтов
// ✅ Сделай это:
☑ Используй preload для критичных шрифтов
☑ Добавь font-display: swap
☑ Используй self-hosted шрифты
☑ Subset шрифты (только нужные буквы)
☑ Используй WOFF2 формат
☑ Используй переменные шрифты если возможно
☑ Проверь CLS (Cumulative Layout Shift)
☑ Не загружай больше 2-3 семейств шрифтов
// ❌ Не делай этого:
☒ Не загружай шрифты без preload
☒ Не используй font-display: block
☒ Не загружай ВСЕ варианты (normal, italic, bold, bold-italic)
☒ Не используй Google Fonts без оптимизации
☒ Не блокируй рендер ожиданием шрифта
Пример: реальное время загрузки
БЕЗ оптимизации:
- DNS lookup: 100ms
- Скачивание Google Fonts CSS: 200ms
- Скачивание шрифта: 5000ms
- Рендер с шрифтом: 5300ms
С оптимизацией (preload + swap):
- DNS lookup: 0ms (preconnect)
- Preload шрифта: 500ms (параллельно с CSS)
- Рендер с fallback: 200ms
- Замена на custom шрифт: 500ms (незаметно)
Итого: 500ms (вместо 5300ms!)
Вывод
Загрузка шрифта за 10 секунд — это критическая проблема. Решить её можно:
- Preload шрифты — они начнут загружаться раньше
- font-display: swap — не ждешь, показываешь fallback
- Self-hosted — избегаешь лишних DNS lookups
- Subset шрифтов — загружаешь только нужное
- System fonts — самый быстрый вариант
Цель: < 100ms загрузка, чтобы пользователь не заметил задержку.
Google штрафует медленные сайты в поиске, так что это важно и для SEO!