---
layout: post
title: Скорость загрузки основного контента (LCP)
authors:
  - philipwalton
date: 2019-08-08
updated: 2022-10-19
description: В этой статье описывается метрика LCP (Скорость загрузки основного контента) и объясняются принципы ее измерения
tags:
  - performance
  - metrics
---

{% Aside %} Скорость загрузки основного контента (LCP) важный, ориентированный на пользователя показатель для измерения [воспринимаемой скорости загрузки,](/user-centric-performance-metrics/#types-of-metrics) так как он отмечает на шкале времени загрузки страницы момент вероятной загрузки основного контента. Низкий показатель LCP убеждает пользователя в [полезности](/user-centric-performance-metrics/#questions) страницы. {% endAside %}

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

Старые метрики, например, события [load](https://developer.mozilla.org/docs/Web/Events/load) или [DOMContentLoaded](https://developer.mozilla.org/docs/Web/Events/DOMContentLoaded), не подходят, так как они не обязательно соответствуют тому, что пользователь видит на экране. А более новые, ориентированные на пользователя показатели производительности, такие как [Первая отрисовка контента (FCP)](/fcp/), отражают только самое начало процесса загрузки. Пользователю не очень важен момент отображения заставки или индикатора загрузки на странице.

Раньше рекомендовалось использовать такие показатели производительности, как [First Meaningful Paint : Время отрисовки основного контента (FMP)](https://developer.chrome.com/docs/lighthouse/performance/first-meaningful-paint/) и [Speed Index : Индекс скорости (SI)](https://developer.chrome.com/docs/lighthouse/performance/speed-index/) (оба показателя доступны в Lighthouse), чтобы помочь оценить восприятие пользователем страницы после начальной отрисовки. Но эти метрики достаточно сложны, запутаны и часто неверны. Это означает, что они всё еще не определяют точное время загрузки основного контента страницы.

Чем проще, тем лучше. Основываясь на обсуждениях в группе [W3C Web Performance Working Group](https://www.w3.org/webperf/) и исследованиях, проведенных в Google, мы обнаружили, что более точный способ измерить время загрузки основного содержимого страницы это зафиксировать время отрисовки самого большого элемента страницы.

## Что такое LCP?

Метрика LCP (Скорость загрузки основного контента) сообщает время рендеринга самого большого [изображения или текстового блока](#what-elements-are-considered), видимого в области просмотра, отсчитанное от момента [начала загрузки](https://w3c.github.io/hr-time/#timeorigin-attribute) страницы.

<picture>
  <source srcset="{{ "image/tcFciHGuF3MxnTr1y5ue01OGLBn2/elqsdYqQEefWJbUM2qMO.svg" | imgix }}" media="(min-width: 640px)" width="400", height="100">
  {% Img src="image/eqprBhZUGfb8WYnumQ9ljAxRrA72/8ZW8LQsagLih1ZZoOmMR.svg", alt="Хорошие значения LCP - 2,5 секунды, низкие значения больше 4,0 секунд, и все, что находится между ними, требует улучшения", width="400", height="300" %}
</picture>

### Что такое хороший показатель LCP?

Для обеспечения удобства работы пользователей сайты должны стремиться к тому, чтобы максимальная продолжительность отрисовки контента составляла **2,5 секунды** или меньше. Чтобы убедиться, что вы достигли этой цели для большинства пользователей, рекомендуется в качестве порогового значения использовать **75-й процентиль** загрузки страниц, сегментированный по мобильным и настольным устройствам.

{% Aside %} Чтобы узнать больше об исследованиях и методологии, лежащих в основе этой рекомендации, см. [«Определение пороговых значений показателей Core Web Vitals»](/defining-core-web-vitals-thresholds/) {% endAside %}

### Какие элементы учитываются?

По данным из [API LCP](https://wicg.github.io/largest-contentful-paint/), при оценке скорости загрузки основного контента учитываются следующие типы элементов:

- элементы `<img>`;
- элементы `<image>` внутри элемента `<svg>`;
- элементы `<video>` (используется изображение постера);
- элементы с фоновым изображением, загруженным с помощью функции [`url()`](https://developer.mozilla.org/docs/Web/CSS/url()) (в отличие от [CSS-градиента](https://developer.mozilla.org/docs/Web/CSS/CSS_Images/Using_CSS_gradients));
- [блочные элементы](https://developer.mozilla.org/docs/Web/HTML/Block-level_elements), содержащие текстовые узлы или другие дочерние строковые элементы.

Обратите внимание, что типы элементов были намеренно ограничены этим списком, чтобы упростить начальную задачу. Дополнительные элементы (например, `<svg>`, `<video>`) могут быть добавлены в будущем по мере проведения дополнительных исследований.

### Как определяются размеры элемента?

Размер элемента для метрики LCP обычно равен размеру, который виден пользователю в области просмотра. Не учитывается в размере элемента следующее: элементы, выходящие за пределы области просмотра, обрезанные элементы и элементы с невидимым [переполнением](https://developer.mozilla.org/docs/Web/CSS/overflow).

В случае масштабированных изображений учитывается видимый или [внутренний размер](https://developer.mozilla.org/docs/Glossary/Intrinsic_Size), в зависимости от того, что меньше. Например, для уменьшенных изображений учитываются размеры, в которых они отображаются, а для растянутых изображений—внутренние (подлинные) размеры.

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

Для всех элементов не учитываются поля, отступы или границы, применяемые с помощью CSS.

{% Aside %} Иногда сложно определить, какие текстовые узлы каким элементам принадлежат. Особенно для элементов, чьи дочерние элементы включают встроенные элементы и узлы с простым текстом, а также блочные элементы. Ключевой момент здесь в том, что каждый текстовый узел принадлежит своему ближайшему блочному элементу-предку (и только ему). В [терминах спецификации](https://wicg.github.io/element-timing/#set-of-owned-text-nodes): каждый текстовый узел принадлежит элементу, который генерирует [содержащий его блок](https://developer.mozilla.org/docs/Web/CSS/Containing_block). {% endAside %}

### Когда сообщается об отрисовке самого большого элемента?

Страницы часто загружаются поэтапно, поэтому самый большой элемент на странице может меняться.

Чтобы уловить возможные изменения, браузер отправляет запись [`PerformanceEntry`](https://developer.mozilla.org/docs/Web/API/PerformanceEntry) типа `largest-contentful-paint`, идентифицирующую самый большой элемент контента, как только отрисовывается первый фрейм. А затем, после рендеринга последующих фреймов, браузер отправляет другие [`PerformanceEntry`](https://developer.mozilla.org/docs/Web/API/PerformanceEntry) при каждом изменении самого большого элемента контента.

Например, на странице с текстом и главным изображением (hero image) браузер может сначала просто отобразить текст—в этот момент он отправит запись `largest-contentful-paint`, свойство `element` которой, скорее всего, будет ссылаться на `<p>` или `<h1>`. Позже, как только главное изображение загрузится, будет отправлена следующая запись `largest-contentful-paint`, а её свойство `element` уже будет ссылаться на `<img>`.

Следует отметить, что элемент может считаться самым большим элементом контента только после того, как он отрисовался и стал видимым для пользователя. Изображения, которые еще не загрузились, не считаются «отрисованными». Текстовые узлы также не используют веб-шрифты в период [блокировки шрифтов](https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display#The_font_display_timeline). В таких случаях о меньшем элементе может сообщаться как о самом большом элементе контента, но как только завершится рендеринг более крупного элемента, браузер сообщит об этом, отправив другой объект `PerformanceEntry`.

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

Если элемент, который в настоящее время является самым большим элементом контента, удаляется из области просмотра (или даже удаляется из DOM), он будет оставаться самым большим элементом контента, пока не появится более крупный элемент.

{% Aside %} До Chrome 88 удаленные элементы не считались самыми большими элементами контента, и их удаление приводило к отправке новой записи `largest-contentful-paint`. Однако из-за популярных шаблонов пользовательского интерфейса, например карусели изображений, которые часто удаляют DOM-элементы, метрика была обновлена, чтобы точнее отражать восприятие пользователей. Более подробную информацию см. в [ЖУРНАЛЕ ИЗМЕНЕНИЙ](https://chromium.googlesource.com/chromium/src/+/master/docs/speed/metrics_changelog/2020_11_lcp.md). {% endAside %}

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

Аналитической службе для проведения оценки понадобится только последняя отправленная запись `PerformanceEntry`.

{% Aside 'caution' %} Иногда пользователи могут открывать страницы в фоновых вкладках. В этом случае отрисовка самого большого элемента контента может вообще не произойти до тех пор, пока пользователь не перейдет в эту вкладку, а это может случиться позднее первой загрузки страницы.{% endAside %}

#### Время загрузки и время рендеринга

По соображениям безопасности метка времени рендеринга изображений не отображается для изображений из разных источников, у которых отсутствует заголовок [`Timing-Allow-Origin`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Timing-Allow-Origin). Вместо этого отображается только время их загрузки (поскольку оно уже доступно через многие другие веб-API).

В [приведенном ниже примере](#measure-lcp-in-javascript) показано, как обрабатывать элементы, время рендеринга которых недоступно. Но, по возможности, всегда рекомендуется устанавливать заголовок [`Timing-Allow-Origin`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Timing-Allow-Origin), чтобы ваши показатели были более точными.

### Как обрабатываются изменения макета и размера элемента?

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

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

### Примеры

Вот несколько примеров того, как меняется самый большой элемент контента на нескольких популярных веб-сайтах:

{% Img src="image/admin/bsBm8poY1uQbq7mNvVJm.png", alt="Временная шкала LCP с cnn.com", width="800", height="311" %}

{% Img src="image/admin/xAvLL1u2KFRaqoZZiI71.png", alt="Временная шкала LCP с techcrunch.com", width="800", height="311" %}

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

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

{% Img src="image/admin/uJAGswhXK3bE6Vs4I5bP.png", alt="Временная шкала LCP с instagram.com", width="800", height="311" %}

{% Img src="image/admin/e0O2woQjZJ92aYlPOJzT.png", alt="Временная шкала LCP с google.com", width="800", height="311" %}

В первом примере логотип Instagram загружается относительно рано и остается самым большим элементом даже по мере отрисовки другого контента. В примере страницы результатов поиска Google самый большой элемент - это абзац текста, который отображается до завершения загрузки любого логотипа или изображения. Так как все отдельные изображения меньше этого абзаца, он остается самым большим элементом на протяжении всего процесса загрузки.

{% Aside %} На первом фрейме временной шкалы Instagram можно заметить, что вокруг логотипа камеры нет зеленой рамки. Это потому, что это элемент `<svg>`, а данные элементы в настоящее время не считаются кандидатами LCP. Первый кандидат LCP это текст во втором фрейме. {% endAside %}

## Как измерить LCP

LCP можно измерить в [лабораторных](/user-centric-performance-metrics/#in-the-lab) или [полевых условиях](/user-centric-performance-metrics/#in-the-field) с помощью следующих инструментов:

### Инструменты для измерения в полевых условиях

- Отчет [Chrome User Experience Report](https://developer.chrome.com/docs/crux/)
- [PageSpeed Insights](https://pagespeed.web.dev/)
- [Search Console (отчет Core Web Vitals report)](https://support.google.com/webmasters/answer/9205520)
- [JavaScript-библиотека `web-vitals`](https://github.com/GoogleChrome/web-vitals)

### Инструменты для измерения в лабораторных условиях

- [Chrome DevTools](https://developer.chrome.com/docs/devtools/)
- [Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/)
- [PageSpeed Insights](https://pagespeed.web.dev/)
- [WebPageTest](https://webpagetest.org/)

### Измерение LCP в JavaScript

{% BrowserCompat 'api.LargestContentfulPaint' %}

Чтобы измерить LCP с помощью JavaScript, можно воспользоваться [Largest Contentful Paint API](https://wicg.github.io/largest-contentful-paint/). В следующем примере показано, как создать [`PerformanceObserver`](https://developer.mozilla.org/docs/Web/API/PerformanceObserver), который прослушивает записи `largest-contentful-paint` и регистрирует их в консоли.

```js
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('LCP candidate:', entry.startTime, entry);
  }
}).observe({type: 'largest-contentful-paint', buffered: true});
```

{% Aside 'warning' %}

Этот код показывает, как регистрировать `largest-contentful-paint`, но само измерение LCP в JavaScript сложнее. Подробнее см. ниже:

{% endAside %}

В приведенном выше примере каждая зарегистрированная запись `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](/bfcache/#impact-on-core-web-vitals), но в данных случаях следует измерять LCP, поскольку пользователи воспринимают такие посещения страниц как отдельные.
- API не учитывает элементы внутри iframe, но для правильного измерения LCP их нужно учитывать. Элементы iframe могут использовать API, чтобы сообщать о своих записях `largest-contentful-paint` в родительский фрейм для агрегирования.

Чтобы не запоминать все эти тонкости, разработчики могут использовать для измерения LCP [JavaScript-библиотеку `web-vitals`](https://github.com/GoogleChrome/web-vitals), которая обрабатывает эти случаи (где это возможно):

```js
import {onLCP} from 'web-vitals';

// Measure and log LCP as soon as it's available.
onLCP(console.log);
```

Полный пример измерения LCP в JavaScript приводится в [исходном коде `onLCP()`](https://github.com/GoogleChrome/web-vitals/blob/main/src/onLCP.ts).

{% Aside %} В некоторых случаях (например, в iframe с перекрестным происхождением) невозможно измерить LCP в JavaScript. См. подробности в разделе  [«Ограничения»](https://github.com/GoogleChrome/web-vitals#limitations) библиотеки `web-vitals`. {% endAside %}

### Что если самый большой элемент не самый важный?

В некоторых случаях самый важный элемент (или элементы) на странице оказывается не самым большим, и разработчики могут быть больше заинтересованы в измерении времени рендеринга данных элементов. Это можно сделать с помощью [Element Timing API](https://wicg.github.io/element-timing/), как описано в статье о [«Пользовательских метриках»](https://wicg.github.io/element-timing/).

## Как улучшить LCP

В первую очередь на LCP влияют четыре фактора:

- медленное время ответа сервера;
- блокирующие рендеринг JavaScript и CSS;
- время загрузки ресурса;
- клиентский рендеринг.

Подробные сведения о том, как улучшить LCP, см. в статье [«Оптимизация LCP»](/optimize-lcp/). Дополнительные рекомендации по отдельным методам повышения производительности, которые также могут улучшить LCP, смотрите в следующих статьях:

- [Применение мгновенной загрузки с помощью шаблона PRPL](/apply-instant-loading-with-prpl)
- [Оптимизация критического пути рендеринга](/critical-rendering-path/)
- [Оптимизация CSS](/fast#optimize-your-css)
- [Оптимизация изображений](/fast#optimize-your-images)
- [Оптимизация веб-шрифтов](/fast#optimize-web-fonts)
- [Оптимизация JavaScript](/fast#optimize-your-javascript) (для сайтов с рендерингом на стороне клиента)

## Дополнительные ресурсы

- [Уроки, извлеченные Энни Салливан](https://anniesullie.com/) [из мониторинга производительности в Chrome](https://youtu.be/ctavZT87syI) с помощью функции [performance.now ()](https://perfnow.nl/) (2019 г.)

{% include 'content/metrics/metrics-changelog.njk' %}
