CLS (Cumulative Layout Shift — совокупный сдвиг макета) — метрика Core Web Vitals, которая измеряет визуальную нестабильность страницы в процессе загрузки. Проще говоря: насколько элементы страницы «прыгают» и перемещаются, пока пользователь её открывает.
Высокий CLS — не просто технический недостаток. Это реальное неудобство: пользователь читает текст, и он внезапно съезжает вниз из-за загрузившегося баннера. Или нажимает кнопку, которая только что сдвинулась, и попадает не туда.
Яндекс учитывает CLS при ранжировании. Хорошее значение: CLS < 0,1. Плохое: CLS > 0,25.
Как измеряется CLS
CLS рассчитывается как сумма произведений «фракции воздействия» на «фракцию расстояния» для каждого неожиданного сдвига макета в течение всего жизненного цикла страницы.
На практике важно знать:
- Сдвиг, вызванный действием пользователя (клик, скролл), не учитывается
- Учитываются только сдвиги, которые происходят без взаимодействия пользователя
- Чем больший процент экрана сдвинулся и чем дальше он переместился — тем хуже CLS
Инструменты для диагностики CLS
PageSpeed Insights — показывает общее значение CLS и в некоторых случаях указывает проблемные элементы.
Chrome DevTools → Performance → Layout Shifts — фиолетовые маркеры «Layout Shift» на таймлайне показывают каждый сдвиг. Кликнув на него, можно увидеть, какой элемент сдвинулся.
Web Vitals расширение для Chrome — показывает CLS в реальном времени при просмотре страницы.
Яндекс Вебмастер — раздел Core Web Vitals, реальные данные пользователей.
Для систематического мониторинга после исправлений удобно использовать ClickFlow — сервис позволяет отслеживать динамику Core Web Vitals в связке с позициями по ключевым запросам.
Причина 1: Изображения без указанных размеров
Самая распространённая причина CLS. Когда браузер начинает рендерить HTML, он не знает размеры изображений до их загрузки. Когда изображение загружается — оно «раздвигает» контент вокруг себя.
Решение: всегда указывайте атрибуты width и height на теге <img>.
<!-- Плохо -->
<img src="product.jpg" alt="Товар">
<!-- Хорошо -->
<img src="product.jpg" alt="Товар" width="800" height="600">
Браузер использует эти значения для вычисления соотношения сторон и резервирует место ещё до загрузки изображения. При адаптивном дизайне CSS max-width: 100% продолжает работать корректно.
Для фоновых изображений в CSS резервируйте место через padding-top в процентах или свойство aspect-ratio:
.hero-image {
aspect-ratio: 16 / 9;
width: 100%;
}
Причина 2: Реклама, виджеты и встраиваемый контент
Рекламные блоки — один из главных источников CLS. Рекламная система загружает баннер асинхронно, и он появляется уже после рендеринга основного контента, сдвигая его.
Решения:
Резервирование места под рекламу:
.ad-container {
min-height: 250px; /* Типичная высота баннера */
width: 100%;
}
Статичный контейнер с фиксированными размерами — создайте div с явными размерами, в который загружается реклама. Контент за пределами блока не сдвинется.
Размещение рекламы в «безопасных» местах — внизу страницы или в боковых колонках, где сдвиг не затрагивает основной контент.
Аналогично для встраиваемых iframe (YouTube, карты):
<div style="position: relative; padding-top: 56.25%;">
<iframe style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
src="https://www.youtube.com/embed/...">
</iframe>
</div>
Причина 3: Веб-шрифты и FOUT/FOIT
При загрузке кастомных шрифтов браузер сначала показывает системный шрифт (FOUT — Flash of Unstyled Text) или вообще скрывает текст (FOIT — Flash of Invisible Text). Когда шрифт загружается — текст перерисовывается, и если размеры символов отличаются — происходит сдвиг макета.
Решения:
font-display: swap — браузер сразу показывает резервный шрифт, а после загрузки кастомного заменяет. Сдвиг может быть, но текст виден сразу.
font-display: optional — если шрифт не загружен за очень короткое время, используется резервный и кастомный не применяется. Нет сдвига, но шрифт может не отобразиться.
Preload шрифтов:
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
Size-adjust дескриптор — позволяет настроить размер резервного шрифта так, чтобы он максимально точно совпадал с кастомным:
@font-face {
font-family: 'FallbackFont';
src: local('Arial');
size-adjust: 96%;
ascent-override: 105%;
}
Самохостинг шрифтов вместо Google Fonts — устраняет дополнительный DNS-запрос и снижает время загрузки.
Причина 4: Динамически добавляемый контент
Контент, добавляемый JavaScript'ом после рендеринга страницы: куки-баннеры, уведомления, чат-виджеты, динамические блоки.
Правила:
Куки-баннер — размещайте в фиксированном (fixed) или прикреплённом (sticky) позиционировании, чтобы он перекрывал контент, а не двигал его:
.cookie-banner {
position: fixed;
bottom: 0;
left: 0;
right: 0;
}
Чат-виджеты — большинство современных чат-систем уже позиционируют виджет через position: fixed. Проверьте настройки вашего провайдера.
Динамические блоки — если блок появляется при взаимодействии пользователя (клик, hover), CLS не начисляется. Если появляется автоматически при загрузке — резервируйте место заранее.
Причина 5: Анимации и переходы
Некоторые CSS-анимации вызывают сдвиг макета. Основное правило: анимировать можно только transform и opacity без влияния на CLS. Свойства, меняющие геометрию элемента (top, left, margin, padding, width, height), вызывают Layout и могут влиять на CLS.
Правильно:
/* Используем transform вместо изменения top/left */
.element {
transform: translateY(0);
transition: transform 0.3s ease;
}
.element.active {
transform: translateY(-20px);
}
Причина 6: Skeleton-экраны и плейсхолдеры
Если при загрузке данных через API страница сначала показывает skeleton (заглушки), а потом заменяет их реальным контентом — важно, чтобы размеры совпадали.
Правило: skeleton должен быть идентичен по высоте реальному контенту. Если текст занимает 3 строки — плейсхолдер тоже должен занимать 3 строки.
Диагностика CLS в реальных условиях
Лабораторные инструменты (Lighthouse) не всегда воспроизводят реальный CLS. Часть сдвигов происходит только при медленном соединении или на конкретных устройствах.
Для диагностики реального CLS:
- Откройте Chrome DevTools на реальном устройстве
- В Network throttling выберите «Slow 3G»
- Запишите загрузку страницы через Performance
- Проанализируйте Layout Shift события
Чек-лист устранения CLS
- [ ] Все изображения имеют атрибуты width и height
- [ ] Для адаптивных изображений используется aspect-ratio в CSS
- [ ] Рекламные места имеют фиксированные размеры контейнера
- [ ] iframe-вставки завёрнуты в responsive-контейнер
- [ ] Шрифты загружаются с preload и font-display: swap или optional
- [ ] Куки-баннеры и уведомления используют fixed-позиционирование
- [ ] Динамический контент не сдвигает существующие элементы
- [ ] Анимации используют transform/opacity, а не позиционные свойства
- [ ] CLS проверен при эмуляции медленного соединения
- [ ] Яндекс Вебмастер — Core Web Vitals показывают CLS < 0,1
Итог
CLS — самая «невидимая» из метрик Core Web Vitals: разработчики часто тестируют страницы на быстром соединении, где сдвиги не заметны. Системный подход включает диагностику каждого источника сдвига, резервирование пространства для динамического контента и тестирование на медленных соединениях. Достижение CLS < 0,1 — вполне реальная задача для большинства сайтов при последовательном устранении причин.