1 апреля 2021

Отладка сдвигов лейаута (layout shift)

Перевод. Источник – web.dev

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

Инструменты

Layout Instability API

Layout Instability API - это механизм браузера для измерения изменений лейаута и создания отчетов. Все инструменты для отладки сдвигов лейаута, включая DevTools, в конечном итоге построены на этом API. Однако прямое использование Layout Instability API является мощным инструментом отладки из-за его гибкости.

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

Использование

Тот же фрагмент кода, который измеряет Cumulative Layout Shift (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 смотрите в спецификации.

Расширение Web Vitals может записывать информацию о сдвиге лейаута в консоль. Чтобы включить эту функцию, перейдите в Options > Console Logging.

LayoutShiftAttribution

Интерфейс 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 сообщают размер и положение node.

  • Координаты 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 меняет размер, в этом примере сдвига лейаута нет.

Посмотрите демонстрацию того, как Layout Instability API сообщает об изменениях DOM.

DevTools

Панель Performance

На панели Experience вкладки Performance в DevTools отображаются все сдвиги лейаута, которые происходят во время данной трассировки производительности (performance trace), даже если они происходят в течение 500 мс после взаимодействия с пользователем и, следовательно, не учитываются в CLS. При наведении указателя мыши на конкретный сдвиг лейаута на панели Experience выделяется затронутый элемент DOM.

Чтобы просмотреть дополнительную информацию о сдвиге, щелкните Layout Shift, затем откройте панель Summary. Изменения размеров элемента перечислены в формате [width, height]; изменения позиции элемента перечислены в формате [x, y]. Свойство Had recent input указывает, произошел ли сдвиг в течение 500 мс после взаимодействия с пользователем.

Для получения информации о продолжительности сдвига лейаута откройте вкладку Event Log. Продолжительность сдвига также можно приблизительно определить, посмотрев на панели Experience длину красного прямоугольника Layout Shift.

Продолжительность сдвига лейаута не влияет на оценку этого сдвига.

Для получения дополнительной информации об использовании панели Performance см. Справочник по анализу производительности.

Выделение областей сдвига лейаута

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

Чтобы включить области сдвига лейаута (Layout Shift Regions) в DevTools, перейдите в Settings > More Tools > Rendering > Layout Shift Regions, затем обновите страницу, которую хотите отладить. Области сдвига будут на короткое время выделены фиолетовым цветом.

Логика мышления при определении причины сдвига лейаута

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

Выявление причины сдвига лейаута

Сдвиг лейаута может быть вызван следующими событиями:

  • Изменения позиции элемента DOM
  • Изменения размеров элемента DOM
  • Вставка или удаление элемента DOM
  • Анимации, запускающие изменения лейаута

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

  • Изменилось ли положение или размеры предыдущего элемента?
  • Был ли элемент DOM вставлен или удален перед смещенным элементом?
  • Было ли явно изменено положение смещенного элемента?

Если предыдущий элемент не вызвал сдвига, продолжайте поиск, рассматривая другие предшествующие и соседние элементы.

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

В этом примере замена шрифта привела к смещению элементов страницы вверх на пять пикселей.

Вот некоторые причины, которые наиболее часто вызывают сдвиг лейаута:

Изменения положения элемента (не из-за движения другого элемента)

Этот тип изменений часто является результатом:

  • Загрузки таблиц стилей с опозданием или таблиц, перезаписывающих ранее объявленные стили.
  • Анимаций и эффектов перехода.

Изменения размеров элемента

Этот тип изменений часто происходит из-за следующего:

  • Загрузки таблиц стилей с опозданием или таблиц, перезаписывающих ранее объявленные стили.
  • Изображений и iframe без атрибутов width и height, которые загружаются после того, как их "слот" был отрендерен.
  • Текстовых блоков без атрибутов width и height, которые меняют шрифты местами после рендеринга текста.

Вставка или удаление элементов DOM

Часто это результат:

  • Размещения рекламы и других сторонних вставок.
  • Вставки баннеров, предупреждений и модальных окон.
  • Бесконечной прокрутки и других шаблонов UX, которые загружают дополнительный контент поверх существующего.

Анимации, запускающие лейаут

Некоторые эффекты анимации могут запускать изменения лейаута. Типичный пример этого - когда элементы DOM «анимируются» путем изменения значений свойств, таких как top или left, вместо использования свойства CSS transform. Прочтите «Как создавать высокопроизводительные CSS-анимации» для получения дополнительной информации.

Воспроизведение сдвигов лейаута

Вы не можете исправить сдвиги лейаута, которые не cможете воспроизвести. Одна из самых простых, но наиболее эффективных вещей, которые вы можете сделать, чтобы лучше оценить стабильность лейаута вашего сайта, - это потратить 5-10 минут на взаимодействие с сайтом, провоцируя сдвиги. При этом держите консоль открытой и используйте Layout Instability 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});

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

Не получилось найти то, что искали?

Напишите нам