Узнайте, как выявить и исправить сдвиги макета.
В первой части этой статьи обсуждаются инструменты для отладки изменений макета, а во второй части обсуждается мыслительный процесс, который следует использовать при определении причины изменения макета.
Оснастка
API нестабильности макета
API нестабильности макета — это механизм браузера для измерения и составления отчетов об изменениях макета. Все инструменты для отладки изменений макета, включая DevTools, в конечном итоге основаны на API нестабильности макета. Однако прямое использование Layout Instability API является мощным инструментом отладки благодаря своей гибкости.
Применение
Тот же фрагмент кода, который измеряет совокупный сдвиг макета (CLS), также может служить для отладки сдвигов макета. В приведенном ниже фрагменте информация об изменениях макета выводится на консоль. Просмотр этого журнала предоставит вам информацию о том, когда, где и как произошел сдвиг макета.
let cls = 0;
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (!entry.hadRecentInput) {
cls += entry.value;
console.log('Current CLS value:', cls, entry);
}
}
}).observe({type: 'layout-shift', buffered: true});
При запуске этого сценария имейте в виду, что:
- Параметр
buffered: true
указывает, чтоPerformanceObserver
должен проверить буфер записей производительности браузера на предмет записей производительности, которые были созданы до инициализации наблюдателя. В результатеPerformanceObserver
сообщит об изменениях макета, произошедших как до, так и после его инициализации. Имейте это в виду при проверке журналов консоли. Первоначальное избыток изменений макета может отражать невыполненную отчетность, а не внезапное возникновение многочисленных изменений макета. - Чтобы избежать влияния на производительность,
PerformanceObserver
ждет, пока основной поток не будет простаивать, чтобы сообщить об изменениях макета. В результате, в зависимости от того, насколько занят основной поток, между моментом сдвига макета и его регистрацией в консоли может возникнуть небольшая задержка. - Этот сценарий игнорирует сдвиги макета, произошедшие в течение 500 мс после ввода пользователя, и поэтому не учитываются в CLS.
Информация о сдвигах макета передается с помощью комбинации двух API: интерфейсов LayoutShift
и LayoutShiftAttribution
. Каждый из этих интерфейсов описан более подробно в следующих разделах.
LayoutShift
О каждом сдвиге макета сообщается с помощью интерфейса LayoutShift
. Содержимое записи выглядит следующим образом:
duration: 0
entryType: "layout-shift"
hadRecentInput: false
lastInputTime: 0
name: ""
sources: (3) [LayoutShiftAttribution, LayoutShiftAttribution, LayoutShiftAttribution]
startTime: 11317.934999999125
value: 0.17508567530168798
Запись выше указывает на сдвиг макета, во время которого три элемента DOM изменили положение. Оценка смещения макета для этого конкретного смещения макета составила 0.175
.
Вот свойства экземпляра LayoutShift
, которые наиболее важны для отладки изменений макета:
Свойство | Описание |
---|---|
sources | Свойство sources перечисляет элементы DOM, которые были перемещены во время изменения макета. Этот массив может содержать до пяти источников. В случае, если сдвиг макета затрагивает более пяти элементов, сообщается о пяти крупнейших (с точки зрения влияния на стабильность макета) источниках смещения макета. Эта информация передается с помощью интерфейса LayoutShiftAttribution (подробнее описано ниже). |
value | Свойство value сообщает оценку сдвига макета для конкретного сдвига макета. |
hadRecentInput | Свойство hadRecentInput указывает, произошел ли сдвиг макета в течение 500 миллисекунд после ввода пользователя. |
startTime | Свойство startTime указывает, когда произошел сдвиг макета. startTime указывается в миллисекундах и измеряется относительно времени начала загрузки страницы . |
duration | Свойство duration всегда будет установлено в 0 . Это свойство унаследовано от интерфейса PerformanceEntry (интерфейс LayoutShift расширяет интерфейс PerformanceEntry ). Однако концепция продолжительности не применяется к событиям смещения макета, поэтому для нее установлено значение 0 . Информацию об интерфейсе PerformanceEntry смотрите в спецификации . |
LayoutShiftАтрибуция
Интерфейс LayoutShiftAttribution
описывает один сдвиг одного элемента DOM. Если несколько элементов смещаются во время изменения макета, свойство sources
содержит несколько записей.
Например, приведенный ниже JSON соответствует сдвигу макета с одним источником: сдвигу вниз элемента DOM <div id='banner'>
с y: 76
на y:246
.
// ...
"sources": [
{
"node": "div#banner",
"previousRect": {
"x": 311,
"y": 76,
"width": 4,
"height": 18,
"top": 76,
"right": 315,
"bottom": 94,
"left": 311
},
"currentRect": {
"x": 311,
"y": 246,
"width": 4,
"height": 18,
"top": 246,
"right": 315,
"bottom": 264,
"left": 311
}
}
]
Свойство node
идентифицирует элемент HTML, который сместился. При наведении курсора на это свойство в DevTools выделяется соответствующий элемент страницы.
Свойства previousRect
и currentRect
сообщают размер и положение узла.
- Координаты
x
иy
сообщают координату x и координату y соответственно верхнего левого угла элемента. - Свойства
width
иheight
сообщают ширину и высоту элемента соответственно. - Свойства
top
,right
,bottom
иleft
сообщают значения координат x или y, соответствующие заданному краю элемента. Другими словами, значениеtop
равноy
; значениеbottom
равноy+height
.
Если все свойства previousRect
установлены в 0, это означает, что элемент переместился в поле зрения. Если все свойства currentRect
установлены в 0, это означает, что элемент вышел из поля зрения.
Одна из наиболее важных вещей, которую следует понимать при интерпретации этих результатов, заключается в том, что элементы, указанные в качестве источников, — это элементы, которые сместились во время изменения макета. Однако возможно, что эти элементы лишь косвенно связаны с «основной причиной» нестабильности макета. Вот несколько примеров.
Пример №1
Об этом сдвиге макета будет сообщаться с одним источником: элементом B. Однако основной причиной этого изменения макета является изменение размера элемента A.
Пример №2
О сдвиге макета в этом примере будет сообщено из двух источников: элемента A и элемента B. Основной причиной этого смещения макета является изменение положения элемента A.
Пример №3
О сдвиге макета в этом примере будет сообщаться с одним источником: элементом B. Изменение положения элемента B привело к этому сдвигу макета.
Пример №4
Хотя элемент B меняет размер, в этом примере сдвиг макета не происходит.
Посмотрите демонстрацию того, как API нестабильности макета сообщает об изменениях в DOM .
Инструменты разработчика
Панель производительности
В области «Оперативность» панели « Производительность DevTools» отображаются все изменения макета, которые происходят во время заданной трассировки производительности, даже если они происходят в течение 500 мс после взаимодействия с пользователем и, следовательно, не учитываются в CLS. При наведении курсора мыши на определенное изменение макета на панели «Возможность» выделяется затронутый элемент DOM.
Чтобы просмотреть дополнительную информацию о сдвиге макета, нажмите на сдвиг макета, затем откройте ящик «Сводка» . Изменения размеров элемента отображаются в формате [width, height]
; изменения положения элемента перечисляются в формате [x,y]
. Свойство «Недавний ввод» указывает, произошел ли сдвиг макета в течение 500 мс после взаимодействия с пользователем.
Для получения информации о продолжительности смены макета откройте вкладку «Журнал событий» . Продолжительность сдвига макета также можно приблизительно определить, посмотрев на панели «Впечатление» длину красного прямоугольника сдвига макета.
Дополнительную информацию об использовании панели «Производительность» см. в документе «Справочник по анализу производительности» .
Выделить области смещения макета
Выделение областей смещения макета может быть полезным методом для быстрого и наглядного определения местоположения и времени смещения макета, происходящего на странице.
Чтобы включить области смещения макета в DevTools, выберите «Настройки» > «Дополнительные инструменты» > «Визуализация» > «Области смещения макета», а затем обновите страницу, которую вы хотите отладить. Области смещения макета будут ненадолго выделены фиолетовым цветом.
Мыслительный процесс для выявления причины сдвигов макета
Вы можете использовать приведенные ниже шаги, чтобы определить причину смещения макета независимо от того, когда и как происходит сдвиг макета. Эти шаги можно дополнить запуском Lighthouse, однако имейте в виду, что Lighthouse может определять только изменения макета, произошедшие во время начальной загрузки страницы. Кроме того, Lighthouse также может предлагать только некоторые причины смещения макета, например элементы изображения, у которых нет явно заданной ширины и высоты.
Выявление причины смещения макета
Сдвиги макета могут быть вызваны следующими событиями:
- Изменения положения элемента DOM
- Изменения размеров элемента DOM
- Вставка или удаление элемента DOM
- Анимации, запускающие макет
В частности, элемент DOM, непосредственно предшествующий смещенному элементу, является элементом, который с наибольшей вероятностью будет вовлечен в «вызывание» сдвига макета. Таким образом, при выяснении того, почему произошел сдвиг макета, учитывайте:
- Изменилось ли положение или размеры предыдущего элемента?
- Был ли элемент DOM вставлен или удален перед смещенным элементом?
- Было ли явно изменено положение сдвинутого элемента?
Если предыдущий элемент не вызвал смещение макета, продолжите поиск, рассматривая другие предыдущие и соседние элементы.
Кроме того, направление и расстояние смещения макета могут подсказать основную причину. Например, большой сдвиг вниз часто указывает на вставку элемента DOM, тогда как сдвиг макета на 1 или 2 пикселя часто указывает на применение конфликтующих стилей CSS или на загрузку и применение веб-шрифта.
![Диаграмма, показывающая сдвиг макета, вызванный заменой шрифта](https://web.dev/static/articles/debug-layout-shifts/image/diagram-showing-layout-s-60ec3d8c95616.png?authuser=7&hl=ru)
Вот некоторые из конкретных действий, которые чаще всего вызывают события смещения макета:
Изменения положения элемента (не связанные с перемещением другого элемента)
Этот тип изменений часто является результатом:
- Таблицы стилей, которые загружаются с опозданием или перезаписывают ранее объявленные стили.
- Анимация и эффекты перехода.
Изменения размеров элемента
Этот тип изменений часто является результатом:
- Таблицы стилей, которые загружаются с опозданием или перезаписывают ранее объявленные стили.
- Изображения и iframe без атрибутов
width
иheight
, которые загружаются после визуализации их «слота». - Текстовые блоки без атрибутов
width
иheight
, которые меняют шрифты после визуализации текста.
Вставка или удаление элементов DOM
Часто это является результатом:
- Вставка рекламы и других сторонних вставок.
- Вставка баннеров, оповещений и модальных окон.
- Бесконечная прокрутка и другие шаблоны UX, которые загружают дополнительный контент поверх существующего.
Анимации, запускающие макет
Некоторые анимационные эффекты могут вызывать срабатывание макета . Типичным примером этого является то, что элементы DOM «анимируются» путем увеличения таких свойств, как top
или left
, вместо использования свойства transform
CSS. Прочтите «Как создавать высокопроизводительную CSS-анимацию» для получения дополнительной информации.
Воспроизведение сдвигов макета
Вы не можете исправить сдвиги макета, которые не можете воспроизвести. Одна из самых простых, но наиболее эффективных вещей, которые вы можете сделать, чтобы лучше понять стабильность макета вашего сайта, — это потратить 5–10 минут на взаимодействие с вашим сайтом с целью вызвать изменения макета. При этом держите консоль открытой и используйте API нестабильности макета, чтобы сообщать об изменениях макета.
Если трудно обнаружить изменения в макете, попробуйте повторить это упражнение с разными устройствами и скоростями соединения. В частности, использование более медленной скорости соединения может облегчить выявление изменений макета. Кроме того, вы можете использовать оператор debugger
, чтобы упростить пошаговое изменение макета.
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (!entry.hadRecentInput) {
cls += entry.value;
debugger;
console.log('Current CLS value:', cls, entry);
}
}
}).observe({type: 'layout-shift', buffered: true});
Наконец, если проблемы с макетом не воспроизводятся при разработке, рассмотрите возможность использования API нестабильности макета в сочетании с выбранным вами внешним инструментом ведения журнала, чтобы собрать больше информации об этих проблемах. Ознакомьтесь с примером кода, позволяющим отслеживать наибольший сдвинутый элемент на странице .