Оптимізація CLS у 2026 році: повний гід зі зменшення Cumulative Layout Shift
Як зменшити Cumulative Layout Shift нижче 0.1 у 2026 році: розміри зображень, font metric overrides, реклама без зсуву, View Transitions API і налагодження в Chrome DevTools з робочими прикладами коду.
Оптимізація CLS (Cumulative Layout Shift) у 2026 році зводиться до однієї простої ідеї: не дозволяти браузеру переставляти вже намальовані елементи. Хороший показник CLS (менше 0.1 для 75% візитів) досягається через резервування простору для зображень, відео й реклами, керування завантаженням шрифтів за допомогою size-adjust та font-display, а також відмову від анімацій тих властивостей, які викликають reflow. Чесно кажучи, я ловив цей баг безліч разів на своїх проєктах, і нижче ми по черзі розберемо всі основні причини layout shift та подивимось робочий код, який зменшує CLS на реальних сторінках.
CLS це сума всіх несподіваних зсувів макета на сторінці; цільовий показник нижче 0.1 (75-й перцентиль).
Найчастіші причини: зображення без розмірів, веб-шрифти, динамічна реклама, банери згоди cookies та late-injected DOM.
Атрибути width/height разом із CSS aspect-ratio усувають shift від медіа майже повністю.
Для шрифтів використовуйте size-adjust, ascent-override, descent-override в @font-face, і FOUT-зсув просто зникає.
У 2026 році Chrome DevTools Performance Insights автоматично показує найбільший layout shift і відповідальний DOM-вузол.
View Transitions API та CSS content-visibility допомагають уникнути зсувів під час навігації між сторінками.
Що таке CLS і як він рахується у 2026 році
Cumulative Layout Shift (CLS) це метрика Core Web Vitals, що вимірює загальну візуальну нестабільність сторінки протягом усього її життєвого циклу. Простіше кажучи: коли користувач читає текст, а кнопка раптом стрибає на 200 пікселів вниз (бо зверху довантажилося зображення), це і є layout shift. CLS обчислюється як сума оцінок усіх несподіваних зсувів у межах session window, тобто інтервалу до 5 секунд, де паузи між зсувами не перевищують 1 секунди. Підсумкове значення CLS сторінки це найбільша така session window.
Формула оцінки кожного зсуву виглядає так: impact fraction × distance fraction. Impact fraction це частка viewport, яку займають елементи, що змінили позицію, а distance fraction це максимальна відстань, на яку вони змістилися, відносно більшої зі сторін viewport. На практиці це означає, що зсув великого блока на 100 пікселів коштує значно дорожче, ніж зсув маленької іконки на ту ж саму відстань.
У 2026 році Google підтверджує пороги: good до 0.1, needs improvement від 0.1 до 0.25, poor вище 0.25. Метрика враховується на 75-му перцентилі реальних користувачів (CrUX). Зсуви, що сталися в межах 500 мс після взаємодії користувача (клік, тап, скрол), позначаються прапором hadRecentInput і не зараховуються, тому розгортання акордеону чи модальне вікно не псує метрику. Деталі алгоритму описано у офіційному гіді web.dev про CLS.
Як виміряти CLS: інструменти 2026 року
Існує два типи вимірювань: лабораторне (Lighthouse, WebPageTest) і польове (CrUX, Real User Monitoring). Лабораторні тести дають відтворюваний бенчмарк, але часто пропускають зсуви, які виникають після взаємодій або в умовах повільної мережі реальних користувачів. Польові ж дані це авторитетне джерело істини для Search Console.
Базовий набір інструментів станом на 2026 рік:
Chrome DevTools → Performance → Insights: автоматично виділяє "Largest layout shift" і показує DOM-вузли, що змістилися, з кадрами before/after.
PageSpeed Insights: показує CrUX-дані за останні 28 днів плюс лабораторний Lighthouse-прогон.
web-vitals JS бібліотека (v4+): найточніший спосіб збирати CLS на проді через onCLS.
Search Console → Core Web Vitals звіт: групує URL за статусом і показує тренди.
Поле attribution.largestShiftTarget це готовий CSS-селектор елемента, який спричинив найбільший shift. На дашборді ви побачите топ-винуватців за тиждень без жодних здогадок.
Що викликає кумулятивний зсув макета
За даними HTTP Archive Web Almanac 2026, понад 65% сторінок із поганим CLS мають принаймні одну з наступних причин. Ось топ-7 джерел layout shift:
Зображення без атрибутів width/height: браузер не знає розмірів до завантаження, верстка перерендеривається.
Веб-шрифти зі стандартним font-display: swap: FOUT (Flash of Unstyled Text) зсуває все навколо.
Реклама та iframe-вставки: банери змінюють розмір після auction.
Cookie consent / GDPR-банери: з'являються згори, відштовхуючи весь body.
Embedded media (YouTube, Twitter/X, Instagram): без явного aspect-ratio зсувають макет.
Late-loaded компоненти SPA: hydration або lazy-loaded секція додає висоту.
Анімація геометричних властивостей (top, left, height) замість transform.
Цікавий хіт-парад поганих сторінок 2026 року є у Web Almanac performance chapter, де показано: лише 39% мобільних сторінок мають "good" CLS. Це означає, що навіть базова гігієна, як-от додавання width/height на зображення, усе ще дає конкурентну перевагу.
Оптимізація CLS для зображень і відео
Це найшвидша перемога. Для кожного <img> і <video> явно задайте розміри. Сучасні браузери (Chrome, Firefox, Safari 16+) автоматично обчислюють aspect-ratio з атрибутів width і height та резервують місце ще до того, як байти зображення доїдуть.
<!-- ПРАВИЛЬНО: розміри в атрибутах -->
<img
src="/hero.avif"
width="1200"
height="675"
alt="Графік Core Web Vitals"
fetchpriority="high"
/>
<!-- Для responsive додаємо CSS -->
<style>
img {
max-width: 100%;
height: auto; /* зберігає aspect-ratio */
}
</style>
Для <picture> з різними джерелами використовуйте однакове співвідношення сторін у всіх <source>, інакше при зміні breakpoint відбудеться зсув. Якщо ви відрізаєте різні crop'и для мобільної та десктопної версії, явно встановіть aspect-ratio через CSS:
Для embed-плеєрів YouTube та Vimeo обертайте <iframe> у контейнер з aspect-ratio. Для зображень, отриманих з CMS без розмірів, генеруйте їх на етапі білда: Next.js Image, Astro Image, Nuxt Image роблять це автоматично. Якщо у вас власна CMS, додайте до фронтматера висоту й ширину або витягуйте їх через probe-image-size у Node.js під час SSG. Більш детальний підхід до медіа описаний у нашому гіді з оптимізації LCP у 2026 році, де image priority і CLS працюють у парі.
Як шрифти впливають на CLS і що з цим робити
Веб-шрифти це друга за частотою причина layout shift у 2026 році. Сценарій типовий: HTML рендериться системним шрифтом (наприклад, system-ui), потім завантажується кастомний шрифт (Inter, Manrope), у якого інша x-висота й ширина гліфів, і весь текст переміщується на кілька пікселів. Це класичний FOUT-зсув.
Стандартне рішення це font metric overrides. У CSS @font-face ви задаєте параметри fallback-шрифта так, щоб вони математично збігалися з кастомним:
Числові значення можна обчислити автоматично через Capsize або fontaine. Next.js (через next/font) і Nuxt роблять це з коробки в 2026 році, тож просто імпортуйте Google Font, а фреймворк сам додасть metric overrides.
Друге правило: завантажуйте критичні шрифти з <link rel="preload" as="font" crossorigin>. Це скорочує паузу між першим рендером системним шрифтом і свопом, тобто зменшує імовірність потрапити у session window. Для не-критичних накреслень (italic, bold для футера) залишайте font-display: swap. Користувач прочитає текст одразу, а оптимізовані metric overrides не дадуть CLS-штрафу.
Реклама, банери та динамічний контент
Для рекламних слотів, cookie-банерів та A/B-banner-experiments резервуйте місце на рівні CSS до того, як скрипт прокинеться. Якщо AdSense або GAM повертає 300×250, ваш слот повинен мати min-height: 250px ще на сервері:
.ad-slot {
min-height: 250px;
width: 300px;
display: flex;
align-items: center;
justify-content: center;
}
/* Якщо реклама не показалася, місце займає placeholder */
.ad-slot:empty::before {
content: 'Advertisement';
color: #999;
}
Для cookie consent НЕ показуйте банер згори, що відштовхує контент. Рендерте його як модальне вікно з position: fixed у нижньому куті. Це гарантує, що навіть якщо банер з'явиться через 500 мс після LCP, він не вплине на CLS (бо він поза потоком).
Анімації без зсувів: transform, will-change, content-visibility
Браузер вважає зсувом будь-яку зміну позиції елемента в потоці layout. Анімація top, left, margin або height викликає reflow і зараховується у CLS. Анімація transform або opacity, навпаки, працює на composite-шарі й layout shift НЕ викликає.
Для довгих сторінок із багатьма секціями використовуйте CSS content-visibility: auto разом із contain-intrinsic-size. Браузер пропускає рендер невидимих секцій, але резервує їм місце. Це й ефективність, і нульовий CLS при скролі.
article section {
content-visibility: auto;
contain-intrinsic-size: auto 800px; /* приблизна висота */
}
Якщо contain-intrinsic-size сильно розходиться з реальною висотою, при скролі ви побачите зсув скролбара. Браузери Chromium у 2025-2026 додали евристику, що запам'ятовує реальну висоту у browsing session, але задавати auto <value> все ж рекомендовано.
CLS у React, Next.js і SPA
Single Page Applications мають свою специфіку: між переходами браузер не перезавантажує сторінку, тож CLS накопичується на ВСІХ маршрутах протягом життя tab. У 2026 році для виміру в Next.js використовуйте reportWebVitals у App Router або хук useReportWebVitals з next/web-vitals:
'use client';
import { useReportWebVitals } from 'next/web-vitals';
export function WebVitals() {
useReportWebVitals((metric) => {
if (metric.name === 'CLS') {
// metric.id: стабільний у межах page lifetime
fetch('/api/rum', {
method: 'POST',
body: JSON.stringify(metric),
keepalive: true,
});
}
});
return null;
}
Для маршрутних переходів використовуйте View Transitions API. Він робить snapshot старого DOM, рендерить новий і анімує перехід через ::view-transition. Це візуально приховує будь-який зсув і не зараховується як CLS. Next.js 15+ і Astro 5+ підтримують це нативно.
Якщо ваш SSR-рендер відрізняється від клієнтського (наприклад, через timezone або A/B-тест), браузер може зробити "hydration mismatch", і React переверне DOM. Це майже завжди 100% CLS. Виправлення таке: використовуйте suppressHydrationWarning точково лише для timestamp'ів, а для решти контенту тримайте SSR і CSR байт-у-байт ідентичними. Якщо вас цікавить, як подібний підхід працює для interaction-метрик, читайте наш гід з оптимізації INP у 2026 році.
Зупиніть запис. Перейдіть на вкладку Insights внизу.
Розгорніть "Cumulative layout shifts", і ви побачите кожен shift із timestamp, score та DOM-вузлом, що змістився.
Натисніть на shift, DevTools підсвітить елемент на сторінці й покаже two-frame diff: before/after.
Якщо ви хочете побачити shift у режимі реального часу: DevTools → Rendering → ввімкніть Layout Shift Regions. Кожен зсув підсвічується синім напівпрозорим прямокутником на 500 мс. Це справді чарівний інструмент для QA-сесій (я тепер не починаю аудит без нього). Більше про діагностику можна прочитати у офіційній документації Chrome DevTools Performance Insights.
Чек-лист оптимізації CLS
Швидкий audit чек-лист, який можна прогнати на будь-якій сторінці перед релізом:
Усі <img> мають атрибути width і height або CSS aspect-ratio.
Усі <iframe> (включно з YouTube, мапами, Twitter/X) обернуті в контейнер з фіксованим співвідношенням сторін.
@font-face для основного шрифта містить size-adjust і ascent-override.
Критичний шрифт preload'нутий з crossorigin.
Рекламні слоти мають min-height, що дорівнює очікуваному розміру креативу.
Cookie consent це модальне вікно з position: fixed, а не банер у потоці.
Усі hover/scroll анімації використовують transform чи opacity, не top/left/height.
Довгі списки використовують content-visibility: auto з contain-intrinsic-size.
SSR HTML байт-у-байт збігається з першим клієнтським рендером.
Налаштовано RUM-збір CLS через web-vitals/attribution з селекторами найбільших shift'ів.
Пройшовши цей список, типовий лендінг або контент-сайт переходить із "needs improvement" у "good" за 1-2 спринти роботи. Найдорожчі зміни це рефакторинг рекламних слотів і дизайнерських банерів; найдешевші це атрибути зображень і metric overrides шрифтів. Якщо вам потрібно зачепити сусідні метрики, гляньте також наш гайд з оптимізації TTFB у 2026 році, бо повільний сервер часто маскує справжню причину поганого CLS.
Часті запитання
Який хороший показник CLS у 2026 році?
Google визначає "good" CLS як значення ≤ 0.1 на 75-му перцентилі реальних користувачів за останні 28 днів. Значення між 0.1 і 0.25 це "needs improvement", а вище 0.25 вважається "poor". Для бізнес-метрик прагніть тримати CLS нижче 0.05, щоб мати запас при коливаннях реклами.
Чим відрізняється CLS від INP та LCP?
LCP вимірює швидкість показу головного контенту, INP вимірює швидкість відповіді на взаємодію, а CLS вимірює візуальну стабільність. Усі три належать до Core Web Vitals, але оптимізуються різними техніками: LCP через пріоритет завантаження, INP через розбиття довгих задач, CLS через резервування простору.
Чи зараховується зсув від клацання на акордеон у CLS?
Ні. Layout shift, що стався протягом 500 мс після input-події (клік, тап, натискання клавіші), має прапор hadRecentInput і виключається з підсумкового CLS. Тобто відкриття меню, акордеону чи модального вікна після кліку не штрафується.
Як знайти, який саме елемент спричиняє CLS?
Найшвидший спосіб це Chrome DevTools → Performance → Insights → "Layout shift culprits". Для проду використовуйте web-vitals/attribution, який повертає largestShiftTarget, тобто CSS-селектор найбільшого винуватця. Це дає вам список топ-проблемних селекторів без необхідності відтворювати на локалі.
Чи допомагає View Transitions API зменшити CLS?
Так, частково. View Transitions приховує візуальні зміни під анімацію snapshot'а старого DOM, тож користувач не бачить "стрибків". Однак самі layout shift'и все одно реєструються Performance Observer, тому архітектурно резервувати простір все одно потрібно. View Transitions покращують сприйняття, а не саму метрику.
Speculation Rules API дає змогу попередньо завантажувати або повністю рендерити майбутні сторінки у фоні — і у 2026 році це найпростіший спосіб отримати майже миттєвий LCP. Розбираємо синтаксис, рівні eagerness, HTTP-заголовок Speculation-Rules та нову опцію Chrome 144.
TTFB напряму визначає, наскільки швидко браузер починає рендерити сторінку. У цьому гіді — як виміряти Time to First Byte, цільові пороги у 2026 році, і дев'ять перевірених стратегій оптимізації від Early Hints до edge-функцій.
Покроковий гід з оптимізації Largest Contentful Paint у 2026 році. Розбір субчастин LCP, практичні техніки — fetchpriority, preload, AVIF/WebP, Speculation Rules API — та робочі приклади коду.