Оптимизация Core Web Vitals
Core Web Vitals — три метрики Google, напрямую влияющие на ранжирование с 2021 года. Плохие показатели дают «Page Experience» penalty; хорошие — дают преимущество при прочих равных.
Три метрики и целевые значения
| Метрика | Хорошо | Требует улучшения | Плохо |
|---|---|---|---|
| LCP (Largest Contentful Paint) | ≤ 2.5 с | 2.5–4.0 с | > 4.0 с |
| INP (Interaction to Next Paint) | ≤ 200 мс | 200–500 мс | > 500 мс |
| CLS (Cumulative Layout Shift) | ≤ 0.1 | 0.1–0.25 | > 0.25 |
INP заменил FID в марте 2024 года. FID измерял только первое взаимодействие; INP — все взаимодействия за сессию.
LCP (Largest Contentful Paint) — скорость загрузки главного элемента
LCP — момент когда самый крупный элемент (обычно hero-изображение или H1) появляется на экране.
Главные причины плохого LCP:
- Изображение hero не preload
- Медленный TTFB сервера
- Render-blocking CSS/JS
- Изображение в WebP/AVIF не оптимизировано
Ключевые оптимизации:
<!-- Preload LCP-изображения -->
<link rel="preload" as="image" href="/images/hero.webp"
imagesrcset="/images/hero-400.webp 400w, /images/hero-800.webp 800w, /images/hero-1200.webp 1200w"
imagesizes="100vw">
<!-- fetchpriority для тега <img> -->
<img src="/images/hero.webp" fetchpriority="high" loading="eager"
width="1200" height="630" alt="...">
# Ускорение TTFB через кеш на Nginx
location ~* \.(html)$ {
proxy_cache_valid 200 5m;
add_header X-Cache-Status $upstream_cache_status;
}
INP (Interaction to Next Paint) — отзывчивость интерфейса
INP измеряет задержку между действием пользователя (клик, нажатие клавиши) и следующей отрисовкой.
Причины плохого INP:
- Длинные JavaScript-задачи (Long Tasks > 50ms) блокируют main thread
- Синхронные вычисления в обработчиках событий
- Слишком частые setState в React без батчинга
Оптимизации:
// Разбивка длинных задач через scheduler
async function processLargeList(items) {
for (let i = 0; i < items.length; i++) {
processItem(items[i]);
// Yield main thread каждые 50 элементов
if (i % 50 === 0) {
await new Promise(r => setTimeout(r, 0));
}
}
}
// React 18: автоматический батчинг уже включён
// Для явного контроля — startTransition для некритичных обновлений
import { startTransition } from 'react';
function handleSearch(query) {
// Срочное обновление (поле ввода)
setInputValue(query);
// Некритичное (список результатов) — можно отложить
startTransition(() => {
setSearchResults(filterResults(query));
});
}
CLS (Cumulative Layout Shift) — стабильность макета
CLS — сумма смещений элементов при загрузке страницы.
Типичные причины:
- Изображения без
width/height(браузер не резервирует место) - Шрифты вызывают FOUT/FOIT
- Динамически вставляемые баннеры/реклама
- Анимации, изменяющие размер элементов
Оптимизации:
<!-- Всегда указывать размеры изображений -->
<img src="photo.webp" width="800" height="600" alt="...">
<!-- Для адаптивных — aspect-ratio в CSS -->
<style>
.hero-image {
aspect-ratio: 16 / 9;
width: 100%;
}
</style>
/* Резервировать место под шрифты */
@font-face {
font-family: 'Inter';
font-display: optional; /* или swap + size-adjust */
src: url('/fonts/inter.woff2') format('woff2');
}
/* Для font-display: swap — компенсировать размерное различие */
@font-face {
font-family: 'InterFallback';
src: local('Arial');
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
size-adjust: 107%;
}
Инструменты измерения
Лабораторные данные (синтетические):
- PageSpeed Insights — быстрая проверка конкретной страницы
- Lighthouse (DevTools) — детальный аудит
- WebPageTest — расширенный анализ с waterfall
Полевые данные (реальные пользователи):
- CrUX (Chrome User Experience Report) — в Search Console
- web-vitals npm-пакет для сбора в аналитику
// Отправка Web Vitals в GA4
import { onCLS, onINP, onLCP, onFCP, onTTFB } from 'web-vitals';
function sendToAnalytics({ name, value, rating, id }) {
gtag('event', name, {
event_category: 'Web Vitals',
event_label: id,
value: Math.round(name === 'CLS' ? value * 1000 : value),
non_interaction: true,
custom_map: { metric_rating: rating }
});
}
onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
onFCP(sendToAnalytics);
onTTFB(sendToAnalytics);
Приоритеты работ
- LCP — обычно даёт наибольший эффект: preload hero-image, FastCGI/Redis кеш для TTFB
- CLS — быстро исправляется добавлением размеров изображениям и настройкой шрифтов
- INP — сложнее: требует профилирования конкретных взаимодействий через Performance DevTools
Срок оптимизации: 1–2 недели для комплексной работы по всем трём метрикам.







