Как стать автором
Обновить
782.62
VK
Технологии, которые объединяют

Как правильно пофиксить INP и весь Performance: опыт команды ОК

Уровень сложностиСредний
Время на прочтение12 мин
Количество просмотров686

С 12 марта 2024 года метрика FID (First Input Delay) из семейства Core Web Vitals заменена метрикой INP (Interaction to Next Paint), которая оценивает скорость отклика сайтов. При этом, согласно оценке Google, по метрике FID было оптимизировано 93 % сайтов, но лишь 65 % — по INP. 

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

Меня зовут Кирилл Радыгин. Я руководитель фронтэнд направления в компании Одноклассники. В этой статье я расскажу, как команда ОК адаптировала соцсеть под изменившийся набор метрик оценки перформанса.

Немного контекста

Для оценки качества и отзывчивости сайтов классически используется набор метрик Core Web Vitals, предложенный компанией Google. С недавних пор он включает три основных показателя:

  • LCP (Largest Contentful Paint) — скорость загрузки большого контента;

  • CLS (Cumulative Layout Shift) — совокупный сдвиг макета;

  • INP (Interaction to Next Paint) — скорость реакции интерфейса на взаимодействия.

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

При этом до марта 2024 года вместо метрики INP был показатель FID, который описывает скорость реакции на первый отклик сразу после загрузки страницы. INP же, в свою очередь, является более комплексной метрикой и оценивает все взаимодействия на протяжении сессии пользователя. Например, насколько быстро меняет положение «тумблер-переключатель» на сайте после клика пользователя.

Нюанс в том, что даже по оценке Google только 65 % сайтов достаточно оптимизированы по метрике INP, то есть после введения метрики в основной набор Core Web Vitals остальные 35 % потенциально могли начать терять позиции в поисковой выдаче. Для такой соцсети как ОК это было недопустимо, поэтому мы сразу начали смотреть в сторону оптимизации.

Шаг 1. Определяем «существует ли проблема»

Базово есть несколько источников получения информации о проблемах с производительностью сайта:

  • жалобы пользователей — обратная связь от аудитории, если сайт начинает работать не так, как того ожидают пользователи;

  • субъективное ощущение — если зависания и некорректные отрисовки заметны даже на мощных девайсах разработчиков;

  • инструменты браузера и плагины — основная проблема этих данных заключается в их синтетичности;

  • открытые данные в Google Console — один из инструментов хорошего СЕОшника.

Именно из последнего источника мы получили информацию о потенциальной проблеме.

После внесения изменений в состав Google Core Web Vitas для нас было важно проконтролировать, чтобы просадки в ранжировании поисковыми системами у нас не произошло. Для первичной аналитики данных мы использовали Google Console — сервис, который отображает данные о реальном опыте пользователей на основе данных из CrUX (Chrome UX Report).

По INP мы обнаружили много проблемных страниц. Причем большинство проблем с метрикой возникало только на мобильных устройствах.

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

По LCP критических проблем в нашем случае не было, но сопоставимых улучшений требовала как десктопная, так и мобильная версия сайта.

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

Из этого мы сделали несколько промежуточных выводов:

  • однозначно сказать, что после 12.03.2024 наше ранжирование в Google стало хуже — нельзя;

  • «всё плохо» у нас только на мобильных устройствах;

  • нет гарантии, что ранжирование улучшится, если мы улучшим метрику INP.

Шаг 2. Подбираем и настраиваем инструменты

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

Критериев при выборе инструмента было несколько. Так, нам было важно, чтобы инструмент:

  • был готов к работе;

  • снабжал наглядной информацией, отвечая на вопрос «есть ли проблема в принципе»;

  • предоставлял достаточно детализированную информацию, по которой можно понять причину проблемы и ее локализацию;

  • предоставлял актуальную информацию;

  • гарантировал достоверность данных.

Мы рассматривали несколько вариантов.

  • Google Console. Решение готово к работе, позволяет локализовать проблему и гарантирует достоверность данных. Но информация в отчетах Google Console недостаточно детализирована. Более того, часто сведения в Google Console обновляются с большой задержкой. По итогу мы оставили этот инструмент только для верификации совокупно-крупных улучшений в среднем раз в 3 месяца.

  • Dev Tools, Plugins. Всевозможные плагины по замеру перформанса — удобный и понятный вариант, с которым можно быстро начать работать. Но ключевой их недостаток в том, что они генерируют синтетические данные на основе синтетических прогонов. То есть инструменты не отражают реальный опыт пользователей и могут сообщать о том, что все плохо, когда по факту это не так и наоборот. Соответственно, эти решения нам не подошли.

  • Внутренние данные. У ОК уже была большая база метрик по клиентской производительности. Нюанс в том, что эти метрики часто были избыточно детализированы и явно не сопоставлялись с используемыми Google метриками Core Web Vitals., то есть были не показательны и нашу проблему не решали.

  • CWV Library. Библиотека для работы с Core Web Vitals — официальное и поддерживаемое Google решение, которое помогает разработчикам измерять и улучшать ключевые показатели скорости и удобства сайта. Решение отвечало всем нашим запросам и имело лишь один недостаток — его нужно было интегрировать. Этим мы и занялись.

Интеграция CWV Library

Произведя интеграцию инструмента, мы столкнулись с рядом сложностей. Одной из них была проблема пустых данных — например, весомая часть логов по INP событиям в базе не содержала информацию об элементе, который спровоцировал событие. Как выяснилось, это происходило из-за особенностей Performance API, который не кешировал свойство target после исчезновения элемента из DOM’a в рамках произвольного сценария.

Сперва мы хотели решить эту проблему с помощью кеширования через monkey-patching PerformanceEntry. Но столкнулись с тем, что API написан на C++ и закрыт для изменений.

В результате мы пошли другим путем и продублировали логику webVitals.onINP() логированием на корневом элементе с последующим кешированием и маппингом элементов событий.

Примечание: интеграция CWV библиотеки для наших задач представляла собой нечто большее, чем просто подключение библиотеки в package.json. Это также подразумевало написание оберток на клиенте и сервере для прокидывания и сохранения данных, интеграцию этих данных в анализаторы для сравнения по А/Б и добавление индикаторов для отслеживания аномальных изменений. То есть интеграция Google CWV библиотеки — это хороший, но не дешевый вариант.

Шаг 3. Поиск страниц для оптимизации и исправление проблем

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

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

Начнем с метрики LCP.

Largest Contentful Paint (LCP)

Показатели LCP зависят от скорости загрузки большого контента. Есть несколько типовых практик, способных улучшить метрику. Среди них:

  • уменьшение времени загрузки первого байта;

  • минимизация задержки перед стартом загрузки;

  • оптимизация времени загрузки;

  • минимизация задержки перед рендером.

Первые две практики подразумевают оптимизацию старта загрузки. Наиболее простой и очевидный способ добиться этого — добавить LCP-содержимое в preload. Это можно сделать 3 разными способами, но наиболее универсальной по поддержке будет следующая реализация на уровне кода:

  • добавить тег link в <head />;

  • добавить к нему атрибут rel=“preload”;

  • добавить к нему атрибут fetchpriority=“high”;

<link rel=“preload" fetchpriority=“high” href=“image.png” />

На картинке ниже видно, что загрузка ресурса с прелоадом происходит в числе первых. Кроме того, красной зоной обозначается дополнительный выигрыш примерно на 50 миллисекунд за счет изменения fetchpriority=”auto” на fetchpriority=“high”.

Способы оптимизации времени загрузки довольно стандартные. Так, желательно:

  • выбирать небольшие по размерам медиафайлы;

  • использовать оптимальное сжатие: webp (картинки), zstd (шрифты);

  • применять кеширование;

  • делать сжатие не в рантайме на уровне условного nginx’a, а статически, в том числе для таких популярных протоколов, как gzip, brotli, deflate;

  • повышать скорость отдачи с сервера с помощью CDN.

К слову, с последним у нас произошло неожиданное открытие — в какой-то момент мы обнаружили, что раздаем CSS & JS не с CDN, а с сервера. Начав изучение, мы нашли фича-тогл, который был отключен несколько лет назад ввиду отсутствия видимого эффекта от CDN’a при А/B.

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

Чтобы проверить гипотезу, мы сформировали выборку пользователей с локаций вокруг наших региональных нод, добавили логирование времени загрузки всех ресурсов с помощью performance.getEntries() и провели повторное A/B на этой выборке. Результаты показали, что для 75 % пользователей из выборки среднее время загрузки ресурса уменьшилось в 2 или более раз — с 536 мс до 258 мс.

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

Это показательный пример, почему важно думать о распределении аудитории в разрезе выбора и настройки CDN.

Четвертая лучшая практика для улучшения показателей LCP — сокращение задержки отрисовки. Добиться этого можно:

  • отображая LCP-элемент сразу;

  • разгружая основной поток в браузере:

  • уменьшая загружаемый на старте .css;

  • минимизируя наличие синхронных скриптов;

Примечание: просадка LCP нередко бывает связана и с загрузкой тяжеловесных рекламных баннеров, которые часто грузятся асинхронно с дополнительными раунд трипами, иногда в айфрейме. Мы в ОК на некоторых страницах также сталкивались с ситуацией, когда LCP элементом в 3 или 4 колонке выбиралась реклама, из-за чего страницы имели плохие показатели. На мой взгляд, это не совсем справедливо, потому что условно долгая загрузка рекламы не характеризует с негативной стороны User Experience. Решением данной проблемы может быть загрузка прозрачного баннера на 1px больше рекламного баннера. Именно таким образом мы исключили влияние скорости загрузки рекламы, чем срезали определенное количество негативных значений и улучшили LCP на всех этих страницах.

Таким образом, на основе своего опыта мы можем сформулировать некоторые рекомендации в части оптимизации LCP:

  • Избавляйтесь от избыточных раунд трипов перед загрузкой LCP элемента.

  • Увеличивайте приоритет загрузки LCP ресурсов.

  • Не загружайте на старте ненужный для первого рендера контент, например, невидимый под теми же модалками.

  • Осознанно используйте прозрачность для неважных, с точки зрения UX, кейсов.

  • Используйте CDN, если ваша аудитория распределена по разным локациям.

Cumulative Layout Shift (CLS)

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

Показатель CLS определяется по формуле:

CLS = доля меняющейся области * доля расстояния сдвига

При этом окно замера — 5 секунд, и учитывается максимальный сдвиг среди всех окон. Если коэффициент выше 0,1 — результат плохой.

Причин возникновения «скачков» на странице может быть несколько:

  • отсутствие размеров у изображений на стадии отрисовки;

  • отсутствие размеров у динамически внедряемого контента;

  • неприоритетная загрузка веб-шрифтов.

Соответственно, чтобы не допускать таких проблем, достаточно:

  • не двигать элементы без интеракций;

  • отображать визуальный статус для действий с большой задержкой (чтобы пользователи видели, что идет загрузка, а не сайт завис);

  • не провоцировать reflow при анимациях.

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

INP

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

При этом жизненный цикл события состоит из трех этапов:

  • задержка перед обработкой эвента — клик, ввод текста, тап на мобильном устройстве с последующей паузой до попадания в браузерный основной поток;

  • обработка события — браузер регистрирует действие и запускает связанный код (например, JavaScript);

  • рендеринг (отрисовка) — браузер перерисовывает страницу или ее часть, чтобы показать изменения (например, анимацию загрузки после клика).

Поизучав данные от CVW библиотеки, мы обнаружили, что основным источником INP событий на сайте были:

  • навигационные элементы;

  • root-элементы;

  • вызывающие относительно тяжелую логику элементы (кнопка «Play» и кнопка «Fullscreen» в плеере, кнопка переключения фотографии & etc).

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

  • повышение прозрачности процесса загрузки;

  • оптимизация активации страниц;

  • оптимизация ключевых сценариев.

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

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

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

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

Отдельно хочется рассказать про оптимизацию сценария fullscreen’a. Дело в том, что видеоплеер у нас был одной из самых проблемных страниц, и, согласно данным, весомая часть проблем с INP генерировалась именно нажатием на кнопку фуллскрина, то есть либо входом в фуллскрин, либо выходом из него.

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

Решением для этого стало следующее: теперь перед вызовом fullscreen API мы берем значение window.offsetWidth и фиксируем его для нашего рутового элемента с контентом. Это помогло нам срезать большое количество экстремальных значений INP.

Кроме того, еще одним удивительно простым, но очень эффективным улучшением на мобильных устройствах было удаление задержки в 300-350 мс за счет добавления touch-action: manipulation на рутовый DOM элемент. Добиться аналогичного эффекта можно и с помощью добавления мета-тега. Подробнее о природе этой задержки и способах решения можно почитать в этой статье.

В целом, на основе нашего опыта оптимизации INP можно сформулировать несколько общих рекомендаций:

  • разгружайте основной поток в браузере;

  • не выполняйте ненужных действий, особенно в тяжелых операциях;

  • разбивайте тяжелые операции на несколько;

  • форсируйте рендеринг первоначальной реакции;

  • разбивайте рендеринг на несколько шагов;

  • убирайте задержку в 300 мс для мобильных устройств.

Шаг 4. Оцениваем результат

После проделанной работы нам было важно оценить, насколько эффективной она была с точки зрения поисковика. Для этого мы снова обратились к Google Console — только так можно было объективно понять разницу «до и после». Результаты оказались значительными.

  • По INP из зоны высокой критичности убрали все проблемные с точки зрения SEO разделы: фото, группы, профиль, поиск и витрину видео.

  • По LCP из зоны средней критичности убрали леера поста, фото, видео, а также разделы групп, профиля, поиска и подарков.

  • По CLS мы снизили количество страниц в зоне высокой и средней критичности до 0.

Шаг 5. Стабилизируем

В контексте оптимизации работа никогда не заканчивается получением результатов — чтобы не потерять их, нужно непрерывно отслеживать состояние продукта и поддерживать его «в тонусе».

При этом всю работу по стабилизации сайта можно условно разделить на этапы «до прода» и «в проде».

Так, чтобы исключить появление новых проблем и своевременно реагировать на потенциальные ошибки до прода мы применяем несколько практик.

  • Добавили автотесты. Теперь результаты CVW складываются в глобальный объект, и при заходе на страницу автотест осуществляет тестовый сценарий и забирает накопленные результаты. Такой прогон делается несколько десятков раз, после чего сравниваются средние значения этих прогонов на конкретных страницах со средними значениями в рамках последних релизов. Если есть значительные отклонения — тест падает, и мы получаем соответствующее уведомление.

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

  • Анализируем конкурентов. Мы используем внутреннее решение Salmon для проверки сценариев, аналогичных нашим, на внешних сервисах, что позволяет понять, хуже или лучше работают фичи конкурентов, и находить точки роста в оптимизации нашей соцсети. При этом конкурентов мы делим на две категории: с точки зрения позиционирования продукта и с точки зрения SEO позиционирования.

Для уменьшения проблем, способных привести к ухудшению перформанса соцсети в проде, мы также проделали большой объем работы. В том числе:

  • добавили обязательную проверку перформанса в рамках А/Б тестирования;

  • подключили мониторинги для аномальных изменений в ряде сервисов;

  • настроили процесс реагирования на аномалии.

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

Что в итоге

Мы в команде ОК проделали большой путь по оптимизации показателей перформанса соцсети в Core Web Vitals — от обнаружения проблем до их устранения и минимизации риска появления новых. И наш опыт, в котором были как встречи с «подводными камнями», так и успешное улучшение метрик, дает возможность выделить несколько ключевых мыслей.

  • Просадка показателей в Core Web Vitals не всегда ведет к изменению CTR и средней позиции — в нашем случае этого не случилось, и наш кейс в этом плане не уникален. Но есть и другая сторона медали — хорошие результаты в отчете ещё не гарантируют высоких рейтингов сайта. 

  • При работе над SEO не стоит ограничиваться только метриками Core Web Vitals, ведь перформанс — это один из более чем 200 критериев. Соответственно, улучшая эти показатели, нельзя забывать о других, которые могут быть характерны только для вашего сайта и сайтов конкурентов.

  • Различных оптимизаций может быть много, и не все из них зависят от frontend’a. 

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

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

А как переход с FID на INP сказался на метриках вашего сайта? И как вы подошли к оптимизации? Делитесь своим опытом в комментариях.

Теги:
Хабы:
+29
Комментарии0

Публикации

Информация

Сайт
team.vk.company
Дата регистрации
Дата основания
Численность
свыше 10 000 человек
Местоположение
Россия
Представитель
Дмитрий Головин