CLS 0.377 → 0.002 за день: три раунда правок critical CSS
Layout-сдвиг 0.377 на старте сайта. К вечеру того же дня - 0.002. Три правки: размеры логотипа, header-nav в critical CSS, Inter Fallback с size-adjust:107%.
22 марта 2026 я выкатил новый сайт клиниговой компании, в которой веду маркетинг как РОМ. На первом прогоне через Lighthouse мобильный отчёт показал CLS 0.377 - красная зона, конкретно режется ранжирование и в Google, и в Яндексе. К вечеру того же дня - 0.002. Три правки, не переписывая сайт.
Если коротко
- На старте CLS 0.377. После трёх правок critical CSS - 0.002. Один рабочий день.
- Правка №1: атрибуты
widthиheightна логотип в шапке. Сэкономила ~40% сдвига.- Правка №2: правила для
.header-navперенёс в инлайн critical CSS в<head>. Шапка перестала прыгать.- Правка №3: фолбэк-шрифт Inter Fallback на базе Arial с
size-adjust:107%иascent-override:90%. FOUT перестал двигать тексты при догрузке woff2.
Что такое CLS и почему 0.377 - это плохо
Cumulative Layout Shift - это метрика, которую Google ввёл в 2020 году как часть Core Web Vitals. Она считает, сколько раз и насколько сильно содержимое страницы прыгает при загрузке. Прыжок - это когда блок текста или картинка смещаются после того, как пользователь уже видит страницу, и не из-за его действия. Зелёная зона до 0.1, выше 0.25 - красная.
Google и Яндекс учитывают Core Web Vitals в общей оценке качества сайта - не как один-в-один фактор ранжирования, а как сигнал в комплексе. Сайт с CLS 0.377 проигрывает соседям из той же выдачи, даже если контент и ссылки сильнее.
На моём первом замере было 0.377. Это значит, что Lighthouse-роботу казалось, что страница буквально прыгает. Не очень удивительно: я ставил приоритет на быстрый запуск, а не на полировку метрик. Через четыре дня после релиза собрался и за один вечер закрыл все три причины.
Раунд 1: размеры логотипа в HTML
Первое, что выдал Lighthouse в Performance Insights - “Image elements do not have explicit width and height”. Конкретно - логотип в шапке. У меня в header.php было так:
<a href="/" class="header__logo">
<img src="/logo.svg" alt="Компания" />
</a>
Браузер не знает, какого размера логотип будет на готовой странице, пока его реально не скачает. И пока не скачает - резервирует место по дефолту. Когда логотип догружается, его реальный размер «выталкивает» соседние блоки. Шапка резко сдвигается на пол-секунды, и за этим уезжает hero.
Правка элементарная:
<a href="/" class="header__logo">
<img src="/logo.svg" alt="Компания" width="180" height="44" />
</a>
Браузер видит атрибуты, считает aspect-ratio 180/44, резервирует место сразу. Когда логотип догружается, никаких сдвигов.
Аналогичная история была с hero-картинкой на главной - <img> без размеров и без CSS-резервирования. Туда тоже добавил width="1200" height="630" и для надёжности style="aspect-ratio: 1200/630". После этих двух правок CLS упал с 0.377 до примерно 0.21. Уже жёлтая зона, но ещё не зелёная.
Урок. Размеры на каждый <img> - самая дешёвая правка в CWV. Поддержка во всех браузерах с 2020 года, никаких рисков. Если у вас старый сайт без них - это первое, что нужно поставить, до всего остального.
Раунд 2: header-nav в critical CSS
После первой правки шапка всё ещё «вырастала» сверху страницы на полсекунды. Я смотрел в Performance-вкладке Chrome DevTools - между First Paint и First Contentful Paint браузер ещё не применял стили .header-nav, поэтому шапка рендерилась как столбик ссылок без флексов, без отступов, без бордеров. И потом, когда CSS-файл догружался, шапка резко принимала вид.
В моём <head> уже был блок инлайн critical CSS - стили body, .hero, h1, базовая типографика. Но правил для шапки там не было. Они лежали в /css/main.css, который грузился отдельным запросом и применялся уже после.
Перенёс блок шапки в инлайн critical:
<style>
/* ...уже было... */
/* CRITICAL: header */
.header { background: #fff; border-bottom: 1px solid #e8e8e8; padding: 14px 0; }
.header__inner { max-width: 1200px; margin: 0 auto; padding: 0 24px; display: flex; align-items: center; justify-content: space-between; gap: 32px; }
.header__logo { display: inline-flex; }
.header-nav { display: flex; gap: 24px; align-items: center; }
.header-nav a { color: #1a1a1a; text-decoration: none; font-weight: 500; }
/* + мобильный бургер */
@media (max-width: 768px) { .header-nav { display: none; } .header__burger { display: block; } }
</style>
Из основного main.css эти же правила убрал - чтобы дубля не было. После пересборки CLS упал с 0.21 до 0.05. Зелёная зона.
Идея простая - всё, что отрисовывается выше fold и видно в первый кадр, должно быть в инлайн critical CSS. Тогда браузер рисует страницу за один проход, без перерисовок.
Раунд 3: Inter Fallback с size-adjust
CLS 0.05 - уже норма, но я хотел загнать в почти-ноль. Оставшийся сдвиг приходил от шрифта. Inter я хостил сам в /fonts/inter.woff2 и подключал так:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-weight: 100 900;
font-display: swap;
}
body { font-family: 'Inter', Arial, sans-serif; }
Что происходило при загрузке. Первый кадр - браузер видит, что Inter ещё не пришёл, рисует текст Arial. Текст занимает место по метрикам Arial - это другая ширина букв, другая высота строки. Когда woff2 догружается (через 200-400 мс на 4G), браузер мгновенно перерисовывает текст Inter. Метрики меняются: предложение, которое занимало две строки, теперь занимает полторы. Блок под ним поднимается вверх на 28 пикселей. CLS считает это сдвигом.
Решение - фолбэк-шрифт с такими же метриками, как у целевого. Я взял Arial как базу (есть на всех системах, не нужно качать) и подкрутил его через size-adjust и ascent-override так, чтобы метрики совпали с Inter.
Вот рабочая комбинация:
@font-face {
font-family: 'Inter Fallback';
src: local('Arial');
size-adjust: 107%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-weight: 100 900;
font-display: swap;
}
body { font-family: 'Inter', 'Inter Fallback', Arial, sans-serif; }
Что это делает. Браузер сначала пробует Inter - пока его нет, идёт по стеку дальше. Видит «Inter Fallback» - это, по сути, Arial с растянутыми метриками. Текст занимает столько же места, сколько займёт Inter после догрузки. Когда настоящий Inter догружается через 300 мс, текст просто меняет внешний вид, но не сдвигает разметку - метрики уже совпадают.
Где взять значения. Я брал из репозитория Capsize, там есть готовые таблицы для популярных пар «целевой шрифт + Arial». Для Inter с Arial рабочие: size-adjust:107%, ascent-override:90%, descent-override:22%. Если у вас другой основной шрифт - нужно посчитать через калькулятор Capsize или fontkit.
После этой правки CLS упал до 0.002. Lighthouse мобильный - зелёная зона, поле в отчёте окрасилось зелёным. Я ради спортивного интереса прогнал ещё через PageSpeed Insights на field data Чрома - там тоже 0.002 после трёх дней накопления.
Что замерили после
| Метрика | До | После |
|---|---|---|
| CLS Lighthouse mobile | 0.377 | 0.002 |
| CLS PageSpeed field data | (нет, новый сайт) | 0.002 (через 3 дня) |
| LCP mobile | 4.5 с | 2.4 с (попутно с CLS - за счёт preload hero) |
| Lighthouse Performance | ~60 | 93 |
Параллельно с CLS на третьем раунде я добавил <link rel="preload" as="image" href="/hero.webp" fetchpriority="high"> для hero-картинки - это снизило LCP. Это не часть CLS-истории, но картинка вытянулась попутно.
Если бы делал заново - в день один, не на 4-й
Главный вывод. Все три правки можно было сделать на старте, ещё до релиза. Они не требуют переписывать сайт, они не требуют перехода на новый стек, они занимают 3-4 часа на двух кофе.
Я их откладывал «потом», и в итоге сайт жил в красной зоне четыре дня. На новом домене эти четыре дня могли стоить мне ранжирования: и Google, и Яндекс берут CWV в первый прогон оценки нового сайта. Если первый замер красный - потом догонять долго.
Чек-лист на день один любого нового сайта:
- Все
<img>с атрибутамиwidthиheight. Это правило, а не желательно. - Header и hero полностью в инлайн critical CSS. Никаких внешних запросов на стили выше fold.
- Self-hosted шрифты с фолбэком через
size-adjustот системного. Не оставляйте Arial без подкрутки - он не совпадает по метрикам ни с Inter, ни с Roboto, ни с Open Sans. - Lighthouse прогон до релиза. Если CLS >0.1 - релиз откладываете, пока не закроете.
Целиком кейс по 50 дням SEO в B2B-клининге - в статье «50 дней SEO в B2B-клининге», там CLS - один из пунктов в широкой картине метрик.
Если у вас сайт с похожей проблемой и нужна точечная помощь - пишите в Telegram @dimik90. По услугам:
- SEO для услуг - полный цикл: техника, schema, контент, программатик
- Независимый аудит подрядчика - проверка работы текущего SEO-агентства
Близкое по теме: как я работаю - без воды и 40-страничных КП.
Вопрос-ответ