Совокупное смещение макета (CLS)

Совокупное смещение макета (CLS)

Updated
Appears in: Web Vitals|Metrics

Key Term: Совокупное смещение макета (CLS)важный, ориентированный на пользователя показатель для измерения визуальной стабильности, так как он помогает количественно оценить, как часто пользователи сталкиваются с неожиданными сдвигами макета. Низкое значение показателя CLS говорит о том, что страница выглядит восхитительно.

Вы когда-нибудь сталкивались с тем, что во время чтения статьи в Интернете внезапно что-то менялось? Без предупреждения текст смещался в сторону, и вы теряли читаемую строчку. Или, еще хуже: вы хотели нажать ссылку или кнопку, но за мгновение до этогоБУМссылка смещалась, и вы в конечном итоге нажимали что-то другое!

В большинстве случаев подобные ситуации просто раздражают, но иногда они могут нанести реальный ущерб.

Видео, демонстрирующее негативные последствия нестабильности макета для пользователей.

Неожиданное перемещение содержимого страницы обычно происходит из-за асинхронной загрузки ресурсов или динамического добавления элементов DOM к странице поверх уже существующего контента. Причиной может быть изображение или видео с неизвестными размерами, шрифт, отображаемый крупнее или меньше, чем его запасной вариант, сторонние объявления или виджеты, которые динамически изменяют размер.

Ещё сильнее эта проблема усугубляется тем, что запланированная в процессе разработки функциональность сайта может сильно отличаться от реальной, воспринимаемой пользователями. Персонализированный или сторонний контент часто ведёт себя иначе, чем при разработке, например: тестовые изображения обычно уже находятся в кеше браузера разработчика, а вызовы API, которые выполняются локально, получают ответ сервера слишком быстро и возможные задержки не заметны.

Показатель CLS (Совокупное смещение макета) помогает решить эту проблему, измеряя, как часто такие проблемы случаются у реальных пользователей.

Что такое CLS? #

CLSэто показатель по временному окну с максимальными оценками смещения макета для каждого неожиданного смещения макета, которые происходят в течение всего времени жизни страницы.

Смещение макета происходит каждый раз, когда видимый элемент меняет свое положение от одного отрисованного фрейма к другому (см. ниже подробные сведения о том, как рассчитываются оценки смещения макета).

Временное окно смещений макета или окно сеансаэто период времени, который начинает отсчитываться в момент первого смещения макета и длится до выполнения одного из двух критериев: появления промежутка в 1 секунду или больше без смещений макета; достижения максимальной продолжительности временного окна, равной 5 секундам.

Временное окно с максимальными оценками смещения макетаэто окно сеанса с максимальной совокупной оценкой всех сдвигов макета в этом окне.

Пример окон сеанса. Синие полосы представляют собой оценки каждого отдельного сдвига макета.

Caution: Ранее метрика CLS измеряла общую сумму всех индивидуальных смещений макета, произошедших в течение всего времени жизни страницы. Чтобы узнать, какие инструменты по-прежнему обеспечивают возможность сравнения с исходной реализацией метрики, ознакомьтесь со статьей «Развитие метрики CLS (Совокупного смещения макета) в веб-инструментах».

Какое значение показателя CLS можно считать хорошим? #

Для обеспечения удобства работы пользователей сайты должны стремиться к тому, чтобы показатель CLS не превышал 0,1. Чтобы убедиться, что вы достигли этой цели для большинства пользователей, рекомендуется в качестве порогового значения использовать 75-й процентиль загрузки страниц, сегментированный по мобильным и настольным устройствам.

Хорошие значения CLS ниже 0,1, плохие значения больше 0,25 и все промежуточные значения требуют улучшения

Чтобы узнать больше об исследованиях и методологии, лежащих в основе этой рекомендации, см. «Определение пороговых значений показателей Core Web Vitals»

Подробно о смещениях макета #

Смещения макета определяются Layout Instability API (API нестабильности макета), который возвращает запись layout-shift каждый раз, когда элемент, видимый в области просмотра, меняет свое начальное положение (например, верхнее и левое положение в значении по умолчанию свойства writing mode) между двумя фреймами. Такие элементы считаются нестабильными.

Обратите внимание, что смещения макета происходят только тогда, когда существующие элементы меняют свое положение. Если новый элемент добавляется в DOM-модель или существующий элемент меняет размерэто не будет считаться смещением макета до тех пор, пока данные изменения не заставят другие видимые элементы изменить свое начальное положение.

Оценка смещения макета #

Чтобы вычислить оценку смещения макета, браузер смотрит на размер области просмотра и перемещение нестабильных элементов в пределах области просмотра между двумя отрисованными фреймами. Оценка смещения макетаэто результат умножения двух показателей этого движения: доли воздействия и доли расстояния (описаны ниже).

оценка смещения макета = доля воздействия * доля расстояния

Ударная фракция #

Доля воздействия измеряет, как нестабильные элементы влияют на область просмотра между двумя фреймами.

Объединение видимых областей всех нестабильных элементов для предыдущего и текущего фреймав виде доли от общей площади области просмотраи будет являться долей воздействия для текущего фрейма.

Пример доли воздействия с одним *нестабильным элементом*

На изображении выше есть элемент, который занимает половину области просмотра в одном фрейме. Затем в следующем фрейме элемент сдвигается вниз на 25% от высоты области просмотра. Красный пунктирный прямоугольник указывает на объединение видимой области элемента в обоих фреймах, которая в данном случае составляет 75% от всего окна просмотра, поэтому доля воздействия составляет 0,75.

Доля расстояния #

Другая часть выражения оценки смещения макета измеряет расстояние, на которое нестабильные элементы переместились относительно области просмотра. Доля расстоянияэто наибольшее расстояние, на которое любой нестабильный элемент переместился в фрейме (по горизонтали или по вертикали), деленное на наибольший размер области просмотра (ширина или высота, в зависимости от того, что больше).

Пример доли расстояния с одним *нестабильным элементом*

В приведенном выше примере наибольший линейный размер области просмотраэто высота, а нестабильный элемент переместился на 25% от высоты области просмотра, поэтому доля расстояния составляет 0,25.

Итак, в этом примере доля воздействия составляет 0,75, а доля расстояния0,25, поэтому оценка смещения макета равна 0,75 * 0,25 = 0,1875.

Первоначально оценка смещения макета рассчитывалась только на основании доли воздействия. Доля расстояния была введена, чтобы избежать чрезмерного значения показателя в случаях, когда большие элементы смещаются на небольшую величину.

В следующем примере показано, как добавление содержимого к существующему элементу влияет на оценку смещения макета:

Пример смещения макета со стабильными и *нестабильными элементами* и обрезкой области просмотра

Кнопка «Щелкни меня!» (Click Me!) добавляется в нижнюю часть серого поля с черным текстом, который толкает зеленое поле с белым текстом вниз (и частично за пределы области просмотра).

В этом примере серый прямоугольник меняет размер, но его начальное положение не меняется, поэтому он не считается нестабильным элементом.

Кнопки «Щелкни меня!» ранее не было в DOM, поэтому ее начальное положение также не изменится.

Хотя начальное положение зеленого прямоугольника изменилось, но так как он был частично перемещен из области просмотра, невидимая область не учитывается при вычислении доли воздействия. Объединение видимых областей для зеленого прямоугольника в обоих фреймах (показано красным пунктирным прямоугольником) совпадает с площадью зеленого прямоугольника в первом кадре50% области просмотра. Доля воздействия0,5.

Доля расстояния показана фиолетовой стрелкой. Зеленая рамка сместилась вниз примерно на 14% от области просмотра, поэтому доля расстояния составляет 0,14.

Оценка смещения макета равна 0,5 x 0,14 = 0,07.

Последний пример иллюстрирует несколько нестабильных элементов:

Пример смещения макета с несколькими стабильными и *нестабильными элементами*

В первом фрейме выше представлены четыре результата запроса к API для животных, отсортированных в алфавитном порядке. Во втором фрейме в отсортированный список добавляется еще несколько результатов.

Первый элемент в списке (Cat, «Кот») не меняет свое начальное положение между фреймами, поэтому он стабильный. Точно так же новые элементы, добавленные в список, ранее не были в DOM, поэтому их начальные позиции также не меняются. Но остальные элементы Dog («Собака»), Horse («Лошадь») и Zebra («Зебра») меняют свои начальные позиции, что делает их нестабильными элементами.

Опять же, красные пунктирные прямоугольники представляют собой объединение этих трех нестабильных элементов до и после областей, которые в этом случае составляют около 38% площади области просмотра (доля воздействия равна 0,38).

Стрелки показывают расстояния, на которые нестабильные элементы переместились из начальных положений. Элемент Zebra («Зебра»), обозначенный синей стрелкой, сместился больше прочих, примерно на 30% высоты области просмотра. Таким образом, доля расстояния в этом примере равна 0,3.

Оценка смещения макета составляет 0,38 x 0,3 = 0,114.

Ожидаемые и неожиданные смещения макета #

Не все сдвиги в макетеэто плохо. Фактически многие динамические веб-приложения часто меняют начальное положение элементов на странице.

Изменения макета по инициативе пользователя #

Смещение макета плохо только в том случае, если пользователь этого не ожидает. С другой стороны, смещения макета, которые происходят в ответ на действия пользователя (щелчок по ссылке, нажатие кнопки, ввод в поле поиска и т. д.), как правило, допустимы, если смещение достаточно близко к взаимодействию, чтобы взаимосвязь между ними была понятна пользователю.

Например, если взаимодействие с пользователем запускает сетевой запрос, выполнение которого может занять некоторое время, лучше сразу освободить место и показать индикатор загрузки, чтобы избежать неприятного смещения макета после завершения запроса. Если пользователь не понимает, что что-то загружается, или не знает, когда ресурс будет готов, он может попытаться щелкнуть что-нибудь еще во время ожидания.

Для смещений макета, которые происходят в течение 500 миллисекунд после ввода пользователя, будет установлен флаг hadRecentInput, поэтому их можно исключить из вычислений.

Caution: Флаг hadRecentInput становится true только для дискретных событий ввода, таких как касание, щелчок или нажатие клавиши. Непрерывные взаимодействияпрокрутка, перетаскивание или жесты сжатия и масштабированияне считаются «недавним вводом». Дополнительные сведения см. в «Спецификации нестабильности макета».

Анимации и переходы #

Если всё сделано правильно, анимация и переходыэто отличный способ обновить контент на странице, не удивляя пользователя. Резко и неожиданно перемещающийся контент на странице почти всегда создает неудобства для пользователей. Но контент, который постепенно и естественно перемещается из одной позиции в другую, часто помогает пользователю лучше понять, что происходит и что делать между изменениями состояния.

CSS-свойство transform позволяет анимировать элементы, не вызывая смещений макета:

  • Вместо изменения свойств высоты height и ширины width можно использовать transform: scale().
  • Чтобы перемещать элементы, следует избегать изменения свойств top, right, bottom или left и использовать вместо них transform: translate().

Как измерить CLS #

CLS можно измерить в лабораторных или полевых условиях с помощью следующих инструментов:

Caution: Инструменты для измерения в лабораторных условиях обычно загружают страницы в имитируемой среде и поэтому могут измерять только смещения макета, которые происходят во время загрузки страницы. В результате значения CLS, сообщаемые лабораторными инструментами для данной страницы, могут быть меньше, чем у реальных пользователей в полевых условиях.

.

Инструменты для измерения в полевых условиях #

Инструменты для измерения в лабораторных условиях #

Измерение CLS в JavaScript #

Чтобы измерить CLS с помощью JavaScript, можно воспользоваться Layout Instability API (API нестабильности макета). В следующем примере показано, как создать PerformanceObserver который прослушивает неожиданные записи смещений макета layout-shift, группирует их в сеансы и регистрирует максимальное значение сеанса при каждом его изменении.

let clsValue = 0;
let clsEntries = [];

let sessionValue = 0;
let sessionEntries = [];

new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Only count layout shifts without recent user input.
if (!entry.hadRecentInput) {
const firstSessionEntry = sessionEntries[0];
const lastSessionEntry = sessionEntries[sessionEntries.length - 1];

// If the entry occurred less than 1 second after the previous entry and
// less than 5 seconds after the first entry in the session, include the
// entry in the current session. Otherwise, start a new session.
if (sessionValue &&
entry.startTime - lastSessionEntry.startTime < 1000 &&
entry.startTime - firstSessionEntry.startTime < 5000) {
sessionValue += entry.value;
sessionEntries.push(entry);
} else {
sessionValue = entry.value;
sessionEntries = [entry];
}

// If the current session value is larger than the current CLS value,
// update CLS and the entries contributing to it.
if (sessionValue > clsValue) {
clsValue = sessionValue;
clsEntries = sessionEntries;

// Log the updated value (and its entries) to the console.
console.log('CLS:', clsValue, clsEntries)
}
}
}
}).observe({type: 'layout-shift', buffered: true});

Warning:

Этот код показывает основной способ вычисления и регистрации CLS. Однако точно измерить CLS таким образом, чтобы метрика соответствовала измерениям в отчете Chrome User Experience Report (CrUX), довольно сложно. Подробности см. ниже:

В большинстве случаев текущее значение CLS на момент выгрузки страницы является окончательным значением CLS для этой страницы, но есть несколько важных исключений.

Далее приведем различия между тем, что сообщает API, и тем, как рассчитывается метрика.

Различия между метрикой и API #

  • Если страница загружается в фоновом режиме или если она находилась в фоновом режиме до того, как браузер отрисовал любой контент, она не должна сообщать значение CLS.
  • Если страница восстанавливается функцией back/forward cache, значение CLS данной страницы должно быть сброшено до нуля, поскольку пользователи воспринимают такие посещения страниц как отдельные.
  • API не сообщает о записях layout-shift для смещений внутри iframe, но для правильного измерения CLS их нужно учитывать. Подфреймы могут использовать API, чтобы сообщать о своих записях layout-shift в родительский фрейм для агрегирования.

Более того, CLS трудно определять из-за того, что показатель измеряется на протяжении всей продолжительности жизни страницы:

  • Пользователи могут держать вкладку открытой в течение очень долгого временидней, недель, месяцев. Фактически пользователь может никогда не закрыть вкладку.
  • В мобильных операционных системах браузеры обычно не запускают обратные вызовы выгрузки страницы для фоновых вкладок, что затрудняет сообщение «окончательного» значения.

Чтобы справиться с такими случаями, CLS следует сообщать каждый раз, когда страница находится в фоновом режиме, в дополнение к любому времени, когда она выгружается (событие visibilitychange охватывает оба этих сценария). Системы аналитики, получающие эти данные, должны будут затем вычислить окончательное значение CLS на бэкенде.

Вместо того чтобы запоминать все эти тонкости, разработчики могут использовать для измерения CLS JavaScript-библиотеку web-vitals, которая учитывает вышеупомянутые моменты:

import {getCLS} from 'web-vitals';

// Measure and log CLS in all situations
// where it needs to be reported.
getCLS(console.log);

Полный пример измерения CLS в JavaScript приводится в исходном коде getCLS().

В некоторых случаях (например, в iframe с перекрестным происхождением) невозможно измерить CLS в JavaScript. См. подробности в разделе «Ограничения» библиотеки web-vitals.

Как улучшить показатель CLS #

Для большинства веб-сайтов можно избежать всех неожиданных смещений макета, придерживаясь нескольких основополагающих принципов:

  • Всегда следует включать атрибуты размеров для изображений и видеоэлементов или иным образом резервировать необходимое пространство с помощью, например, CSS-свойства aspect-ratio. Такой подход гарантирует, что браузер сможет выделить правильный объем места в документе во время загрузки изображения. Кроме того, можно также применять политику функции unized-media, чтобы принудительно использовать это поведение в браузерах, поддерживающих политики функций.
  • Никогда не следует вставлять контент поверх существующего, кроме случаев, когда это требуется в ответ на взаимодействие с пользователем. Это гарантирует, что любые изменения макета будут ожидаемыми.
  • Лучше выбирать анимацию трансформации, чем анимацию изменения свойств, запускающих изменение макета. Нужно анимировать переходы таким образом, чтобы обеспечить контекст и непрерывность от состояния к состоянию.

Подробные сведения о том, как улучшить CLS, см. в статьях «Оптимизация CLS» и «Отладка смещений макета».

Дополнительные ресурсы #

CHANGELOG #

Occasionally, bugs are discovered in the APIs used to measure metrics, and sometimes in the definitions of the metrics themselves. As a result, changes must sometimes be made, and these changes can show up as improvements or regressions in your internal reports and dashboards.

To help you manage this, all changes to either the implementation or definition of these metrics will be surfaced in this CHANGELOG.

Last updated: Improve article