Оптимизация скорости загрузки основного контента
Как ускорить рендеринг основного контента.
Я не вижу полезного контента! Почему так долго загружается? 😖
Одним из факторов, ухудшающих пользовательский опыт, является длительное время рендеринга контента. Метрика FCP (Первая отрисовка контента) измеряет, сколько времени требуется для визуализации исходного содержимого DOM, но не фиксирует, сколько времени потребовалось для визуализации самого большого (обычно более значимого) содержимого на странице.
LCP (Скорость загрузки основного контента)это метрика Core Web Vitals, измеряющая время, за которое становится видимым самый большой элемент контента в области просмотра. Ее можно использовать, чтобы определить, когда основное содержимое страницы завершило рендеринг на экране.
Наиболее частые причины плохого показателя LCP:
- медленное время ответа сервера;
- блокирующие рендеринг JavaScript и CSS;
- медленное время загрузки ресурсов;
- клиентский рендеринг.
Медленное время ответа сервера #
Чем дольше браузер получает контент с сервера, тем больше времени требуется для отображения чего-либо на экране. Более быстрое время отклика сервера напрямую улучшает каждую метрику загрузки страницы, включая LCP.
Прежде всего, улучшите то, как и где ваш сервер обрабатывает контент. Используйте метрику TTFB (Время до первого байта), чтобы измерить время ответа сервера. Есть несколько способов улучшить TTFB:
- оптимизировать сервер;
- направлять пользователей в ближайшую CDN (географически распределённую сетевую инфраструктуру);
- кешировать активы;
- применять для HTML-страниц политику выборки cache-first;
- устанавливать сторонние подключения на раннем этапе;
- использовать подписанные обмены.
Оптимизация сервера #
Вы запускаете ресурсоёмкие запросы, на выполнение которых у вашего сервера уходит много времени? Или на стороне сервера происходят другие сложные операции, которые задерживают процесс возврата содержимого страницы? Анализ и повышение эффективности вашего серверного кода напрямую улучшит время, необходимое браузеру для получения данных.
Вместо того чтобы сразу же обслуживать статическую страницу по запросу браузера, многим серверным веб-фреймворкам необходимо создавать веб-страницу динамически. Другими словами, вместо отправки готового HTML-файла по запросу браузера, фреймворкам необходимо запускать логику для создания страницы. Это может быть связано с ожиданием результатов запроса к базе данных или даже с тем, что компоненты должны быть сгенерированы с разметкой с помощью платформы пользовательского интерфейса (например, React). Многие веб-платформы, работающие на сервере, содержат рекомендации по производительности, которые можно использовать для ускорения этого процесса.
Направление пользователей в ближайшую CDN #
Сеть доставки контента (CDN)это географически распределенная сетевая инфраструктура. Если контент на вашей веб-странице размещается на одном сервере, то веб-сайт будет загружаться медленнее для географически удаленных пользователей, потому что запросы их браузера должны буквально путешествовать по всему миру. Рассмотрите возможность использования CDN, чтобы вашим пользователям никогда не приходилось ждать выполнения сетевых запросов к удаленным серверам.
Кеширование активов #
Если ваш HTML статичен и его не нужно изменять при каждом запросе, кеширование может предотвратить его ненужное воссоздание. Сохраняя копию сгенерированного HTML на диске, кеширование на стороне сервера может уменьшить TTFB и минимизировать использование ресурсов.
В зависимости от вашего пакета инструментальных средств существует множество различных способов применения кеширования на сервере:
- настройте обратные прокси-серверы (Varnish, nginx) для обслуживания кешированного содержимого или работы в качестве кеш-сервера при установке перед сервером приложений;
- настройте режим кеширования на облачном провайдере (Firebase, AWS, Azure);
- используйте CDN, которая переадресует запросы пользователя к географически ближайшему кеширующему серверу сети.
Применение для HTML-страниц политики выборки cache-first #
После установки сервис-воркер работает в фоновом режиме браузера и может перехватывать запросы с сервера. Этот уровень программного управления кешем позволяет кешировать часть или всё содержимое HTML-страницы и обновлять кеш только при изменении контента.
На следующей диаграмме показано, как с помощью этого шаблона было сокращено распределение LCP на сайте:

На диаграмме показано распределение LCP с одного сайта за последние 28 дней, сегментированное по состоянию сервис-воркера. Обратите внимание, насколько больше загрузок страниц имеют более быстрое значение LCP после того, как в сервис-воркере для HTML-страниц была введена политика выборки cache-first (синяя часть столбцов диаграммы).
Установление сторонних подключений на раннем этапе #
Запросы сервера к сторонним источникам также могут повлиять на LCP, особенно если они необходимы для отображения важного содержимого на странице. Используйте rel="preconnect"
, чтобы сообщить браузеру, что ваша страница намеревается установить соединение как можно скорее.
<link rel="preconnect" href="https://example.com" />
Кроме того, можно использовать dns-prefetch
для более быстрого поиска DNS.
<link rel="dns-prefetch" href="https://example.com" />
Хотя обе подсказки работают по-разному, рассмотрите возможность использования dns-prefetch
в качестве запасного варианта для браузеров, которые не поддерживают preconnect
.
<head>
…
<link rel="preconnect" href="https://example.com" />
<link rel="dns-prefetch" href="https://example.com" />
</head>
Использование подписанных обменов (SXG) #
Подписанные обмены (SXG)это механизм доставки, который позволяет ускорить взаимодействие с пользователем, предоставляя контент в легко кешируемом формате. В частности, Google Поиск будет кешировать, а иногда и предварительно загружать файлы SXG. Для сайтов, которые получают большую часть своего трафика от Поиска Google, SXG могут стать важным инструментом улучшения LCP. Более подробно см. в статье «Подписанные обмены».
Блокирующие рендеринг JavaScript и CSS #
Прежде чем браузер сможет отобразить какой-либо контент, ему необходимо преобразовать разметку HTML в дерево DOM. Анализатор HTML приостановит работу, если обнаружит какие-либо внешние таблицы стилей (<link rel="stylesheet">
) или синхронные теги JavaScript (<script src="main.js">
).
Сценарии и таблицы стилейэто блокирующие рендеринг ресурсы, которые задерживают FCP и, следовательно, LCP. Отложите любой некритический JavaScript и CSS, чтобы ускорить загрузку основного контента веб-страницы.
Уменьшение времени блокировки CSS #
С помощью следующих шагов сведите блокирующий рендеринг CSS к минимально необходимому:
- выполните минификацию CSS-кода;
- отложите некритический CSS-код;
- встройте критический CSS-код в HTML.
Минификация CSS #
Для удобочитаемости CSS-файлы могут содержать интервалы, отступы или комментарии. Все эти символы не нужны браузеру, и путём удаления их из исходного кода можно уменьшить его размер. В конечном итоге уменьшение количества блокирующего CSS-кода всегда сокращает время, необходимое для полной отрисовки основного контента страницы (LCP).
Если вы используете сборщик модулей или систему сборки пакетов, включите соответствующий плагин для минификации CSS-кода при каждой сборке:
- для webpack: optimize-css-assets-webpack-plugin;
- для Gulp: gulp-clean-css;
- для Rollup: rollup-plugin-css-porter.

Отложенная загрузка некритичного CSS-кода #
Используйте вкладку Coverage в Chrome DevTools, чтобы найти неиспользуемый CSS-код на своей веб-странице.

Для оптимизации:
- Полностью удалите неиспользуемый CSS или переместите его в другую таблицу стилей, если он используется на отдельной странице вашего сайта.
- Остальной CSS-код, который не требуется для начального рендеринга страницы, загружайте асинхронно с помощью библиотеки loadCSS, использующей
rel="preload"
иonload
.
<link rel="preload" href="stylesheet.css" as="style" onload="this.rel='stylesheet'">

Встраивание критического CSS-код в HTML #
Встройте любой критический CSS-код, используемый для содержимого верхней части страницы, включив его непосредственно в <head>.

Встраивание важных стилей избавляет от необходимости делать двусторонний запрос для получения критически важного CSS. Отсрочка остального сводит к минимуму время блокировки CSS.
Если вы не можете вручную добавить встроенные стили на свой сайт, используйте библиотеку для автоматизации процесса. Несколько примеров:
- Critical, CriticalCSS и Penthouseвсё это пакеты, которые извлекают и встраивают верхнюю часть CSS.
- Crittersэто плагин для веб-пакетов, который встраивает критический CSS и отлаживает загрузку прочего CSS.

Уменьшение времени блокировки JavaScript #
Загрузите и предоставьте пользователям минимальное количество необходимого JavaScript. Уменьшение количества блокирующих рендеринг JavaScript приводит к более быстрой отрисовке и, как следствие, лучшему значению LCP.
Этого можно добиться, оптимизируя скрипты несколькими различными способами:
- выполняйте минификацию и сжатие файлов JavaScript;
- отложите загрузку неиспользуемого JavaScript;
- минимизируйте неиспользуемые полифиллы.
Медленное время загрузки ресурсов #
Хотя увеличение времени блокировки CSS или JavaScript напрямую приведет к снижению производительности, время, необходимое для загрузки многих других типов ресурсов, также может повлиять на время отрисовки. Типы элементов, которые влияют на LCP:
- элементы
<img>
; - элементы
<image>
внутри элемента<svg>
; - элементы
<video>
(момент отрисовки изображения poster используется для измерения LCP); - элементы с фоновым изображением, загруженным с помощью функции
url()
(в отличие от CSS-градиента); - блочные элементы, содержащие текстовые узлы или другие дочерние строковые элементы.
Время, необходимое для загрузки этих элементов при рендеринге в верхней части страницы, будет иметь прямое влияние на LCP. Есть несколько способов обеспечить максимально быструю загрузку этих файлов:
- оптимизировать и сжимать изображения;
- предварительно загружать важные ресурсы;
- сжимать текстовые файлы;
- доставлять различные ресурсы на основании сетевого подключения (адаптивное обслуживание);
- кешировать активы с помощью сервис-воркера.
Оптимизация и сжатие изображений #
Для многих сайтов изображения—самые крупные элементы, видимые после завершения загрузки страницы. Главные изображения, большие карусели или изображения баннеров—типичные примеры крупных элементов.

Улучшение времени загрузки и рендеринга этих типов изображений, напрямую ускорит LCP. Для этого:
- Подумайте о том, чтобы не использовать изображения в первую очередь. Если они не важны для контента, удалите их.
- Сжимайте изображения (например, с помощью Imagemin).
- Преобразуйте изображений в новые форматы (JPEG 2000, JPEG XR или WebP).
- Используйте адаптивные изображения.
- Рассмотрите возможность использования CDN для обработки изображений.
Предварительная загрузка важных ресурсов #
Иногда важные ресурсы, которые объявлены или используются в определенном файле CSS или JavaScript, могут извлекаться позже, чем требуется (например, шрифт, спрятанный глубоко в одном из многих CSS-файлов приложения).
Если вы знаете, что приоритет должен быть отдан определенному ресурсу, используйте <link rel="preload">
, чтобы получить его раньше. Можно предварительно загрузить многие типы ресурсов, но сначала следует сосредоточиться на предварительной загрузке критически важных ресурсов, таких как шрифты, изображения или видео в верхней части страницы, а также CSS или JavaScript для критических этапов рендеринга.
<link rel="preload" as="script" href="script.js" />
<link rel="preload" as="style" href="style.css" />
<link rel="preload" as="image" href="img.png" />
<link rel="preload" as="video" href="vid.webm" type="video/webm" />
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />
Начиная с Chrome 73, предварительную загрузку можно использовать вместе с адаптивными изображениями, чтобы объединить оба шаблона для более быстрой загрузки изображений.
<link
rel="preload"
as="image"
href="wolf.jpg"
imagesrcset="wolf_400px.jpg 400w, wolf_800px.jpg 800w, wolf_1600px.jpg 1600w"
imagesizes="50vw"
/>
Сжатие текстовых файлов #
Алгоритмы сжатия, такие как Gzip и Brotli, могут значительно уменьшить размер текстовых файлов (HTML, CSS, JavaScript) при их передаче между сервером и браузером. Gzip эффективно поддерживается во всех браузерах, а Brotli, обеспечивающий еще лучшие результаты сжатия, и поддерживается почти всеми новыми браузерами.
Сжатие ресурсов минимизирует размер их доставки, сокращая время загрузки и, следовательно, LCP.
- Сначала проверьте, использует ли уже ваш сервер автоматическое сжатие файлов. Большинство хостинговых платформ, CDN и обратных прокси-серверов либо кодируют ресурсы со сжатием по умолчанию, либо позволяют легко настроить сжатие.
- Если вам нужно внедрить сжатие файлов на сервере, рассмотрите возможность использования Brotli вместо Gzip, поскольку Brotli обеспечивает лучшую степень сжатия.
- После того как вы выберите алгоритм сжатия, сжимайте ресурсы заранее в процессе сборки, а не на лету, когда они запрашиваются браузером. Это минимизирует потребление ресурсов сервера и предотвратит задержки при выполнении запросов, особенно при использовании высоких степеней сжатия.

Адаптивное обслуживание #
При загрузке ресурсов, составляющих основной контент страницы, эффективным может быть условная выборка различных ресурсов в зависимости от типа устройства или условий сети пользователя. Это можно сделать с помощью API-интерфейсов Network Information, Device Memory и HardwareConcurrency.
Если у вас есть большие ресурсы, критически важные для первоначального рендеринга, вы можете использовать разные варианты одного и того же ресурса в зависимости от скорости подключения или от устройства пользователя. Например, вы можете отображать изображение вместо видео для любых скоростей подключения ниже 4G:
if (navigator.connection && navigator.connection.effectiveType) {
if (navigator.connection.effectiveType === '4g') {
// Load video
} else {
// Load image
}
}
Список полезных свойств, которые вы можете использовать:
navigator.connection.effectiveType
: эффективный тип подключения;navigator.connection.saveData
: экономия данных включена/отключена;navigator.hardwareConcurrency
: количество ядер ЦП;navigator.deviceMemory
: память устройства.
Кэширование активов с помощью сервис-воркера #
Сервис-воркеры могут использоваться для множества полезных задач, в том числе для сокращения ответов на запросы контента HTML, как упоминалось ранее в этой статье. Их также можно использовать для кеширования любого статического ресурса, чтобы затем выдать его браузеру, а не загружать из сети при повторных запросах.
Предварительное кеширование критических ресурсов с помощью сервис-воркера может значительно сократить время их загрузки, особенно для пользователей, которые перезагружают веб-страницу, используя более слабое подключение (или даже получают к ней доступ в автономном режиме). Иногда, чтобы упростить процесс обновления предварительно кешированных ресурсов, проще использовать библиотеку наподобие Workbox, чем писать пользовательский сервис-воркер.
Рендеринг на стороне клиента #
Многие сайты используют клиентскую логику JavaScript для отображения страниц непосредственно в браузере. Фреймворки и библиотеки, такие как React , Angular и Vue, упростили создание одностраничных приложений, которые обрабатывают различные аспекты веб-страницы полностью на стороне клиента, а не на сервере.
Если вы создаете сайт, который в основном отображается на стороне клиента, вам следует опасаться влияния больших пакетов JavaScript на LCP. Если не предусмотреть оптимизацию для предотвращения этого влияния, пользователи могут не видеть контент или не иметь возможности взаимодействовать с ним на странице до тех пор, пока не завершится загрузка и выполнение всего критического JavaScript-кода.
При создании сайта, отображаемого на стороне клиента, подумайте о проведении следующих оптимизаций:
- минимизируйте критический JavaScript;
- используйте рендеринг на стороне сервера;
- используйте предварительный рендеринг.
Минимизация критического JavaScript #
Если контент на вашем сайте становится видимым или с ним можно взаимодействовать только после загрузки определенного количества JavaScript, то первоочередной задачей стаёт максимальное уменьшение размера пакета. Для этого:
- выполните минификацию JavaScript;
- отложите загрузку неиспользуемого JavaScript;
- минимизируйте неиспользуемые полифиллы.
Вернитесь в раздел «Уменьшение времени блокировки JavaScript», чтобы подробнее прочитать об этих оптимизациях.
Использование рендеринга на стороне сервера #
Минимизация количества JavaScriptпервоочередная задача для сайтов, которые в основном отрисовываются на стороне клиента. Кроме того, для максимального улучшения LCP следует рассмотреть возможность сочетания клиентского и серверного рендеринга.
Эта концепция работает с использованием сервера для рендеринга приложения в HTML, где клиент затем «впитывает» весь JavaScript и необходимые данные в одно и то же содержимое DOM. Это может улучшить LCP, гарантируя, что основное содержимое страницы сначала отрисовывается на сервере, а не только на клиенте, но есть несколько недостатков:
- сохранение одного и того же приложения, отрисованного с помощью JavaScript, на сервере и на клиенте может увеличить сложность;
- выполнение JavaScript для рендеринга HTML-файла на сервере всегда увеличивает время ответа сервера (TTFB) по сравнению с простым обслуживанием статических страниц с сервера;
- страница, отображаемая на сервере, может выглядеть так, как будто с ней можно взаимодействовать, но она не может реагировать на действия пользователя, пока не будет выполнен весь клиентский JavaScript. Проще говоря, это может ухудшить метрику TTI (Время до интерактивности).
Использование предварительного рендеринга #
Предварительный рендерингэто отдельный метод, который менее сложен, чем рендеринг на стороне сервера, но также позволяет улучшить LCP в вашем приложении. Браузер без графического интерфейса используется для создания статических файлов HTML для каждого маршрута во время сборки. Затем эти файлы могут быть отправлены вместе с пакетами JavaScript, необходимыми для приложения.
При предварительном рендеринге TTI по-прежнему подвергается негативному воздействию, но время отклика сервера не так сильно ухудшается, как при рендеринге на стороне сервера, которое динамически отображает каждую страницу только после ее запроса.

Инструменты разработчика #
Для измерения и отладки LCP доступен ряд инструментов:
- Lighthouse 6.0 включает поддержку измерения LCP в лабораторных условиях.

- Раздел Timings панели Performance в Chrome Devtools включает маркер LCP и показывает, какой элемент связан с LCP при наведении мыши на поле Related Node.

- Отчет Chrome User Experience Report предоставляет реальные значения LCP, агрегированные на уровне источника.
Выражаем благодарность Филиппу Уолтону, Кэти Хемпениус, Кейси Баскесу и Илье Григорику за их обзоры.