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


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


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


В этом руководстве мы рассмотрим те оптимизации производительности, которые:


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

Эти рекомендации представляют собой самые эффективные и применимые способы улучшения показателей Core Web Vitals. Если вы новичок в сфере производительности веб-приложений или еще не решили, на чем сосредоточиться для достижения максимальной отдачи от инвестиций, это руководство станет для вас отличной отправной точкой.


❯ Взаимодействие со следующей отрисовкой


Взаимодействие со следующей отрисовкой (Interaction to Next Paint, INP) — это новейший показатель Core Web Vitals, он предоставляет значительные возможности для улучшения производительности. Однако стоит отметить, что гораздо меньшее количество сайтов сейчас достигает стандартов "хорошего" пользовательского опыта по сравнению с устаревшим показателем. Вероятно, мы попали в число разработчиков, которые впервые сталкиваются с задачей оптимизации скорости ответа на взаимодействие.


Рассмотрим методы, которые помогут нам достичь наилучших результатов в повышении INP.


1. Регулярные паузы для разделения длительных задач


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


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


Scheduler API позволяет ставить задачи в очередь с учетом их приоритетов. В частности, метод scheduler.yield() разбивает длительные задачи, позволяя обрабатывать действия пользователя, без потери их места в очереди задач.





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


Оптимизация длительных задач


2. Минимизация JavaScript


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


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


  • пользуйтесь стандартными, широко доступными функциями веб-платформы, вместо избыточных реализаций на JS
  • используйте инструмент покрытия (coverage tool) в Chrome DevTools для выявления неиспользуемого кода. Снижение объема ресурсов, необходимых для первичной загрузки, приводит к уменьшению нагрузки на парсинг и компиляцию, что обеспечивает более комфортное первое впечатление для пользователя
  • внедрите технику разделения кода, чтобы создавать отдельные пакеты для кода, который не нужен при первоначальном рендеринге, но будет использоваться позже
  • если вы используете тег-менеджер, периодически проводите его оптимизацию. Удаляйте устаревшие теги с неиспользуемым кодом, чтобы сократить объем загружаемого JS

Удаление неиспользуемого кода


3. Минимизация крупных обновлений рендеринга


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


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



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


❯ Скорость загрузки основного контента


Скорость загрузки основного контента (Largest Contentful Paint, LCP) является одним из ключевых показателей качества пользовательского опыта, с которым разработчики нередко испытывают трудности. В соответствии с отчетом Chrome UX, 40% сайтов не соответствуют рекомендованному порогу LCP для обеспечения хорошего пользовательского опыта. Команда Chrome предлагает несколько наиболее эффективных методов для улучшения LCP.


1. Обеспечение доступности ресурса LCP в HTML-коде и его приоритетность


Команда Chrome обратила внимание на несколько важных аспектов, касающихся LCP в вебе:


  • согласно отчету Web Almanac 2022 года от HTTP Archive, 72% мобильных страниц используют изображение в качестве элемента LCP
  • анализ данных реальных пользователей Chrome показывает, что большинство сайтов с низким LCP тратят менее 10% своего времени на уровне 75-го процентиля на загрузку изображения LCP
  • на страницах с низким LCP загрузка LCP-изображений задерживается на стороне клиента на 1290 миллисекунд на 75-м процентиле — это больше половины рекомендуемого времени для быстрого взаимодействия
  • на страницах, где LCP-элемент представлен в виде изображения, 39% изображений имели URL-адреса, которые не были доступны в исходном HTML-ответе (например,<img src="..."> или <link rel="preload" href="...">). Это мешает браузеру заблаговременно обнаруживать эти ресурсы
  • согласно данным Web Almanac, лишь 0,03% подходящих страниц используют атрибут HTML fetchpriority для повышения приоритета ресурсов, включая те, которые могли бы улучшить LCP страницы минимальными усилиями

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


Если проблема заключается в медленной загрузке ресурсов, важно понять, что, возможно, уже не получится достичь хорошего LCP, если страница ожидает полной загрузки CSS или JavaScript перед загрузкой изображений. Кроме того, продолжительность загрузки изображения LCP можно сократить, сделав его более приоритетным, чтобы оно получало больше пропускной способности и загружалось быстрее с помощью атрибута HTML fetchpriority.





Если элемент LCP представлен в виде изображения, его URL-адрес должен быть доступен в HTML-ответе для ускорения его загрузки. Вот несколько рекомендаций, как это сделать:


  • Используйте элемент <img> с атрибутами src или srcset для загрузки изображений. Избегайте нестандартных атрибутов, таких как data-src, для рендеринга которых требуется JS, это замедлит процесс. 9% страниц скрывают свои LCP-изображения за data-src.
  • Используйте серверный рендеринг (SSR) вместо клиентского (CSR), поскольку SSR предполагает наличие всей разметки страницы (включая изображения) в HTML-коде. CSR требуют выполнения JS перед загрузкой изображений.
  • Если ссылка на изображение содержится во внешнем CSS или JS-файле, все равно можно включить его в HTML-код с помощью тега <link rel="preload">. Учтите, что изображения, указанные во встроенных стилях, не могут быть обнаружены сканером предварительной загрузки браузера.

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


  • Добавьте атрибут fetchpriority="high" к тегам <img> или <link rel="preload"> LCP-изображения. Это увеличивает приоритет ресурса изображения, позволяя раньше начинать его загрузку.


  • Удалите атрибут loading="lazy" из тега <img> LCP-изображения. Это помогает избежать задержки загрузки, связанной с проверкой нахождения изображения в пределах или рядом с областью просмотра.


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


  • Устраните задержку загрузки ресурсов


  • Распространенные заблуждения об оптимизации LCP



2. Мгновенная навигация


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


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


Возможность восстановления ранее посещенных страниц обеспечивается кэшем назад/вперед (bfcache). Для его эффективного использования необходимо, чтобы страницы соответствовали определенным критериям. Наиболее распространенные причины неподходящих для bfcache страниц включают отсутствие кэширования (no-store) или наличие обработчиков события unload.


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


Предварительная загрузка следующей страницы, которую пользователь собирается посетить — еще один эффективный способ значительно улучшить производительность LCP, и этот процесс возможен благодаря API Speculation Rules. Однако, чтобы добиться улучшений, необходимо правильно определять страницы для предварительной загрузки. Неверные спекуляции могут привести к лишней трате ресурсов как на серверной, так и на клиентской стороне, что, в свою очередь, может ухудшить общую производительность. Поэтому, если нет уверенности в том, какая страница будет следующей, стоит проявить осторожность в ее предварительной загрузке. В случае сомнений, аналитические данные могут помочь с выбором страниц с наивысшей вероятностью следующего посещения.






3. Использование CDN для оптимизации TTFB


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


Это время известно как время до первого байта (Time to First Byte, TTFB). Чтобы сократить TTFB, нужно помнить о следующих принципах:


  • размещать контент как можно ближе к пользователям географически
  • кешировать контент для быстрого ответа при повторных запросах

Наилучший способ реализовать оба принципа — использовать CDN. Сети доставки контента (Content Delivery Network, CDN) распределяют ресурсы по серверам, расположенным ближе к пользователям, тем самым уменьшая расстояние, которое им нужно преодолеть. Кроме того, большинство CDN предлагают широкие возможности для тонкой настройки кэширования в зависимости от потребностей сайта.


Хотя CDN могут также обслуживать и кэшировать HTML-документы, согласно данным Web Almanac, лишь 29% запросов к этим документам обрабатываются через CDN. Это открывает значительные возможности для оптимизации.


Вот несколько рекомендаций по настройке CDN:


  • кешируйте статические HTML-документы даже на короткое время. Насколько важно, чтобы контент всегда был актуальным? Как часто его необходимо обновлять?
  • рассмотрите возможность переноса динамической логики, выполняемой на основном сервере, на граничные серверы — такую функцию предлагают большинство современных CDN

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


Оптимизация TTF


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


Совокупный сдвиг макета Cumulative Layout Shift, CLS — это степень смещения элементов на странице с момента ее загрузки. Несмотря на то, что CLS является метрикой, в которой большинство сайтов показывает хорошие результаты, примерно четверть из них все же не достигает рекомендованных значений. Это открывает значительные перспективы в улучшении пользовательского опыта для многих сайтов.


1. Четкие размеры для загружаемого контента


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


Наилучший способ устранить сдвиги, вызванные изображениями без заданных размеров, — это явно указать атрибуты width и height, а также эквивалентные им CSS-свойства. 72% страниц содержат хотя бы одно изображение без заданных размеров. Если размеры не заданы, изображения изначально отображаются с высотой 0px, что может привести к смещению макета при загрузке и последующем определении размеров браузером.


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





Однако не всегда удается точно определить размеры динамического контента. Даже в таких случаях, когда конкретные размеры неизвестны, можно все же уменьшить сдвиги макета. Установка разумного значения min-height почти всегда является лучшим вариантом, чем позволить браузеру использовать значение высоты по умолчанию, равное 0px для пустого элемента. Это решение обычно простое и эффективное, поскольку дает возможность контейнеру увеличиваться до высоты окончательного контента, но при этом ограничивает его до более приемлемого уровня.


Оптимизация CLS


2. Страницы, поддерживающие bfcache


Как уже упоминалось в этом руководстве, bfcache позволяет мгновенно загружать страницы из истории браузера с помощью сохраненного снимка памяти (snapshot). Эта оптимизация на уровне браузера значительно улучшает LCP и полностью устраняет смещения макета. На самом деле, появление bfcache в 2022 году стало причиной самого значительного улучшения CLS в том году.


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


Владельцы сайтов должны проверить, подходят ли страницы для использования bfcache, и устранить причины, по которым это невозможно. В Chrome, в инструментах разработчика есть специальный инструмент для тестирования bfcache. Также можно воспользоваться API Not Restored Reasons для выявления причин недоступности.


3. Анимации и переходы CSS вызывают сдвиги макета


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


Хотя данные HTTP Archive не могут однозначно показать связь между анимациями и сдвигами макета, исследования показывают, что страницы, которые анимируют любые CSS-свойства, способные повлиять на макет, на 15% реже имеют "хороший" CLS по сравнению с другими страницами. Некоторые свойства оказывают худшее влияние на показатели CLS, чем другие. Например, страницы, анимирующие ширину полей (margin) или рамок (border), имеют "плохой" CLS почти вдвое чаще, чем другие страницы.


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


Некоторых разработчиков может удивить, что это также касается элементов, выведенных за пределы обычного потока документа. Например, анимация элементов с абсолютным позиционированием в направлении верхней или левой границы также приводит к смещениям макета, даже если другие элементы не смещаются. Однако, если вместо анимации вертикальной или горизонтальной позиции мы используем transform: translateX() или transform: translateY(), обновление макета страницы браузером не потребуется, что поможет избежать сдвигов.


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


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


Аудит Lighthouse под названием "Избегайте некомпозитных анимаций" предупреждает, когда страница анимирует потенциально медленные CSS-свойства.


Оптимизация сдвигов макета, вызываемых анимацией


❯ Заключение


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


Руководства для получения дополнительной информации:





Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале

Комментарии (0)