v146 · Performance · Candidate Rules

Candidate Rules

The specification rules for what qualifies as an LCP candidate, which conditions Chrome 146 now correctly enforces, and how to interpret LargestContentfulPaint entries.

element type eligibility

Element type LCP candidate Notes
<img> Yes Must be visible, non-zero dimensions, within viewport
<image> in SVG Yes SVG images treated same as <img>
<video> poster Yes Poster image evaluated, not the video frame itself
Block-level text (headings, paragraphs) Yes Entire block's text rendering area is measured
Background images (background-image: url()) Yes Only when the element is in the viewport and visible
<input>, <button> No Form elements are excluded by the spec
<iframe> No Cross-origin frames are excluded

Chrome 146 fixes — previously incorrect behavior

Scenario Pre-Chrome 146 Chrome 146 (spec-compliant)
Image with 0×0 dimensions Incorrectly included as candidate Fixed — excluded (size = 0)
Element with opacity: 0 Incorrectly included Fixed — excluded (not visible)
Element entirely outside viewport Incorrectly included Fixed — excluded (not in viewport)
Element with visibility: hidden Incorrectly included Fixed — excluded (not painted)

size computation

// LCP entry.size is computed as:
// min(intrinsic_size, viewport_intersection_area)
//
// For images:
//   intrinsic_size = image's natural width × natural height
//   (NOT the rendered size — this is spec-defined)
//
// For text blocks:
//   size = text bounding box area
//   (the area of the rendered text, not the element's box)
//
// If size === 0, the element is not emitted as a candidate.
// Chrome 146 enforces this — previously a 0-size element could
// still appear as a candidate.

observer.observe({ type: 'largest-contentful-paint', buffered: true });
// entry.size gives the computed size in square pixels
// entry.element.getBoundingClientRect().width × height
// may differ — use entry.size for the LCP metric

see also

scenario focus

Select a scenario to focus its rendered example and summary.