Кумулятивное смещение макета, иногда называемое jank, – это показатель того, насколько сильно элементы перемещаются из-за того, что содержимое отображается с опозданием. Вы можете думать об этом как об измерении нестабильности макета. Это стало распространенной проблемой для многих веб-сайтов из-за сторонних скриптов и управления тегами.

Нестабильность макета

Современные веб-приложения сложны. JavaScript рендерит DOM, сторонние скрипты добавляются как конфеты, и слишком много поваров работают на кухне, асинхронно рендеря DOM-контент (рекламные сети, инструменты A/B-тестирования и т. д.). Эта сложность и асинхронная загрузка являются причиной серьезной проблемы: нестабильности макета.

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

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

API измерения нестабильности компоновки

Ребята из группы сообщества веб-инкубатора (WICG) предложили API для измерения нестабильности макета (также называемого смещением макета). На данный момент он поддерживается только в браузерах на базе Blink, таких как Chrome, Edge и Opera, но его довольно просто использовать. Цель состоит в том, чтобы обеспечить количественный способ последовательного измерения изменения макета.

Давайте попробуем API на примере выше, где всплывает реклама. Первое, что нужно сделать, это создать объект PerformanceObserver. Затем нам нужно сообщить ему, какие записи мы хотим отслеживать. Обратите внимание, что мы также передаем ему параметр buffered: true, который будет включать все записи, которые произошли до того, как мы запустили наш код.

new PerformanceObserver(entryList => {
    console.log(entryList.getEntries());
}).observe({ type: "layout-shift", buffered: true });

Обратите внимание, что мы используем класс PerformanceObserver вместо объекта производительности. Сегодня performance.getEntries() не включает запись LayoutShift.

Этот код дает следующий вывод консоли для нашего надуманного примера рекламы:

Мы видим, что было два изменения макета, каждое из которых соответствовало новой всплывающей рекламе. Обратите особое внимание на свойство value. Это оценка, описывающая величину смещения макета. Чем выше оценка, тем резче сдвиг. Оценка представляет собой комбинацию фракции удара и фракции расстояния. Два значения перемножаются, чтобы вычислить значение записи layout-shift. Документ WICG API подробно описывает, как рассчитывается оценка. Достаточно сказать, что мы хотим, чтобы наши оценки были низкими!

Совокупный сдвиг макета

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

Google создал полезную страницу с описанием Cumulative Layout Shift (CLS) и его значением. CLS является одним из трех основных веб-важных показателей, которые Google рекомендует измерять, чтобы убедиться, что ваши пользователи получают хороший опыт. Мы думаем, что вскоре Google будет ранжировать результаты поиска на основе этих оценок, поэтому важно понимать, как работают наши веб-сайты.

Согласно Google, ваш CLS должен быть ниже 0,1, чтобы считаться «хорошим». Что-то выше, и вы перемещаете слишком много контента асинхронно.

Измерение CLS с помощью JavaScript

Мы можем улучшить наш фрагмент кода несколькими способами, чтобы измерить кумулятивный сдвиг макета. Вы можете подумать, что мы можем просто сложить value каждой записи смены макета и на этом закончить, но это не так просто. Не все изменения макета плохи или неожиданны. Если пользователь нажимает кнопку или ссылку, разумно ожидать, что макет каким-либо образом изменится. Мы не хотим включать в наши расчеты ожидаемые изменения макета, а только неожиданные.

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

new PerformanceObserver(entryList => {
    var entries = entryList.getEntries() || [];
    var cls = 0;
    entries.forEach(e => {
        if (!e.hadRecentInput) { // omit entries likely caused by user input
            cls += e.value;
        }
    });
    console.log(`Cumulative Layout Shift: ${cls}`);
}).observe({ type: "layout-shift", buffered: true })

Теперь, когда мы собрали все это вместе, давайте посмотрим на оценки CLS для некоторых популярных веб-сайтов при загрузке в Chrome Devtools с включенной эмуляцией мобильного устройства.

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

Ограничения оценки CLS

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

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

Хотя CLS — несовершенная метрика, она по-прежнему является ценным сигналом для пользовательского опыта вашего сайта. Пользователи, которые не могут читать контент или нажимать кнопки, потому что страница продолжает двигаться, будут раздражены.

Мониторинг производительности CLS

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

Первоначально опубликовано на https://requestmetrics.com.