Core Web Vitals для PHP-сайтов: как исправить LCP, INP и CLS
Core Web Vitals измеряются в браузере, но на PHP-сайте значительная часть результата определяется сервером. В этом гайде - куда смотреть в первую очередь, какие изменения в PHP, nginx и фронтенде двигают цифры и как измерять, не обманывая себя.
Коротко
- Три метрики: Largest Contentful Paint (LCP) меньше 2,5 с, Interaction to Next Paint (INP) меньше 200 мс, Cumulative Layout Shift (CLS) меньше 0,1; оценивается 75-й перцентиль реальных пользователей.
- Начните со времени ответа сервера (TTFB): OPcache, настроенный пул PHP-FPM, кэш страниц или фрагментов и CDN обычно дают самый большой выигрыш по LCP на PHP-сайтах.
- Займитесь LCP-элементом осознанно: подберите размер hero-картинки, отдавайте WebP, добавьте
fetchpriority="high"и никогда не ленивую загрузку. - Резервируйте место под изображения, рекламу и встраиваемые блоки, чтобы убрать сдвиги макета; используйте
font-display: swapи предзагрузку шрифтов. - Сначала смотрите полевые данные (Search Console, CrUX), потом воспроизводите проблему в Lighthouse и панели Performance браузера.
Core Web Vitals для PHP-сайтов - это не только тема фронтенда. Медленная PHP-страница может тратить секунду просто на генерацию HTML, и никакая оптимизация картинок этого не вернёт. И наоборот: быстрый сервер не поможет, если крупнейшую отрисовку блокирует hero-картинка на 1,5 МБ. Так мы подходим к обеим сторонам на своих PHP-сайтах (integrono.com работает на PHP-FPM за nginx и Cloudflare) и в проектах клиентов.
Что измеряют Core Web Vitals
- LCP (Largest Contentful Paint): когда отрисован самый большой видимый элемент (обычно hero-картинка или блок заголовка). Хорошо - 2,5 секунды и меньше.
- INP (Interaction to Next Paint): как быстро страница визуально реагирует на клики, касания и нажатия клавиш за всё посещение. Хорошо - 200 мс и меньше.
- CLS (Cumulative Layout Shift): насколько контент «прыгает» при загрузке. Хорошо - 0,1 и меньше.
Google оценивает их по полевым данным реальных пользователей Chrome, по 75-му перцентилю, отдельно для мобильных и десктопа. Поэтому один медленный шаблон или одна медленная страна могут провалить всю группу. Лабораторные инструменты вроде Lighthouse нужны для отладки, а не для итоговой оценки.
Шаг 1. Измеряйте правильно
- Откройте отчёт Core Web Vitals в Google Search Console, чтобы увидеть, какие группы URL не проходят и по какой метрике.
- Проверьте в PageSpeed Insights по одному URL из каждой проблемной группы. Важен верхний блок «полевые данные», а блок Lighthouse ниже - лабораторный тест, который объясняет причины.
- Используйте панель Performance в Chrome DevTools с замедлением CPU в 4 раза и сетью «Slow 4G», чтобы воспроизвести типичный мобильный опыт.
- Для постоянного мониторинга собирайте данные реальных пользователей библиотекой
web-vitalsи отправляйте их в аналитику.
<script type="module">
import {onLCP, onINP, onCLS} from 'https://unpkg.com/web-vitals@4?module';
const send = (m) => navigator.sendBeacon('/vitals', JSON.stringify({
name: m.name, value: m.value, id: m.id, url: location.pathname
}));
onLCP(send); onINP(send); onCLS(send);
</script>
Шаг 2. Сначала исправьте время ответа сервера (TTFB)
В LCP входит время до первого байта. Если HTML генерируется 800 мс, треть бюджета уже потрачена. На PHP-сайтах основные рычаги такие:
- Включите OPcache и убедитесь, что его размера хватает для всех скриптов. Без него PHP компилирует файлы заново при каждом запросе.
- Настройте PHP-FPM. Слишком мало воркеров ставит запросы в очередь, слишком много исчерпывает память. Следите на странице статуса PHP-FPM за «listen queue» и «max children reached».
- Кэшируйте страницы целиком для анонимных посетителей (nginx
fastcgi_cache, кэш ответов в Laravel или правила кэширования Cloudflare), а фрагменты и результаты запросов - в Redis. - Исправьте медленные запросы. Включите slow query log, найдите паттерны N+1 и добавьте индексы. Страница с 120 запросами медленная при любой версии PHP.
- Обновляйте PHP. Новые версии быстрее и экономнее по памяти.
# php.ini (production)
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; reload php-fpm on each deploy
# php-fpm pool
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500
Значение pm.max_children считайте от реальной памяти: разделите память, которую можно отдать PHP, на средний размер процесса воркера (смотрите через ps). При validate_timestamps=0 не забывайте перезагружать PHP-FPM после каждого деплоя, иначе в памяти останется старый код.
На уровне веб-сервера включите HTTP/2 или HTTP/3, Brotli или gzip и долгие заголовки кэширования для статики:
location ~* \.(?:css|js|webp|avif|jpg|png|svg|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
Используйте версионные имена файлов или параметр ?v= на основе времени изменения файла, чтобы «immutable» никогда не отдавал устаревшие ресурсы.
Шаг 3. Исправьте LCP-элемент
Найдите LCP-элемент в PageSpeed Insights или панели Performance в DevTools. На большинстве контентных страниц это hero-картинка. Дальше:
- Не используйте для неё ленивую загрузку.
loading="lazy"на LCP-картинке задерживает её. Вместо этого поставьтеfetchpriority="high". - Отдавайте нужный размер. Картинка 2400 px для слота 900 px - лишние байты. Используйте
srcsetиsizes. - Используйте WebP или AVIF. Обычная экономия - от 30 до 60 процентов по сравнению с JPEG при схожем качестве.
- Избегайте цепочек. Картинка, заданная фоном в CSS или вставленная JavaScript, обнаруживается поздно. Положите её в HTML как
<img>. - Используйте preconnect или свой хостинг для сторонних источников, от которых зависит LCP (шрифты, CDN картинок).
<img src="/images/hero-1200.webp"
srcset="/images/hero-640.webp 640w, /images/hero-1200.webp 1200w"
sizes="(max-width: 1040px) 92vw, 960px"
width="1200" height="630"
alt="Descriptive alt text"
decoding="async" fetchpriority="high">
По такому шаблону сделаны обложки статей в этом блоге: два размера WebP, явные размеры и высокий приоритет загрузки для hero.
Шаг 4. Уберите сдвиги макета (CLS)
- Всегда задавайте
widthиheight(илиaspect-ratioв CSS) для изображений, видео и iframe, чтобы браузер резервировал место. - Резервируйте место под баннеры, уведомления о cookie и рекламу. Вставляйте их в контейнер с фиксированной минимальной высотой, а не сдвигайте контент после загрузки.
- Шрифты: используйте
font-display: swapилиoptional, предзагружайте основной файл шрифта и делайте subset. Подберите запасной шрифт с похожими метриками. - Не вставляйте контент над уже показанным, если это не результат действия пользователя.
- Анимируйте через
transformиopacity, а не через свойства, меняющие макет (top,height).
Шаг 5. Улучшите INP: меньше JavaScript в основном потоке
INP - самая новая метрика, и PHP-разработчики её часто упускают, потому что сервер на неё напрямую не влияет. Причины лежат в браузере: длинные задачи из больших бандлов, тяжёлые сторонние скрипты (аналитика, чат-виджеты, менеджеры тегов) и обработчики, которые синхронно делают слишком много работы.
- Проведите аудит сторонних скриптов. Удалите те, что никому не нужны, остальные загружайте с
deferили после первого взаимодействия. - Разбивайте длинные задачи. Делите работу на части через
requestIdleCallback,setTimeoutили Scheduler API, тяжёлые вычисления выносите в Web Worker. - Держите DOM небольшим. Тысячи узлов замедляют каждое обновление.
- Избегайте принудительных синхронных перерасчётов макета в циклах (чередование чтения и записи свойств макета).
- Показывайте мгновенную обратную связь (состояние нажатия или индикатор) до начала медленной работы.
Шаг 6. Закрепите результат в процессе деплоя
Производительность деградирует незаметно: новый тег, более тяжёлая обложка, лишний запрос на главной. Добавьте Lighthouse CI или регулярную проверку через PageSpeed API для пяти самых важных шаблонов, задайте бюджеты (LCP, общий размер JS, вес картинок) и настройте оповещения о превышении. Сравнивайте TTFB до и после каждого релиза: если он подскочил, причина почти всегда в запросе или кэше, который перестал срабатывать.
Реалистичный порядок работ
- Измерьте полевые данные и определите проблемные группы URL.
- Включите OPcache, пересмотрите настройки PHP-FPM, добавьте кэш целых страниц для анонимного трафика.
- Исправьте hero-картинки: формат, размер, приоритет, размеры.
- Зарезервируйте место для всего, что загружается поздно.
- Сократите и отложите JavaScript, уберите ненужные сторонние скрипты.
- Измерьте повторно через 28 дней: полевые данные - скользящее окно.
Улучшения будут появляться в Search Console постепенно: отчёт использует примерно последние 28 дней, поэтому исправление, выкаченное сегодня, полностью проявится примерно через месяц.
Чем мы можем помочь
Мы занимаемся производительностью PHP и Laravel проектов в рамках технического SEO и отдельными работами: кэш, запросы, изображения и правки фронтенда прямо в коде. Если хотите понять, какие из изменений выше окупятся именно на вашем сайте, запишитесь на консультацию или анализ сервера. Более широкий чек-лист по сканированию и индексации - в статье технический SEO-аудит.
Частые вопросы
Какие значения Core Web Vitals считаются хорошими?
LCP 2,5 секунды и меньше, INP 200 миллисекунд и меньше и CLS 0,1 и меньше, по 75-му перцентилю реальных посещений.
Влияют ли Core Web Vitals на позиции в Google?
Они входят в сигналы page experience и являются фактором ранжирования умеренного веса. Релевантность и контент важнее, но медленная или нестабильная страница хуже конвертирует, и для бизнеса это часто дороже.
Как PHP влияет на Core Web Vitals?
В основном через время ответа сервера (TTFB), которое входит в LCP. Его снижают OPcache, настроенный PHP-FPM, кэширование, быстрые запросы и актуальная версия PHP. На INP и CLS PHP напрямую не влияет, они зависят от фронтенд-кода и вёрстки.
Почему PageSpeed Insights показывает не те цифры, что Search Console?
PageSpeed Insights показывает лабораторный тест одного URL плюс полевые данные, если они есть, а Search Console - полевые данные по группам URL примерно за 28 дней. Об успехе судите по полевым данным.
Через сколько улучшения появятся в Search Console?
Отчёт Core Web Vitals использует скользящее окно в 28 дней реальных данных, поэтому полный эффект исправления видно примерно через четыре недели.
Бесплатный discovery-звонок
Хаотичный стек или зависшая интеграция - Integrono наметит самый умный первый шаг.
Вы получаете senior-взгляд на бюджетные ловушки, зависимости и когда покупать, склеивать или писать - до старта оплаты. CEO остаётся в контуре.