Image lazy loading implemented for below-fold content
Why it matters
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.
Severity rationale
Medium because loading below-fold images eagerly wastes bandwidth and delays initial render, with measurable impact on mobile users and slow connections.
Remediation
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.
Detection
-
ID:
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 useloading="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} />
External references
- iso-25010:2011 · performance-efficiency.time-behaviour — Time Behaviour
Taxons
History
- 2026-04-18·v1.0.0·Initial import from performance-core·automated