Оптимизируем отрисовку вашего приложения

Прогрессивная загрузка изображений

Добавив прогрессивную загрузку изображений, вы сможете вывести ленивую загрузку на новый уровень. По аналогии с Facebook, Pinterest, Medium и Wolt сначала можно показать превью низкого качества (можно даже размытое), а затем, по мере загрузки страницы, заменять их на изображения с более высоким разрешением. Для этого можно исопльзовать BlurHash или LQIP (Low Quality Image Placeholders).

Не смотря на то, что нет единого мнения относительно эффективности подобной оптимизации, но она определенно улучшает метрику FCP (First Contentful Paint). Для генерации плейсхолдеров для ваших изображений можено использовать SQIP или Gradient Image Placeholders

Дин Хьюм (Dean Hume) описал, как использовать эти плейсхолдеры вместе с IntersectionObserver.

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

Техника ленивой загрузки SVG. Источник. Увеличить.

Отложенные рендеринг с помощью content-visibility

Для сложных layout-ов с большим количеством блоков, изображений и видео декодинг и рендеринг этих блоков может быть дорогостоящей операцией, особенно для low-end устройств. С помощью ‘content-visibility: auto' можно скрывать блоки, если контейнер находится за пределами вьюпорта.

Вот так можно скрыть футер при первоначальной загрузке:
footer {

  content-visibility: auto;
  contain-intrinsic-size: 1000px;
  /* 1000px is an estimated height for sections
that are not rendered yet. */

}
Обратите внимание, что content-visibility: auto; ведет себя как overflow: hidden; Но это можно исправить, поменяв стандартные margin-left: auto; margin-right: auto; на padding-left и padding-right. По сути, padding позволяет элементам выходить за пределы content-box и попадать в padding-box, не выходя за пределы контейнера в целом и не обрезаясь.

Будьте осторожны. Вы можете ухудшить метрику CLS. Чтобы избежать этого эффекта воспользуйтесь contain-intrinsic-size с плейсхолдером нужного размера.

Тийс Терлуин и Мальте Убл (Thijs Terluin, Malte Ubl) подробнее написали об этих двух свойствах здесь и здесь. А в этом коротком видео от Джейка и Сурмы объясняется, как всё работает.

Если вам нужен более гибкий контроль отрисовки обратите внимание на CSS Containment
В этом примере применение ‘content-visibility: auto' к областям контента, разбитым на куски, дает 7-кратный прирост производительности рендеринга при первоначальной загрузке. (Увеличить)

Оптимизируем производительность рендеринга

Пользователи сразу же замечают если ваше приложение визуально подтормаживает. В идеале необходимо стремиться чтобы перерисовка страницы происходила с частотой 60 кадров в секунду (60fps). Если вы не можете достичь такого результаты постарайтесь сделать так, чтобы частота перерисовки оставалась постоянной

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

В DevTools есть множество полезных инструментов для отладки скорости рендеринга. Вот список полезных материалов:
Обратите внимание: Изменение некоторых CSS-свойства вызывают только “Compositing” шаг в цепочке рендеринга. Поэтому если вы используете  opacity  и transform, вы на правильном пути. В статье  Debugging UI Rendering Performance вы найдёте много практических советов. А чтобы понять, как отладить производительность отрисовки в DevTools, посмотрите видеоролик Paint Performance audit video.

Perceived performance

Perceived performance то как ваши пользователи воспринимают производительность вашей страницы. Может быть полезно учитывать психологический аспект этого восприятия. Например, мы можете как-то развлечь ваших пользователей, пока происходит что-то ещё. Здесь в игру вступают управление восприятием, preemptive start, early completion и tolerance management.

При загрузке ассетов полезно быть на шаг впереди клиента: попытаться создать видимость быстрого UX. Чтобы вовлечь пользователя, можно использовать skeleton screens (смотрите демо) вместо индикаторов загрузки или добавлять плавные анимированные переходы.

В исследовании The Art of UI Skeletons Кумара МакМиллана (Kumar McMillan) можно найти несколько трюков для создания динамических списков и текста, а также информацию о том как применяется skeleton-thinking в React.

Будьте осторожны: предварительно протестируйте свои скелетоны. некоторые тесты показали, что они могут негативно влиять на UX.

Избегайте смещения layoutа и перерисовок (repaint)

Layout shift (смещение контента) один из самых неприятных эффектов, который может повлиять на воспринимаемую производительность и будет раздражать ваших пользователей. Этот эффект возникает из-за изменения размера изображений, веб-шрифтов, встраиваемой рекламы или скриптов которые генерируют компоненты уже после загрузки вашего контента

Есть несколько техник и правил чтобы избежать этого неприятного эффекта:
  • Избегайте вставки нового контента перед уже существующим существующего, если только это не происходит в ответ на пользовательское действие.
  • Всегда задавайте атрибуты width и height для изображений. Современные сразу же будут вставлять блок нужного размера (Firefox, Chrome).
  • Для изображений, и для видео можно использовать SVG-плейсхолдер, это поможет работать с изображениями и видео с учетом их пропорций
  • Мы также можем использовать плейсхолдеры или для рекламы и любого другого динамического контента
  • Вы можете использовать нативную или гибридную ленивой загрузку для ваших изображений вместо техник основанных на использовании JavaScript
  • Всегда группируйте перерисовку веб-шрифтов и переходите от всех фолбек-шрифтов ко всем веб-шрифтам одновременно — только убедитесь, что этот переход не будет слишком резким, отрегулируйте line-height и интервалы между шрифтами с помощью font-style-matcher. Чтобы переопределить параметры fallback-шрифта можно использовать @font-face descriptors.
  • Так же нам следует убедиться, что весь CSS влияющий на наш layout заинлайнен в начале каждой страницы.
  • Для страниц с прокруткой скролбар смещает контент на 16 пикселей влево. Чтобы показать скролбар заранее, мы можем добавить overflow-y к нашей странице. Эта техника также может помочь так как скролбар может вызывать хитрые смещения контента
  • Для табов в с разным количеством текста вы можете предотвратить смещение контента, используя CSS grid stacks. Для этого разместите контент каждого таба в одной и той же области грида (grid-area)
  • Бесконечная прокрутка и «Загрузить еще» могут вызывать смещения контента если у вас есть контент ниже этим областей. Чтобы улучшить CLS заранее выделите достаточно места для загружаемого контента, а также переместите весь контент который может быть смещен вниз при загрузке
  • Подгружайте данные и изображения заранее, до того как пользователь до них доскролил.
  • Вы можете использовать специальные библиотеки, например react-window чтобы оптимизировать работу с длинными списками (спасибо, Эдди Османи!).
Вы можете использовать Layout Instability API для расчета метрики Cumulative Layout Shift (CLS) и добавить эту метрику к своим тестам. Так вы сразу обнаружите регрессию этой метрики и сможете все быстро исправить.