When a webpage has 30–50 images, loading all of them at page open is a serious waste: users wait for dozens of images they haven't scrolled to yet. Lazy loading solves this by loading images only when they're about to enter the user's viewport. It's one of the highest-impact improvements for Core Web Vitals performance.
Google data shows lazy loading reduces initial data transfer by 30–60% for image-heavy pages, directly improving LCP (Largest Contentful Paint) — the most important Core Web Vitals metric for SEO.
Native Lazy Loading: The Simplest Approach
Since 2019, all modern browsers support native lazy loading with just a single HTML attribute. This is the fastest implementation with zero JavaScript required:
- ▸<img loading="lazy" src="..." alt="..."> — browser handles everything automatically
- ▸Supported by: Chrome 77+, Firefox 75+, Safari 15.4+, Edge 79+ (>95% of global users)
- ▸Combine with width and height attributes to prevent layout shift (CLS)
- ▸Do NOT apply to hero/above-the-fold images — these must load immediately
IMPORTANT: Never use loading="lazy" on the hero banner or the first 1–2 content images. These are above-the-fold and must load immediately to avoid penalizing your LCP score.
Which Images Should Be Lazy Loaded?
- ▸DO lazy load: In-article images, below-fold product images, galleries, footer images
- ▸DON'T lazy load: Hero banners, logos, OG images, any image in the first 600px of the page
- ▸OPTIONAL: Product thumbnails in listings — lazy load for long lists, eager load for 6–8 items
Advanced Lazy Loading: Intersection Observer API
With frameworks like React, Vue, or Next.js, you can implement custom lazy loading with the Intersection Observer API — giving you fine-grained control: preload threshold (start loading N pixels before the image enters viewport), loading animation (fade/blur-to-sharp transitions), and progressive loading (show placeholder first, then swap in high-quality image).
Placeholder Techniques: Preventing Layout Shift (CLS)
CLS occurs when images finishing loading push down content below — frustrating users and hurting Core Web Vitals. Solution: always declare width and height on img tags, or use CSS aspect-ratio to reserve space before loading. The LQIP (Low Quality Image Placeholder) technique shows a blurred version while the full image loads.
- ▸Always set width and height on <img> tags — browser calculates aspect ratio automatically
- ▸CSS: aspect-ratio: 16/9 for landscape, 4/3 for product images
- ▸LQIP: Generate 20×20px placeholder images (only a few bytes), blur with CSS filter
- ▸Skeleton placeholders: Animated gray frames while images are loading
Lazy Loading in WordPress, Next.js, and Shopify
WordPress / WooCommerce
WordPress 5.5+ automatically adds loading="lazy" to all content images. Verify by inspecting HTML for the loading attribute. If your theme overrides this behavior, add the filter: add_filter("wp_lazy_loading_enabled", "__return_true").
Next.js
Next.js <Image> component lazy loads all images by default and auto-optimizes size and format. Use priority={true} for hero images to disable lazy loading and prioritize early loading.
Shopify
Modern Shopify themes (Dawn and OS 2.0) have native lazy loading enabled by default. Verify with Google PageSpeed Insights — if "defer offscreen images" warnings still appear, manually add loading="lazy" in theme.liquid.