Error! NO_LCP: как 4 пикселя сломали PageSpeed, и как мы ловили их всю ночь

2026-07-29 06:48:36 Время чтения 6 мин 55

Обычная проверка сайта клининговой компании в PageSpeed Insights. Жду привычные цифры, а вижу: Largest Contentful Paint - Error! NO_LCP. Главная метрика скорости, по которой Google оценивает сайты, просто не измерялась. Не "плохая", не "красная" - её не было вообще. При этом остальное выглядело прилично: FCP 1,4 секунды, оценка 96 из 100. И до кучи пять аудитов диагностики падали со словом "Ошибка".

Прогнали ещё раз. И ещё. Мобильная версия, десктопная - везде NO_LCP.

Первая версия была удобной: это Google глючит. Проверили независимыми инструментами. Локальный Lighthouse той же версии 13.4.1, что у Google, - LCP измеряется, 1,9 секунды. SpeedVitals с сервером в Германии - Grade A, 94%, LCP 2,1. Полевые данные CrUX за 28 дней - LCP 1,7, Core Web Vitals пройдены. Три системы из четырёх меряют нормально. Значит, глючит движок PageSpeed, можно расходиться?

Не тут-то было. Прогнали через PSI второй сайт - личный, без сложной начинки. Всё измерилось идеально. Значит, что-то именно на этом сайте ломает замер.

Дальше - классический перебор подозреваемых. Бегущая лента из 22 логотипов партнёров: отложили старт на 2 секунды - NO_LCP на месте. Полупрозрачная hero-картинка с opacity 0.3 (новые Chrome исключают такие из кандидатов в LCP): сделали непрозрачной - локальный LCP стал красивым, в PSI по-прежнему NO_LCP. Коллтрекинг: скрипт подмены номеров сбрасывал кандидатов в LCP девять раз за загрузку - отключили, LCP упал с 6,7 до 3,9 секунды, но NO_LCP не делся никуда. Шрифты со свапом - мимо. Раздутый до 25 МБ трейс - похудел на треть, score локально 95, в PSI угадайте что.

Счёт к трём часам ночи: пять гипотез, пять частичных улучшений (сайт объективно стал быстрее!), ноль решений.

Ключевое решение ночи - перестать интерпретировать отчёты Lighthouse и напрямую спросить браузер. Взяли канареечный Chrome, запустили через puppeteer и повесили на страницу простейшую пробу: PerformanceObserver на largest-contentful-paint плюс слушатель скроллов. Контрольный сайт выдал две здоровые записи LCP. Наш - одну: крошечный логотип в шапке на 8 016 квадратных пикселей. Огромный заголовок и hero-картинку на треть экрана браузер будто не видел.

LCP-поток не сбоил - он умирал в первую секунду. А по спецификации наблюдение LCP необратимо останавливается ровно от двух вещей: действия пользователя или скролла.

Заблокировали вообще все скрипты на странице. Чистый HTML+CSS. И проба показала: scrolls: 4, первый на 1193 мс. Страница без единого скрипта скроллила сама себя.

Виновником оказалась карусель "Наши работы": в её CSS стояли scroll-snap-type: x mandatory и padding: 4px. Из-за паддинга первый слайд стоит в четырёх пикселях от края, mandatory-снап требует прижать его к снап-точке - и браузер в момент применения стилей сам доскролливает карусель на эти 4 пикселя. Никакого JS. А такое scroll-событие - программное, внутреннего контейнера, на 4 пикселя - навсегда останавливает наблюдение LCP в новых Chrome. Больше ни один элемент не может стать LCP. PageSpeed разводит руками: Error! NO_LCP.

Фикс - одна строка: scroll-padding-inline: 4px. Снап-точка учитывает паддинг, браузеру нечего доскролливать. Результат: LCP 0,9 секунды на десктопе, 2,9 на мобайле, CLS упал с 0,447 до 0,008 - в 50 раз, Performance 89-93, все аудиты живые.

Затраты: три часа расследования, восемь гипотез, полтора десятка замеров четырьмя инструментами. Решение - одна строка CSS против четырёх пикселей.

Могло ли это уронить SEO? Пока нет: Google ранжирует по полевым данным CrUX, а у реального человека первый же тап или скролл останавливает наблюдение LCP до того, как баг успевает сработать - позиции не пострадали. Но мина тикала: с мёртвым LCP невозможно заметить настоящую деградацию, реальные сдвиги макета уже копились, ужесточённая логика LCP из тестовых сборок Chrome со временем доезжает до стабильных - и до полевых метрик. А любой аудитор, открыв PageSpeed с пятью сломанными аудитами, сделал бы вывод "сайт сломан".

Главный практический вывод: зелёные полевые метрики - не повод игнорировать сломанную лабораторию. Полевые данные показывают прошлое - последние 28 дней существующей аудитории. Лаборатория - будущее: что увидит новый посетитель и новый браузер. Когда они противоречат друг другу, это не глюк одного из них - это разрыв, в котором прячется проблема.

Полная версия расследования - с кодом проб, трейсами и всеми уликами: dimaserbun.ru/blog/error-no-lcp-4-pikselya. Вопросы - в Telegram @dimik90.