~/wiki / ux-i-interfeisy / pagespeed-lighthouse-core-web-vitals-audit

Аудит сайта через PageSpeed, Lighthouse и Core Web Vitals: пошаговый разбор

Основной чат

Чат для вайбкодеров: новости, гайды, поиск исполнителей, маркетплейс и разбор реальных кейсов.

$ cd раздел/ $ join vibe dev
Аудит сайта через PageSpeed, Lighthouse и Core Web Vitals: пошаговый разбор - обложка

Три инструмента и их роли

Прежде чем бежать что-то проверять — разберёмся что за инструменты существуют и чем они отличаются.

PageSpeed Insights (PSI)

Ссылка: pagespeed.web.dev

Это онлайн-инструмент от Google. Анализирует одну страницу и даёт оценку от 0 до 100 для мобайла и десктопа отдельно.

Что важно понять: PSI показывает два типа данных.

Лабораторные данные (Lab data) — Lighthouse запускается на серверах Google в контролируемых условиях. Это синтетический тест: фиксированное железо, фиксированная сеть, один конкретный момент времени.

Полевые данные (Field data / CrUX) — реальные данные от реальных пользователей Chrome за последние 28 дней. Это Chrome User Experience Report (CrUX). Если сайт мало посещают — полевых данных может не быть.

Разница принципиальная: лабораторные данные нужны чтобы диагностировать проблемы. Полевые данные нужны чтобы понять как сайт ощущается реальными пользователями.

Lighthouse

Где запустить: Chrome DevTools → вкладка Lighthouse (F12 → Lighthouse)

Тот же движок что используется в PSI, но запускается в вашем браузере. Анализирует не только производительность — ещё доступность, SEO, best practices.

Преимущество перед PSI: можно тестировать локальные сборки, staging-окружения, страницы за авторизацией. PSI не может добраться до закрытых страниц.

Core Web Vitals

Это не инструмент — это три конкретные метрики которые Google считает ключевыми для пользовательского опыта:

  • LCP (Largest Contentful Paint) — когда загрузился главный контент
  • INP (Interaction to Next Paint) — насколько быстро реагирует интерфейс
  • CLS (Cumulative Layout Shift) — насколько стабильна верстка при загрузке

Эти три метрики есть и в PSI, и в Lighthouse, и в Google Search Console.


Как читать отчёт PageSpeed Insights

Открываешь pagespeed.web.dev, вставляешь URL, жмёшь «Анализ». Через 20–30 секунд — отчёт. Разбираем его сверху вниз.

Первый экран: оценки и полевые данные

Вверху — два числа: оценка для мобайла и для десктопа. Мобайл почти всегда ниже — потому что тестируется на эмулированном медленном устройстве (Moto G4) с медленным соединением (4G).

Цветовая кодировка:

  • 90–100 🟢 — хорошо
  • 50–89 🟡 — требует улучшений
  • 0–49 🔴 — плохо

Ниже — полевые данные (Field Data) если они есть. Это реальные пользователи. Здесь та же цветовая кодировка для каждой из трёх Core Web Vitals метрик.

Важно: оценка — это агрегированное число. Две страницы могут иметь оценку 65 по совершенно разным причинам. Смотри не на оценку — смотри на конкретные метрики.

Метрики производительности

Под полевыми данными — раздел «Диагностика производительности» с шестью метриками:

FCP (First Contentful Paint) — когда появился первый элемент контента (текст или изображение). Норма: < 1.8 секунды.

LCP (Largest Contentful Paint) — когда загрузился самый крупный элемент на странице (обычно hero-изображение или заголовок). Норма: < 2.5 секунды. Это одна из Core Web Vitals.

TBT (Total Blocking Time) — суммарное время блокировки основного потока JavaScript. Лабораторный прокси для INP. Норма: < 200 мс.

CLS (Cumulative Layout Shift) — насколько элементы «прыгают» при загрузке. Норма: < 0.1. Это Core Web Vitals.

Speed Index — насколько быстро визуально заполняется экран. Норма: < 3.4 секунды.

INP (Interaction to Next Paint) — время от действия пользователя до следующего отрисованного кадра. Это ключевая метрика интерактивности в 2024+. Норма: < 200 мс. Core Web Vitals.

Раздел «Возможности» (Opportunities)

Это конкретные действия которые улучшат LCP и другие метрики — с оценкой потенциальной экономии в секундах.

Здесь приоритизируй по потенциальному выигрышу. «Удалить неиспользуемый JavaScript» с экономией 2.3 секунды — важнее чем «Использовать формат WebP» с экономией 0.1 секунды.

Раздел «Диагностика» (Diagnostics)

Более детальные рекомендации — не напрямую влияющие на оценку, но влияющие на качество.


Core Web Vitals: разбор каждой метрики

LCP (Largest Contentful Paint)

Что это: момент когда загрузился самый крупный видимый элемент страницы. Обычно это:

  • Hero-изображение
  • Большой блок текста (заголовок на текстовой странице)
  • Видео-постер

Нормы:

  • ✅ < 2.5 секунды — хорошо
  • 🟡 2.5–4 секунды — требует улучшений
  • 🔴 > 4 секунды — плохо

Как узнать что является LCP-элементом:

В Chrome DevTools → Performance → запусти запись → перезагрузи страницу → в разделе Timings найди LCP-маркер → кликни → увидишь какой элемент.

Или в Lighthouse-отчёте — в деталях LCP написано что именно.

Почему LCP медленный — типичные причины:

  1. Медленный сервер (TTFB) — браузер долго ждёт первый байт от сервера. Всё остальное бессмысленно оптимизировать если TTFB > 600 мс. Решение: CDN, кэширование на сервере, апгрейд хостинга.

  2. LCP-изображение не preload'ится — браузер обнаруживает изображение только когда парсит CSS или рендерит HTML. Если это hero-картинка — она должна грузиться с самого начала. Решение: <link rel="preload" as="image" href="hero.webp"> в <head>.

  3. Изображение не оптимизировано — PNG 2 МБ вместо WebP 200 КБ. Решение: конвертация в WebP/AVIF, правильные размеры (не грузить изображение 3000px шириной если отображается 800px).

  4. Render-blocking ресурсы — CSS и JS в <head> без defer/async блокируют рендеринг. Решение: критичный CSS — inline в <head>, некритичный — с media="print" и JS-переключением, JavaScript — с defer или async.

  5. Медленные шрифты — браузер ждёт загрузки шрифта прежде чем показать текст. Решение: font-display: swap + preload критичных шрифтов.


INP (Interaction to Next Paint)

Что это: время от любого взаимодействия пользователя (клик, тап, нажатие клавиши) до момента когда браузер отрисовал следующий кадр в ответ. Заменил FID (First Input Delay) как метрику интерактивности в 2024 году.

Нормы:

  • ✅ < 200 мс — хорошо
  • 🟡 200–500 мс — требует улучшений
  • 🔴 > 500 мс — плохо

Почему INP медленный:

INP страдает когда основной поток (main thread) занят. Причины:

  • Тяжёлые JavaScript-задачи блокирующие поток
  • Много обработчиков событий
  • Сложные перерасчёты стилей (layout thrashing)
  • Синхронные операции в обработчике клика

Как диагностировать:

Chrome DevTools → Performance → запиши 5–10 секунд взаимодействия → найди в треке «Main» длинные жёлтые/красные задачи (Long Tasks) — это то что блокирует поток.

В LoAF (Long Animation Frames) — новый раздел в Chrome 123+ — видны конкретные анимации и скрипты которые создают задержку.

Как чинить:

  • Разбивать длинные задачи через setTimeout(0) или scheduler.yield()
  • Использовать Web Workers для тяжёлых вычислений
  • Debounce/throttle для частых событий (scroll, resize, input)
  • Виртуализация длинных списков (react-virtual, tanstack-virtual)

CLS (Cumulative Layout Shift)

Что это: суммарная «нестабильность» верстки при загрузке. Когда элементы «прыгают» — пользователь случайно нажимает не то, теряет место в тексте, испытывает раздражение.

Нормы:

  • ✅ < 0.1 — хорошо
  • 🟡 0.1–0.25 — требует улучшений
  • 🔴 > 0.25 — плохо

Как считается: каждый unexpected layout shift имеет impact fraction (% экрана который сдвинулся) × distance fraction (как далеко сдвинулся). CLS — сумма всех таких событий за сессию.

Типичные причины CLS:

1. Изображения без размеров

html
<!-- ❌ Плохо: браузер не знает сколько места зарезервировать -->
<img src="hero.jpg" alt="Hero">

<!-- ✅ Хорошо: резервирует место заранее -->
<img src="hero.jpg" alt="Hero" width="1200" height="600">

Или через CSS: aspect-ratio: 16/9.

2. Реклама и embed-контент без зарезервированного места

Рекламный блок появляется после загрузки страницы и сдвигает контент. Решение: резервируй место через min-height для рекламного блока.

3. Динамически вставляемый контент

Баннер «принять cookies» появляется поверх контента и сдвигает его. Решение: фиксированное позиционирование (position: fixed) вместо смещения потока.

4. Шрифты вызывающие FOUT/FOIT

Текст сначала показывается системным шрифтом, потом заменяется кастомным — и слегка сдвигается (разные размеры букв). Решение: font-display: optional (не показывает кастомный шрифт если не загружен) или size-adjust, ascent-override для максимального совпадения с fallback-шрифтом.

Как диагностировать:

Chrome DevTools → Performance → включи «Web Vitals» в настройках → запись при перезагрузке → в треке «Experience» видны CLS-события с указанием элементов.

Или: в Lighthouse-отчёте в деталях CLS — список конкретных элементов которые сдвигались.


Полный алгоритм аудита: шаг за шагом

Шаг 1: Полевые данные из Search Console

Начни не с Lighthouse, а с Google Search Console → Core Web Vitals.

Там видишь реальные данные по всем страницам сайта с разбивкой «хорошо / требует улучшений / плохо». Это позволяет приоритизировать: какие страницы и какие метрики проблемные у реальных пользователей.

URL: search.google.com/search-console → Core Web Vitals (в левом меню)

Шаг 2: Лабораторный анализ проблемных страниц

Для каждой проблемной страницы из Search Console — запусти PSI. Смотри на:

  1. Что является LCP-элементом
  2. TBT (прокси для INP)
  3. CLS-нарушители
  4. Топ-5 «Opportunities» по потенциальной экономии

Шаг 3: Глубокий анализ в DevTools

Для сложных случаев — Chrome DevTools → Performance.

plaintext
F12 → Performance → ⚙️ настройки:
- CPU throttling: 4x slowdown (эмуляция среднего смартфона)
- Network: Fast 4G
→ нажми Record → перезагрузи страницу → через 5–7 секунд Stop

Что смотреть в трейсе:

  • Main thread: длинные красные задачи (Long Tasks > 50 мс) — это TBT/INP
  • Network: waterfall загрузки ресурсов — что грузится последовательно вместо параллельно
  • Timings: маркеры FCP, LCP, DCL (DOMContentLoaded)
  • Frames: где происходят перерасчёты стилей (фиолетовые блоки)

Шаг 4: Анализ сети (Network panel)

DevTools → Network → перезагрузи страницу → сортируй по Size.

Ищи:

  • Изображения > 500 КБ (кандидаты на оптимизацию)
  • JavaScript-бандлы > 300 КБ (кандидаты на code splitting)
  • CSS-файлы > 100 КБ (возможно много неиспользуемого)
  • Ресурсы без кэша (нет Cache-Control заголовков)
  • Ресурсы с другого домена которые блокируют рендеринг

Шаг 5: Coverage — неиспользуемый код

DevTools → Ctrl+Shift+P → «Show Coverage» → Record → перезагрузи.

Покажет процент неиспользуемого JavaScript и CSS. 50–70% неиспользуемого JavaScript на первой загрузке — это норма для сложных SPA. Но > 80% — значит что-то явно не так с code splitting.


Приоритизация: что чинить первым

Не всё одинаково важно. Вот порядок по влиянию:

1. TTFB (Time to First Byte) — серверное время ответа

Если TTFB > 600 мс — всё остальное бессмысленно оптимизировать. Браузер ждёт сервер прежде чем начать что-то делать.

Как проверить: в Network → первый запрос → вкладка Timing → «Waiting (TTFB)».

Как улучшить:

  • CDN (Content Delivery Network) — ответ приходит с ближайшего сервера
  • Серверный кэш — не пересчитывать страницу для каждого запроса
  • Оптимизация базы данных (медленные запросы)
  • Апгрейд хостинга

2. LCP-изображение — самое влияющее на восприятие

  • Формат WebP или AVIF (в среднем 30–50% меньше PNG при том же качестве)
  • fetchpriority="high" на LCP-изображении
  • Правильный srcset чтобы не грузить 2000px на телефон
  • Preload: <link rel="preload" as="image" fetchpriority="high" href="hero.webp">

3. Render-blocking ресурсы

CSS в <head> без media атрибута блокирует рендеринг. JavaScript в <head> без defer блокирует рендеринг.

html
<!-- ❌ Блокирует рендеринг -->
<script src="analytics.js"></script>

<!-- ✅ Загружается параллельно, выполняется после HTML -->
<script src="analytics.js" defer></script>

<!-- ✅ Загружается и выполняется параллельно (порядок не гарантирован) -->
<script src="widget.js" async></script>

4. JavaScript bundle size

Крупные бандлы — главная причина высокого TBT и медленного INP.

  • Code splitting: загружай только то что нужно для текущей страницы
  • Tree shaking: удаляй неиспользуемый код из библиотек
  • Lazy loading: компоненты ниже fold грузи отложено

5. Изображения ниже fold

Все изображения которые не видны при первой загрузке:

html
<img src="photo.jpg" alt="..." loading="lazy">

Атрибут loading="lazy" — браузер не загружает изображение пока оно не приближается к viewport. Для изображений в первом экране — не используй (задержит LCP).


Типичные сценарии и решения

Сценарий: высокий CLS на мобайле из-за баннера

Баннер cookies появляется поверх контента и сдвигает его.

css
/* ❌ Плохо: баннер в потоке документа */
.cookie-banner {
  position: relative;
}

/* ✅ Хорошо: фиксированный, не сдвигает поток */
.cookie-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 1000;
}

Сценарий: медленный LCP из-за hero-изображения

Hero-изображение 1.2 МБ в PNG, грузится после CSS.

Чеклист исправления:

  1. Конвертируй в WebP: cwebp -q 80 hero.png -o hero.webp
  2. Добавь srcset для разных размеров
  3. Добавь preload в <head>:
html
<link rel="preload" as="image" href="hero.webp" 
      imagesrcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
      imagesizes="100vw"
      fetchpriority="high">
  1. На img добавь fetchpriority="high"

Сценарий: высокий TBT из-за тяжёлого JavaScript

TBT 1800 мс. В Coverage видно что 60% бандла не используется на текущей странице.

Чеклист:

  1. Анализ через Webpack Bundle Analyzer или Rollup Visualizer — что занимает место
  2. Dynamic imports для компонентов которые не нужны сразу
  3. Проверить нет ли дублирующихся зависимостей
  4. Заменить тяжёлые библиотеки на лёгкие альтернативы (moment.js → date-fns, lodash → lodash-es с tree shaking)

Инструменты для мониторинга в реальном времени

Разовый аудит — хорошо. Регулярный мониторинг — лучше.

Google Search Console — бесплатно, реальные данные от пользователей Chrome, оповещения при ухудшении. Обязательный инструмент для каждого сайта.

web-vitals.js — библиотека от Google для сбора CWV в аналитику:

javascript
import {onLCP, onINP, onCLS} from 'web-vitals';

onLCP(console.log);
onINP(console.log);
onCLS(console.log);

Подключи к своей аналитике (GA4, Amplitude, самописная) — получай реальные данные от своих пользователей.

Lighthouse CI — запускай Lighthouse автоматически в CI/CD при каждом деплое. Если оценка упала ниже порога — сборка падает.

Vercel Speed Insights, Netlify Analytics — встроенные инструменты у популярных хостингов.

WebPageTest (webpagetest.org) — более детальный чем PSI, позволяет тестировать с разных локаций, разных устройств, с видео-записью загрузки.


Часто задаваемые вопросы

«Оценка 100 = сайт быстрый?»

Нет. Оценка 100 в Lighthouse означает что ты хорошо выступил на синтетическом тесте. Реальные пользователи на реальных устройствах с реальным интернетом — другая история. Смотри на полевые данные в CrUX.

«Моя оценка каждый раз разная — почему?»

Лабораторные тесты имеют вариативность ±10–15% из-за загрузки серверов, шума в процессоре, параллельных задач. Для точности: запускай несколько раз и смотри на среднее. Или используй WebPageTest с несколькими прогонами.

«Сайт быстрый на десктопе, но медленный на мобайле в PSI»

Lighthouse для мобайла тестирует на эмулированном Moto G4 (медленный CPU) с эмулированным 4G соединением. Это намеренно пессимистичные условия. Реальный опыт зависит от твоей аудитории — если большинство на флагманах с 5G, оценка 55 для мобайла не означает плохой опыт.

«Реклама роняет CWV — что делать?»

Резервируй место под рекламный блок даже до загрузки рекламы: min-height: 250px (стандартный баннер). Используй position: sticky или fixed для блоков которые появляются поверх контента.


ИИ и аудит производительности: как Claude помогает

Промпт: интерпретировать отчёт PSI

plaintext
Вот данные из PageSpeed Insights для нашего сайта:

Мобайл: оценка [число]
LCP: [значение] сек
INP/TBT: [значение] мс
CLS: [значение]
FCP: [значение] сек

Топ-5 рекомендаций из раздела Opportunities:
[список с временем экономии]

Проанализируй:
1. Какие метрики критичны (влияют на Core Web Vitals и ранжирование)?
2. Что чинить в первую очередь — по соотношению влияния и сложности?
3. Что из списка Opportunities может быть решено быстро (1–2 дня)?
4. Какие проблемы требуют глубокой технической работы?

Промпт: план оптимизации для разработчика

plaintext
Нам нужно улучшить следующие показатели сайта:
— LCP: [текущее] → цель [целевое]
— CLS: [текущее] → цель < 0.1
— TBT: [текущее] → цель < 200 мс

Стек: [React/Vue/Next.js/WordPress/другое]
Хостинг: [описание]
Основные проблемы из Lighthouse: [список]

Составь технический план оптимизации:
1. Quick wins (до 1 дня работы) — что даст быстрый результат
2. Medium (1–3 дня) — более сложные изменения
3. Long-term (неделя+) — архитектурные улучшения

Для каждого пункта: что именно делать (конкретные изменения в коде или конфигурации).

Промпт: объяснить результаты стейкхолдерам

plaintext
Нам нужно объяснить результаты аудита производительности руководству / клиенту.

Текущая ситуация:
— Оценка PSI мобайл: [число]
— Основные проблемы: [список]
— Время загрузки: [секунды]

Напиши объяснение для нетехнической аудитории:
1. Что означают эти показатели простыми словами
2. Как это влияет на пользователей (конкретно)
3. Как это влияет на бизнес (конверсия, SEO, удержание)
4. Что мы планируем исправить и какого результата ожидаем

Без технического жаргона. Максимум 1 страница.

Промпт: code review для производительности

plaintext
Проверь этот код на проблемы с производительностью (LCP, CLS, INP):

[вставь HTML/CSS/JavaScript]

Контекст: это [описание страницы/компонента].

Найди:
1. Что может вызывать медленный LCP
2. Что может вызывать CLS
3. Что может блокировать main thread (влияет на INP)
4. Неоптимальная загрузка ресурсов

Для каждой проблемы: конкретное исправление с кодом.

Чеклист аудита производительности

Инструменты:

  • Проверены Core Web Vitals в Google Search Console (реальные данные)
  • Запущен PSI для главной и ключевых посадочных страниц (мобайл!)
  • Запущен Lighthouse в DevTools для страниц за авторизацией
  • Проверен TTFB в Network panel

LCP:

  • Определён LCP-элемент (что именно)
  • Изображение в WebP/AVIF с правильными размерами
  • Preload для LCP-изображения в <head>
  • fetchpriority="high" на LCP-изображении
  • TTFB < 600 мс

CLS:

  • Все изображения имеют атрибуты width и height
  • Место под рекламу и embed зарезервировано
  • Динамически появляющийся контент не сдвигает поток (position: fixed)
  • Шрифты с font-display: swap и fallback близкий по размеру

INP / TBT:

  • Нет Long Tasks > 50 мс в main thread (DevTools Performance)
  • JavaScript-бандлы < 300 КБ для первой загрузки
  • Сторонние скрипты загружаются с defer или async
  • Тяжёлые обработчики с debounce/throttle

Ресурсы:

  • Изображения ниже fold с loading="lazy"
  • Критичный CSS inline или preload
  • Некритичный JavaScript с defer
  • Cache-Control заголовки на статических ресурсах
  • Gzip или Brotli сжатие включено на сервере
$ cd ../ ← назад к UX и интерфейсы