Производительность сайта
Скорость для пользователей и метрик: Core Web Vitals, LCP и CLS, вес страницы, критический CSS, кэш, preload и измерение в Lighthouse.
1. Зачем оптимизировать скорость
Медленный сайт теряет пользователей: половина посетителей уходит, если страница грузится дольше нескольких секунд, а конверсия падает с ростом времени загрузки. Скорость — это бизнес-метрика, и её измеряют не «в секундах», а по сценариям реальных пользователей.
- первые 2–3 секунды решают, останется ли пользователь;
- мобильный сайт в среднем медленнее десктопного и чаще теряет трафик;
- скорость — фактор ранжирования в поисковых системах;
- медленный UX чувствуют все, а не только мобильные.
2. Core Web Vitals
Google измеряет скорость тремя метриками Core Web Vitals, которые отражают реальный опыт: быстро ли загрузилось главное (LCP), не прыгает ли макет (CLS), и живо ли сайт реагирует (INP). Все три имеют «зелёную зону» — ориентиры для работы.
| Метрика | Что измеряет | Хорошо |
|---|---|---|
| LCP (Largest Contentful Paint) | время появления самого крупного контента на экране | до 2,5 с |
| CLS (Cumulative Layout Shift) | насколько макет сдвигается при загрузке | до 0,1 |
| INP (Interaction to Next Paint) | задержка реакции на взаимодействие | до 200 мс |
LCP обычно определяется картинкой или текстом на первом экране; CLS — «прыжками» блока, когда дозагружается контент (без зарезервированного места); INP — блокирующим JS и тяжёлыми обработчиками.
3. LCP: ускорьте главный экран
Первый экран на десктопе — это hero-картинка и заголовок, на мобильном чаще текст. Ускорение LCP — это сокращение цепочки: DNS → сеть → сервер → CSS → ресурс → отрисовка. Устраняйте самое длинное звено.
<!-- LCP-картинка: качаем сразу и с приоритетом -->
<img src="hero.jpg" width="1200" height="600"
alt="Баннер" fetchpriority="high">
<!-- подсказываем браузеру критические ресурсы -->
<link rel="preload" href="fonts/hero.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preconnect" href="https://cdn.site.com">- LCP-изображению заданы width/height — место занято сразу, CLS не растёт;
- предзагружайте hero-изображение и критичный шрифт (preload/fetchpriority);
- CSS до LCP держите в head и небольшим (критический CSS);
- отложенные ресурсы (lazy, defer) должны быть ниже первого экрана.
4. CLS: без прыжков
Прыжки макета — когда блок сдвигается после отрисовки. Причины: картинки и видео без размеров, шрифты, подменяющие текст (swap), динамически вставленный контент, баннеры. Лечится резервированием места и запретом внезапных сдвигов.
/* место под картинку/видео */
img, video { aspect-ratio: 4 / 3; object-fit: cover; }
/* шрифт не переставляет текст: предзагрузка + системный запас */
@font-face { font-family: "Inter"; font-display: swap; }
body { font-family: "Inter", system-ui, sans-serif; }
/* динамике не сдвигать страницу внезапно: контейнер с высотой или overflow */
.ad-slot { min-height: 250px; }- всем картинкам и iframe — width/height или aspect-ratio;
- динамическому контенту (баннеры, уведомления) — зарезервированный слот;
- transform/opacity для анимаций, а не top/left/margin (не двигают layout);
- объявления и виджеты — внутри контейнеров с фиксированной высотой.
5. INP: отклик интерфейса
Реакцию измеряют от действия пользователя до обновления экрана. Долгие главные потоки — синхронный JS, тяжёлые раскладки, крупные DOM-операции — держат интерфейс «замерзшим». INP хорош, когда код выполняет работу быстро и кусочками.
// долгие задачи дробим, чтобы поток дышал
const items = await fetch("/api/items").then(r => r.json());
for (const chunk of chunks(items, 50)) {
render(chunk); // рендер частями
await new Promise(r => setTimeout(r)); // отдаём поток браузеру
}
// лёгкие варианты: requestAnimationFrame для плавных черновиков- не блокируйте поток при загрузке: defer/async отключают синхронные script;
- тяжёлую обработку (парсинг, DOM) выполняйте порциями;
- при вводе текста дебаунсите дорогие обработчики;
- для скролла и тач-обработчиков ставьте passive: true.
6. Вес страницы и передача
Трафик стоит денег и времени: каждый байт, прошедший по сети, оплачен лимитом и задержкой. Вес страницы считают как сумму всех ресурсов: HTML, CSS, JS, картинки, шрифты. Современные сайты весят 1.5–3 МБ, из которых половина — изображения.
# реальный вес страницы
curl -I https://site.com # заголовки ресурса
curl -so /dev/null -w "%{size_download}" https://site.com
# в DevTools: Network → размер «Передано» vs «Ресурс»
# передано меньше, если включено сжатие (Content-Encoding)| Приём | Экономия |
|---|---|
| сжатие HTML/CSS/JS (gzip/brotli) | до 70–80% передачи |
| картинки в AVIF/WebP, правильно обрезанные | десятки–сотни КБ |
| критический CSS инлайн, остальной — отложенно | важное быстрее |
| шрифт одним файлом начертания (не 5) | сотни КБ |
| SVG вместо PNG для иконок | байты вместо КБ |
7. Критический CSS
Браузер не рисует страницу, пока не получит весь блокирующий CSS. Если стилей сайта много (500 КБ), первый экран ждёт лишние секунды. Критический CSS — узкий набор правил для первого экрана (тут же, в head), остальное — отдельный файл с отложившимся соединением.
<head>
<style>
/* критический CSS: только то, что видно на первом экране */
body { margin: 0; font: 1rem/1.5 system-ui, sans-serif; }
.hero { padding: 24px; background: #0f172a; color: #fff; }
</style>
<link rel="stylesheet" href="style.css" media="print"
onload="this.media='all'">
</head>
<noscript><link rel="stylesheet" href="style.css"></noscript>- инструменты (Critical, PurgeCSS) выделяют критический CSS автоматически;
- не держите огромный