Скорость загрузки основного контента (LCP)
В прошлом веб-разработчикам было довольно сложно измерять время, за которое основной контент веб-страницы загружается и становится видимым для пользователей.
Старые метрики, например, события load или DOMContentLoaded, не подходят, так как они не обязательно соответствуют тому, что пользователь видит на экране. А более новые, ориентированные на пользователя показатели производительности, такие как Первая отрисовка контента (FCP), отражают только самое начало процесса загрузки. Пользователю не очень важен момент отображения заставки или индикатора загрузки на странице.
Раньше рекомендовалось использовать такие показатели производительности, как First Meaningful Paint : Время отрисовки основного контента (FMP) и Speed Index : Индекс скорости (SI) (оба показателя доступны в Lighthouse), чтобы помочь оценить восприятие пользователем страницы после начальной отрисовки. Но эти метрики достаточно сложны, запутаны и часто неверны. Это означает, что они всё еще не определяют точное время загрузки основного контента страницы.
Чем проще, тем лучше. Основываясь на обсуждениях в группе W3C Web Performance Working Group и исследованиях, проведенных в Google, мы обнаружили, что более точный способ измерить время загрузки основного содержимого страницы это зафиксировать время отрисовки самого большого элемента страницы.
Что такое LCP? #
Метрика LCP (Скорость загрузки основного контента) сообщает время рендеринга самого большого изображения или текстового блока, видимого в области просмотра, отсчитанное от момента начала загрузки страницы.
Что такое хороший показатель LCP? #
Для обеспечения удобства работы пользователей сайты должны стремиться к тому, чтобы максимальная продолжительность отрисовки контента составляла 2,5 секунды или меньше. Чтобы убедиться, что вы достигли этой цели для большинства пользователей, рекомендуется в качестве порогового значения использовать 75-й процентиль загрузки страниц, сегментированный по мобильным и настольным устройствам.
Какие элементы учитываются? #
По данным из API LCP, при оценке скорости загрузки основного контента учитываются следующие типы элементов:
- элементы
<img>
; - элементы
<image>
внутри элемента<svg>
; - элементы
<video>
(используется изображение постера); - элементы с фоновым изображением, загруженным с помощью функции
url()
(в отличие от CSS-градиента); - блочные элементы, содержащие текстовые узлы или другие дочерние строковые элементы.
Обратите внимание, что типы элементов были намеренно ограничены этим списком, чтобы упростить начальную задачу. Дополнительные элементы (например, <svg>
, <video>
) могут быть добавлены в будущем по мере проведения дополнительных исследований.
Как определяются размеры элемента? #
Размер элемента для метрики LCP обычно равен размеру, который виден пользователю в области просмотра. Не учитывается в размере элемента следующее: элементы, выходящие за пределы области просмотра, обрезанные элементы и элементы с невидимым переполнением.
В случае масштабированных изображений учитывается видимый или внутренний размер, в зависимости от того, что меньше. Например, для уменьшенных изображений учитываются размеры, в которых они отображаются, а для растянутых изображений—внутренние (подлинные) размеры.
В случае текстовых элементов учитывается только размер их текстовых узлов (наименьший прямоугольник, охватывающий все текстовые узлы).
Для всех элементов не учитываются поля, отступы или границы, применяемые с помощью CSS.
Когда сообщается об отрисовке самого большого элемента? #
Страницы часто загружаются поэтапно, поэтому самый большой элемент на странице может меняться.
Чтобы уловить возможные изменения, браузер отправляет запись PerformanceEntry
типа largest-contentful-paint
, идентифицирующую самый большой элемент контента, как только отрисовывается первый фрейм. А затем, после рендеринга последующих фреймов, браузер отправляет другие PerformanceEntry
при каждом изменении самого большого элемента контента.
Например, на странице с текстом и главным изображением (hero image) браузер может сначала просто отобразить текст—в этот момент он отправит запись largest-contentful-paint
, свойство element
которой, скорее всего, будет ссылаться на <p>
или <h1>
. Позже, как только главное изображение загрузится, будет отправлена следующая запись largest-contentful-paint
, а её свойство element
уже будет ссылаться на <img>
.
Следует отметить, что элемент может считаться самым большим элементом контента только после того, как он отрисовался и стал видимым для пользователя. Изображения, которые еще не загрузились, не считаются «отрисованными». Текстовые узлы также не используют веб-шрифты в период блокировки шрифтов. В таких случаях о меньшем элементе может сообщаться как о самом большом элементе контента, но как только завершится рендеринг более крупного элемента, браузер сообщит об этом, отправив другой объект PerformanceEntry
.
Помимо дальнейшей загрузки изображений и шрифтов, страница может добавлять новые элементы в DOM по мере того, как новый контент становится доступным. Если какой-либо из этих новых элементов окажется больше, чем предыдущий самый большой элемент контента, то браузер сообщит об этом с помощью PerformanceEntry
.
Если элемент, который в настоящее время является самым большим элементом контента, удаляется из области просмотра (или даже удаляется из DOM), он будет оставаться самым большим элементом контента, пока не появится более крупный элемент.
Браузер перестанет сообщать о новых записях, как только пользователь начнет взаимодействовать со страницей (касание, клик, прокрутка или нажатие клавиш), поскольку в результате взаимодействие отображаемый контент может измениться (что особенно верно при прокрутке).
Аналитической службе для проведения оценки понадобится только последняя отправленная запись PerformanceEntry
.
Время загрузки и время рендеринга #
По соображениям безопасности метка времени рендеринга изображений не отображается для изображений из разных источников, у которых отсутствует заголовок Timing-Allow-Origin
. Вместо этого отображается только время их загрузки (поскольку оно уже доступно через многие другие веб-API).
В приведенном ниже примере показано, как обрабатывать элементы, время рендеринга которых недоступно. Но, по возможности, всегда рекомендуется устанавливать заголовок Timing-Allow-Origin
, чтобы ваши показатели были более точными.
Как обрабатываются изменения макета и размера элемента? #
Чтобы снизить влияние вычислений и отправки LCP-записей на общую производительность, изменение размеров или положения элемента не учитываются и не приводят к созданию новых кандидатов LCP. Учитывается только начальный размер и положение элемента в области просмотра.
Это означает, что изображения, которые изначально появляются за пределами видимой области и лишь затем оказываются в ней, могут не учитываться. Верно и обратное: изначально отображаемые в видимой области элементы, которые затем уходят из поля зрения, продолжат сообщать о своем исходном размере в области просмотра.
Примеры #
Вот несколько примеров того, как меняется самый большой элемент контента на нескольких популярных веб-сайтах:


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


В первом примере логотип Instagram загружается относительно рано и остается самым большим элементом даже по мере отрисовки другого контента. В примере страницы результатов поиска Google самый большой элемент - это абзац текста, который отображается до завершения загрузки любого логотипа или изображения. Так как все отдельные изображения меньше этого абзаца, он остается самым большим элементом на протяжении всего процесса загрузки.
Как измерить LCP #
LCP можно измерить в лабораторных или полевых условиях с помощью следующих инструментов:
Инструменты для измерения в полевых условиях #
- Отчет Chrome User Experience Report
- PageSpeed Insights
- Search Console (отчет Core Web Vitals report)
- JavaScript-библиотека
web-vitals
Инструменты для измерения в лабораторных условиях #
Измерение LCP в JavaScript #
- Chrome 77, Supported 77
- Firefox, Not supported
- Edge 79, Supported 79
- Safari, Not supported
Чтобы измерить LCP с помощью JavaScript, можно воспользоваться Largest Contentful Paint API. В следующем примере показано, как создать PerformanceObserver
, который прослушивает записи largest-contentful-paint
и регистрирует их в консоли.
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP candidate:', entry.startTime, entry);
}
}).observe({type: 'largest-contentful-paint', buffered: true});
В приведенном выше примере каждая зарегистрированная запись largest-contentful-paint
представляет текущего кандидата LCP. Как правило, значение startTime
последней отправленной записи является значением LCP, однако это не всегда так. Не все записи largest-contentful-paint
подходят для измерения LCP.
Далее приведем различия между тем, что сообщает API, и тем, как рассчитывается метрика.
Различия между метрикой и API #
- API будет отправлять записи с
largest-contentful-paint
для страниц, загруженных в фоновых вкладках, но при вычислении LCP такие страницы следует игнорировать. - API продолжит отправку записей
largest-contentful-paint
после того, как страница перестанет быть фоновой, но эти записи следует игнорировать при вычислении LCP (элементы могут учитываться только в том случае, если страница всё время была на переднем плане). - API не сообщает о записях
largest-contentful-paint
, когда страницы восстанавливаются функцией back/forward cache, но в данных случаях следует измерять LCP, поскольку пользователи воспринимают такие посещения страниц как отдельные. - API не учитывает элементы внутри iframe, но для правильного измерения LCP их нужно учитывать. Элементы iframe могут использовать API, чтобы сообщать о своих записях
largest-contentful-paint
в родительский фрейм для агрегирования.
Чтобы не запоминать все эти тонкости, разработчики могут использовать для измерения LCP JavaScript-библиотеку web-vitals
, которая обрабатывает эти случаи (где это возможно):
import {onLCP} from 'web-vitals';
// Measure and log LCP as soon as it's available.
onLCP(console.log);
Полный пример измерения LCP в JavaScript приводится в исходном коде onLCP()
.
Что если самый большой элемент не самый важный? #
В некоторых случаях самый важный элемент (или элементы) на странице оказывается не самым большим, и разработчики могут быть больше заинтересованы в измерении времени рендеринга данных элементов. Это можно сделать с помощью Element Timing API, как описано в статье о «Пользовательских метриках».
Как улучшить LCP #
В первую очередь на LCP влияют четыре фактора:
- медленное время ответа сервера;
- блокирующие рендеринг JavaScript и CSS;
- время загрузки ресурса;
- клиентский рендеринг.
Подробные сведения о том, как улучшить LCP, см. в статье «Оптимизация LCP». Дополнительные рекомендации по отдельным методам повышения производительности, которые также могут улучшить LCP, смотрите в следующих статьях:
- Применение мгновенной загрузки с помощью шаблона PRPL
- Оптимизация критического пути рендеринга
- Оптимизация CSS
- Оптимизация изображений
- Оптимизация веб-шрифтов
- Оптимизация JavaScript (для сайтов с рендерингом на стороне клиента)
Дополнительные ресурсы #
- Уроки, извлеченные Энни Салливан из мониторинга производительности в Chrome с помощью функции performance.now () (2019 г.)
CHANGELOG #
Occasionally, bugs are discovered in the APIs used to measure metrics, and sometimes in the definitions of the metrics themselves. As a result, changes must sometimes be made, and these changes can show up as improvements or regressions in your internal reports and dashboards.
To help you manage this, all changes to either the implementation or definition of these metrics will be surfaced in this CHANGELOG.
If you have feedback for these metrics, you can provide it in the web-vitals-feedback Google group.