Largest Contentful Paint (LCP)

Largest Contentful Paint (LCP) – важная, ориентированная на пользователя метрика для измерения визуально-воспринимаемой скорости загрузки, она фиксирует на временной шкале загрузки страницы точку, когда основное содержимое страницы, вероятно, загружено. Быстрая LCP помогает убедить пользователя в том, что страница полезна .

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

Старые метрики, такие как load или DOMContentLoaded, не подходят, потому что они не обязательно соответствуют тому, что пользователь видит на своем экране. А новые, ориентированные на пользователя показатели производительности, такие как First Contentful Paint (FCP), отражают только самое начало процесса загрузки. Если на странице отображается заставка или индикатор загрузки, этот момент не очень важен для пользователя.

Раньше рекомендовались такие показатели производительности, как First Meaningful Paint (FMP) и Speed ​​Index (SI) (оба доступны в Lighthouse), чтобы помочь уловить больше впечатлений от загрузки после начальной отрисовки, но эти показатели сложны, их трудно объяснить. Они часто неверны – это означает, что они все еще не определяют, когда загружено основное содержимое страницы.

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

Что такое LCP?

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

Largest Contentful Paint (LCP)

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

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

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

Как указано в API Largest Contentful Paint в настоящее время, для оценки будут рассматриваться следующие типы элементов:

  • элементы <img>
  • элементы <image> внутри элемента <svg>
  • элементы <video> (используется изображение постера)
  • элементы с фоновым изображением, загруженным с помощью функции url() (в отличие от CSS-градиента)
  • блочные элементы, содержащие текстовые узлы или другие дочерние строковые элементы

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

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

Размер элемента, о котором сообщается для Largest Contentful Paint, обычно равен размеру, который виден пользователю в области просмотра. Если элемент выходит за пределы области просмотра, или если какой-либо элемент обрезан или имеет невидимое overflow, эти части не учитываются в размере элемента.

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

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

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

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

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

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

Чтобы перехватить возможные изменения, браузер отправляет PerformanceEntry типа large-contentful-paint, идентифицирующий самый большой контентный элемент, как только отрисовывается первый кадр. Но затем, после рендеринга следующих кадров, он будет отправлять другие PerformanceEntry каждый раз, когда изменяется самый большой содержательный элемент.

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

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

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

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

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

До Chrome 88 удаленные элементы не считались элементами с наибольшим содержимым, и их удаление приводило к отправке новой записи largest-contentful-paint. Однако из-за популярных шаблонов пользовательского интерфейса, например карусели изображений, которые часто удаляют DOM-элементы, метрика была обновлена, чтобы точнее отражать то, что испытывают пользователи.

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

Для анализа вы должны сообщать в службу аналитики только последний отправленный PerformanceEntry элемент.

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

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

По соображениям безопасности метка времени рендеринга изображений не отображается для изображений из разных источников, у которых отсутствует заголовок Timing-Allow-Origin. Вместо этого отображается только время их загрузки (поскольку оно уже доступно через многие другие веб-API).

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

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

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

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

Примеры

Вот несколько примеров, как Largest Contentful Paint происходит на нескольких популярных веб-сайтах:

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

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

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

В первом кадре временной шкалы Instagram можно заметить, что вокруг логотипа камеры нет зеленой рамки. Это потому, что он – элемент <svg>, а <svg>-элементы в настоящее время не считаются кандидатами LCP. Первый кандидат LCP – это текст появляется во втором кадре.

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

В полевых условиях

В лабораторных условиях

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

Чтобы измерить LCP в JavaScript, можно воспользоваться API Largest Contentful Paint API. В следующем примере показано, как создать PerformanceObserver, который прослушивает записи largest-contentful-paint и возвращает их в консоль.

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('LCP кандидат:', entry.startTime, entry);
  }
}).observe({type: 'largest-contentful-paint', buffered: true});

Этот код показывает только, как записывать в консоль записи с самым большим содержимым, но само измерение LCP в JavaScript сложнее. Ниже будет рассмотрено, как:

В приведенном выше примере каждая зарегистрированная запись largest-contentful-paint представляет текущего кандидата LCP. Как правило, значение startTime последней отправленной записи является значением LCP, однако это не всегда так. Не все записи largest-contentful-paint подходят для измерения LCP.

Здесь перечислены различия между тем, что сообщает API, и тем, как рассчитывается метрика.

  • API будет отправлять записи с самым большим содержимым largest-contentful-paint для страниц, загруженных на фоновой вкладке, но при вычислении LCP такие страницы следует игнорировать.
  • API продолжит отправку записей largest-contentful-paint после того, как страница перестает быть фоновой, но эти записи следует игнорировать при вычислении LCP (элементы могут учитываться только в том случае, если страница все время была на переднем плане).
  • API не сообщает о записях с самым большим содержимым, когда страница восстанавливается из кэша назад/вперед, но в таких случаях следует измерять LCP, поскольку пользователи воспринимают это как отдельные посещения страницы.
  • API не учитывает элементы iframe, но для правильного измерения LCP вы должны их учитывать. iframe могут использовать API, чтобы сообщать о своих записях largest-contentful-paint в родительское окно для агрегирования.

Вместо того, чтобы запоминать все эти тонкости и различия, разработчики могут использовать JavaScript-библиотеку web-vitals для измерения LCP, которая, где это возможно, обрабатывает такие случаи:

import {getLCP} from 'web-vitals';

// Измерение и логирование LCP по возможности.
getLCP(console.log);

В некоторых случаях (например, в cross-origin iframe) невозможно измерить LCP в JavaScript. Подробности в разделе ограничений библиотеки web-vitals.

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

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

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

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

  • Медленное время ответа сервера
  • Блокирующие рендеринг JavaScript и CSS
  • Время загрузки ресурса
  • Клиентский рендеринг

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