Решение проблем с CLS на веб-сайте электронной коммерции на базе Next.js (пример из практики)

Опубликовано: 2022-03-10
Краткий обзор ↬ Cumulative Layout Shift — одна из самых сложных для отладки основных веб-приложений. В этой статье мы рассмотрим различные инструменты для исследования CLS, когда их использовать (а когда нет), а также решения некоторых проблем CLS, с которыми мы столкнулись на нашем веб-сайте электронной коммерции на основе Next.js.

Fairprice — один из крупнейших продуктовых интернет-магазинов в Сингапуре. Мы постоянно ищем возможности для улучшения пользовательского опыта онлайн-покупок. Производительность является одним из основных аспектов, обеспечивающих нашим пользователям восхитительный пользовательский интерфейс независимо от их устройств или сетевого подключения.

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

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

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

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

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

Как мы обнаружили проблему CLS на нашей странице продукта

Мы используем Lighthouse и WebPagetest в качестве инструментов синтетического тестирования производительности для измерения CLS. Мы также используем библиотеку web-vitals для измерения CLS для реальных пользователей. Кроме того, мы проверяем раздел отчета Google Search Console Core Web Vitals, чтобы получить представление о любых потенциальных проблемах с CLS на любой из наших страниц. Изучая раздел отчета, мы обнаружили, что многие URL-адреса со страницы сведений о продукте имеют значение CLS более 0,1 , что указывает на то, что там происходит какое-то серьезное событие изменения макета.

Еще после прыжка! Продолжить чтение ниже ↓

Отладка проблемы CLS с помощью различных инструментов

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

Итак, мы запустили маяк, чтобы проверить, может ли он найти какой-либо элемент, который может вызвать серьезное изменение макета, он сообщил, что CLS равен 0,004, что довольно мало.

CLS составляет 0,004
CLS показал низкий результат CLS .004 . (Большой превью)

На странице отчета Lighthouse есть раздел диагностики. Это также не показало ни одного элемента, вызывающего высокое значение CLS.

Страница отчета маяка
Предварительный просмотр страницы отчета, включая результаты вклада CLS. (Большой превью)

Затем мы запустили WebpageTest и решили проверить просмотр диафильма:

просмотр диафильма
В представлении диафильма любой кадр, который имеет визуальное изменение и смену макета, отображается желтой пунктирной линией. (Большой превью)

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

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

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

Примечание . Способ измерения CLS изменился с июня 2021 года.

Поскольку Lighthouse и WebpageTest не смогли обнаружить ни одного элемента, который вызвал серьезное изменение макета, что означает, что это произошло после начальной загрузки страницы, возможно, из-за какого-либо действия пользователя. Поэтому мы решили использовать расширение Web Vitals для Google Chrome, так как оно может записывать CLS на странице, пока пользователь взаимодействует с ней. После выполнения различных действий мы обнаружили, что оценка смещения макета увеличивается, когда пользователь использует функцию увеличения изображения.

Чтобы проверить, происходит ли смещение макета при наведении курсора на изображение, мы использовали приведенный ниже фрагмент кода из https://web.dev/cls/, который добавляет console.log при смещении макета:

 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});

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

Основная причина

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

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

Мы использовали библиотеку react-image zoom для создания этой функции увеличения изображения.

Библиотеки Image Magnify обычно имеют линзу (квадрат, который перемещается при перемещении мыши по изображению). Поскольку эта линза меняет свое верхнее и левое положение при движении мыши, она определяется как сдвиг макета, запускающий CLS. Мы проверили страницу библиотеки, а также другие подобные библиотеки реагирования ( react-image-magnify , react-image-zoom , react-image-magnifiers ) и обнаружили, что все они страдают от одной и той же проблемы с CLS.

Как мы это исправили

Мы заметили, что react-image-zoom использует библиотеку js-image-zoom . Поэтому нам пришлось изменить библиотеку js-image zoom , чтобы решить эту проблему.

Решение довольно простое. Пока мышь перемещается по изображению продукта, элемент линзы изображения перемещается, изменяя свое левое и верхнее положение. Чтобы решить эту проблему, мы использовали transform translate , которое перемещает элемент на новый слой, т.е. любое перемещение, происходящее на этом новом слое, больше не вызывает смещение макета:

управление движением линзы с помощью transform translate
(Большой превью)

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

создание PR для исходного репо
PR создан, чтобы помочь избавиться от проблемы с CLS. (Большой превью)

Влияние изменений

После развертывания кода в рабочей среде CLS был исправлен на странице сведений о продукте, а количество страниц, затронутых CLS, сократилось на 98 %.

график, показывающий влияние изменения.
transform имеет преимущество в производительности по сравнению с манипулированием положением с использованием левого и верхнего. (Большой превью)

Так как мы использовали transform , это также помогло сделать изображение более плавным для пользователей.

Примечание : Пол Айриш написал отличную статью на эту тему.

Другие ключевые изменения, которые мы сделали для CLS

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

  • Веб-шрифты:
    Мы заметили, что поздняя загрузка шрифтов вызывает разочарование пользователей, поскольку содержимое мигает, а также вызывает некоторое смещение макета. Чтобы минимизировать это, мы сделали несколько изменений:

    • Мы разместили шрифты на собственном хостинге вместо загрузки со стороннего CDN.
    • Предварительно загружаем шрифты.
    • Мы используем отображение шрифта необязательно.
  • Картинки:
    Отсутствие значения высоты или ширины в изображении приводит к тому, что элемент после изображения смещается после загрузки изображения. В конечном итоге это становится основным вкладом в CLS. Так как мы используем Next.js, мы воспользовались встроенным компонентом изображений, который называется next/images . Этот компонент включает в себя несколько лучших практик, связанных с изображениями. Он построен на основе HTML-тега <img> и может помочь улучшить LCP и CLS. Я настоятельно рекомендую прочитать этот RFC, чтобы узнать основные функции и преимущества его использования.

  • Бесконечная прокрутка:
    На нашем веб-сайте страницы со списком товаров имеют бесконечную прокрутку. Таким образом, изначально, когда пользователи прокручивают страницу до конца, они видят нижний колонтитул за долю секунды до загрузки следующего набора данных, что вызывает сдвиг макета. Чтобы решить эту проблему, мы предприняли несколько шагов:

    • Мы вызываем API для загрузки данных еще до того, как пользователь достигнет абсолютного конца списка.
    • Мы зарезервировали достаточно места для состояния загрузки и показываем скелеты продуктов во время состояния загрузки. Так что теперь, когда пользователь прокручивает, он не видит нижний колонтитул в течение доли секунды, пока загружаются продукты.

Эдди Османи написал подробную статью об этом подходе, которую я настоятельно рекомендую прочитать.

Ключевые выводы

  • Хотя Lighthouse и WebpageTest помогают обнаруживать проблемы с производительностью, возникающие до загрузки страницы, они не могут обнаружить проблемы с производительностью после загрузки страницы.
  • Расширения Web Vitals могут обнаруживать изменения CLS, вызванные взаимодействием с пользователем, поэтому, если страница имеет высокое значение CLS, но Lighthouse или WebpageTest сообщает о низком CLS, расширение Web Vitals может помочь точно определить проблему.
  • Данные Google Search Console основаны на данных реальных пользователей, поэтому они также могут указывать на потенциальные проблемы с производительностью, возникающие в любой момент жизненного цикла страницы. Как только проблема обнаружена и устранена, повторная проверка раздела отчета может помочь проверить эффективность исправления производительности. Изменения отражаются в течение нескольких дней в разделе веб-отчета о жизненно важных показателях.

Последние мысли

Хотя проблемы CLS сравнительно сложно отлаживать, использование комбинации различных инструментов до загрузки страницы (Lighthouse, WebPageTest) и расширения Web Vitals (после загрузки страницы) может помочь нам точно определить проблему. Это также одна из метрик, которая активно развивается, чтобы охватить широкий спектр сценариев, и это означает, что способ ее измерения будет изменен в будущем. Мы следим за https://web.dev/evolving-cls/, чтобы быть в курсе любых предстоящих изменений.

Что касается нас, мы постоянно работаем над улучшением и других Core Web Vitals. Недавно мы внедрили адаптивную предварительную загрузку изображений и начали показывать изображения в формате WebP, что помогло нам сократить полезную нагрузку изображений на 75 %, уменьшить LCP на 62 % и индекс скорости на 24 %. Вы можете прочитать более подробную информацию об оптимизации для улучшения LCP и индекса скорости или следить за нашим инженерным блогом, чтобы узнать о других интересных работах, которые мы делаем.

Мы хотели бы поблагодарить Алекса Кастла за помощь в отладке проблемы с CLS на странице продукта и решении проблем в реализации next/images .