Eager-loading all images transfers bytes the user may never scroll to see (ISO-25010 time-behaviour). A product listing page with eight gallery images below the fold can waste 450 KB on initial load — bytes that delay the LCP image, consume mobile data allowances, and increase time-to-interactive on slow connections. The browser's native loading="lazy" attribute costs one attribute; the performance payoff is the elimination of all below-fold image requests until the images actually enter the viewport.
Medium because loading below-fold images eagerly wastes bandwidth and delays initial render, with measurable impact on mobile users and slow connections.
Mark all below-fold images with loading="lazy". Above-fold images must use loading="eager" (or omit the attribute — eager is the default):
<!-- Above fold: load eagerly -->
<img src="/hero.jpg" alt="Hero" loading="eager" />
<!-- Below fold: defer until near viewport -->
<img src="/product-1.jpg" alt="Product 1" loading="lazy" />
With Next.js, loading="lazy" is the default for next/image; the LCP image needs priority to override it:
// src/app/page.tsx
<Image src="/hero.jpg" alt="Hero" priority width={1200} height={600} />
<Image src="/product.jpg" alt="Product" width={300} height={300} /> {/* lazy by default */}
Do not mark the hero or any above-fold image as loading="lazy" — that delays the LCP element and directly degrades Core Web Vitals.
ID: performance-core.image-media-optimization.lazy-loading
Severity: medium
What to look for: Count all relevant instances and enumerate each. Scan image and iframe elements for loading="lazy" attribute or Intersection Observer patterns. Check whether below-fold images are loaded eagerly (synchronously) or deferred. Look for lazy loading libraries in dependencies (react-lazyload, vanilla-lazyload, etc.) or custom implementations.
Pass criteria: Below-fold images (not in initial viewport) use loading="lazy" attribute natively, or are lazy-loaded via Intersection Observer or a library. At least 1 implementation must be verified. Above-fold images use loading="eager" or omit the attribute (default eager).
Fail criteria: All images load eagerly including those far below fold, or lazy loading is not implemented. Large below-fold images cause unnecessary initial page load delay.
Skip (N/A) when: The project has no images or all images are above the fold on typical viewports.
Detail on fail: Specify the below-fold images. Example: "Product gallery images (8 images, 450KB total) all loaded eagerly. Images 500px below fold start loading immediately instead of on-demand" or "Hero image at 100px marked with loading='lazy' incorrectly; should be eager".
Remediation: Lazy loading defers image loading until the image enters the viewport, reducing initial page load:
Use native loading="lazy":
<img src="product.jpg" alt="Product" loading="lazy" />
Or with Next.js Image:
<Image src="/product.jpg" alt="Product" loading="lazy" width={300} height={300} />
For more control, use Intersection Observer:
const [isVisible, setIsVisible] = useState(false)
const ref = useRef()
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) setIsVisible(true)
})
observer.observe(ref.current)
}, [])
return isVisible ? <img src="..." /> : <div ref={ref} />