{"post":{"slug":"how-to-lazy-load-images-2026","title":"How to lazy load images in 2026","excerpt":"Native browser lazy loading covers most cases today, but getting LCP right still requires knowing when NOT to lazy-load and how to size images properly.","category":"code","date":"March 31, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">L</span>azy loading images is one of the highest-ROI performance changes you can make on a content-heavy website. Done right it cuts initial page weight by 50–80% on image-rich pages. Done wrong — especially on the LCP element — it tanks your Core Web Vitals score in a way that is hard to diagnose.\n\n## What changed in 2026\n\n- **Native `loading=\"lazy\"` is baseline everywhere** — all modern browsers and the entire iOS/Android installed base support it. There is no longer a reason to ship an IntersectionObserver polyfill for this.\n- **`fetchpriority` is supported across all major browsers** — use it on your hero image to get a measurable LCP improvement.\n- **Next.js `<Image>` is the template** for framework-level image optimization — automatic WebP/AVIF conversion, responsive `srcset`, and built-in lazy loading.\n- **INP replaced FID** in Core Web Vitals — images affect INP indirectly through layout shift and main-thread blocking; AVIF cuts both.\n\n## The basic pattern (plain HTML)\n\n```html\n<!-- Above the fold — do NOT lazy load, add high priority -->\n<img\n  src=\"/hero.jpg\"\n  alt=\"Hero image\"\n  width=\"1200\"\n  height=\"630\"\n  fetchpriority=\"high\"\n/>\n\n<!-- Below the fold — lazy load -->\n<img\n  src=\"/product.jpg\"\n  alt=\"Product photo\"\n  width=\"400\"\n  height=\"300\"\n  loading=\"lazy\"\n/>\n```\n\nTwo attributes carry all the weight:\n- `loading=\"lazy\"` — defers the request until the image is near the viewport.\n- `width` and `height` — reserve space so layout does not shift when the image loads.\n\n## Responsive images with srcset\n\n```html\n<img\n  src=\"/photo-800.jpg\"\n  srcset=\"\n    /photo-400.jpg  400w,\n    /photo-800.jpg  800w,\n    /photo-1600.jpg 1600w\n  \"\n  sizes=\"(max-width: 600px) 100vw, 50vw\"\n  alt=\"Team photo\"\n  width=\"800\"\n  height=\"533\"\n  loading=\"lazy\"\n/>\n```\n\n`srcset` + `sizes` lets the browser pick the right resolution for the device. Without it you are sending a 1600px image to a 375px phone.\n\n## Next.js Image component\n\n```tsx\nimport Image from \"next/image\";\n\n// Hero image — no lazy loading, high priority\nexport function Hero() {\n  return (\n    <Image\n      src=\"/hero.jpg\"\n      alt=\"Hero\"\n      width={1200}\n      height={630}\n      priority          // equivalent to fetchpriority=\"high\" + no lazy\n    />\n  );\n}\n\n// Product card — lazy load\nexport function ProductCard({ src, name }: { src: string; name: string }) {\n  return (\n    <Image\n      src={src}\n      alt={name}\n      width={400}\n      height={300}\n      // lazy is the default; no extra prop needed\n    />\n  );\n}\n```\n\nNext.js `<Image>` automatically:\n- Converts to WebP/AVIF\n- Generates a responsive `srcset`\n- Adds `loading=\"lazy\"` by default (use `priority` to override)\n- Prevents CLS with the correct aspect ratio\n\n## React without Next.js\n\n```tsx\ninterface LazyImgProps {\n  src: string;\n  alt: string;\n  width: number;\n  height: number;\n}\n\nexport function LazyImg({ src, alt, width, height }: LazyImgProps) {\n  return (\n    <img\n      src={src}\n      alt={alt}\n      width={width}\n      height={height}\n      loading=\"lazy\"\n      decoding=\"async\"\n    />\n  );\n}\n```\n\n`decoding=\"async\"` tells the browser it can decode the image off the main thread — a small but free win.\n\n## When NOT to lazy-load\n\n| Image | Should lazy-load? | Reason |\n| --- | --- | --- |\n| Hero / banner at top of page | No | It is usually the LCP element |\n| First visible product image | No | Above the fold |\n| Images in carousels (all slides) | No (first), Yes (rest) | First slide is visible |\n| Thumbnails in a long grid | Yes | Below the fold |\n| Blog post body images | Yes | Reader scrolls to them |\n| Open Graph / og:image | N/A | Not rendered in browser |\n\n## How to find your LCP image\n\n```bash\n# In Chrome DevTools > Performance tab, look for \"LCP\" in the timeline.\n# Or use Lighthouse:\nnpx lighthouse https://yoursite.com --only-categories=performance\n```\n\nThe LCP image is reported in the \"Largest Contentful Paint\" section. Verify it does **not** have `loading=\"lazy\"` and **does** have `fetchpriority=\"high\"`.\n\n## Common mistakes\n\n**Lazy-loading the LCP image.** This is the most common image performance mistake in 2026. The browser needs to load the LCP image as fast as possible; `loading=\"lazy\"` tells it to wait. Result: LCP score drops, Core Web Vitals fail.\n\n**Missing width and height.** Without explicit dimensions the browser does not know the aspect ratio until the image loads, causing a layout shift (high CLS). Always set them.\n\n**Using a JavaScript lazy loader when you do not need to.** Every IntersectionObserver-based library adds JS parse time and a dependency. Native `loading=\"lazy\"` is zero-JS and supported everywhere.\n\n**Not serving modern formats.** A JPEG is typically 2–3× larger than the equivalent AVIF. Use Next.js `<Image>` or a CDN image transform (Cloudflare Images, Imgix) to serve AVIF automatically.\n\n## What to skip\n\n- **Blur-up placeholders for every image** — they add JS complexity; use them only for images above the fold where CLS matters.\n- **`loading=\"eager\"` on below-the-fold images** — this is the default before 2020; it is now the wrong default.\n- **Third-party lazy-load scripts** for new projects — native is better.\n\n## FAQ\n\n**Does `loading=\"lazy\"` affect SEO?**\nNo. Google's crawler renders JavaScript and loads lazy images before indexing. Lazy loading does not hide images from search engines.\n\n**How far from the viewport does the browser start loading a lazy image?**\nIt varies by browser and connection speed — roughly 1 000–2 000 px below the viewport on fast connections, closer on slow ones. This is intentional to avoid visible loading.\n\n**Should I lazy-load background images set with CSS?**\nNative `loading=\"lazy\"` only applies to `<img>` tags. For CSS background images you still need JavaScript (`IntersectionObserver`) or a content-visibility trick.\n\n**What is the difference between loading=\"lazy\" and decoding=\"async\"?**\n`loading=\"lazy\"` delays the network request. `decoding=\"async\"` allows the decode to happen off the main thread after the image has downloaded. Use both together for below-the-fold images.\n\n## Where to go next\n\n- [How to optimize React performance in 2026](/blog/how-to-optimize-react-performance-2026)\n- [How to debounce a function in 2026](/blog/how-to-debounce-a-function-2026)\n- [How to throttle requests in 2026](/blog/how-to-throttle-requests-2026)","hue":317,"metaTitle":"How to Lazy Load Images in 2026: Native, Next.js, React","metaDescription":"Complete guide to lazy loading images in 2026. Covers native loading=\"lazy\", fetchpriority, Next.js Image, and avoiding LCP regressions.","keywords":["how to lazy load images 2026","html lazy loading images","loading lazy attribute","next.js image optimization 2026","lcp image optimization","fetchpriority high image","core web vitals images 2026","react lazy image loading","image cls layout shift","web performance images 2026"],"tldr":["**Use loading=\"lazy\" for below-the-fold images** — it is native, zero-JS, and supported in every major browser since 2020.","**Never lazy-load your LCP image** — the Largest Contentful Paint element needs to load as fast as possible; lazy-loading it kills your Core Web Vitals score.","**Add explicit width and height to every image** — it prevents layout shift (CLS) even with lazy loading.","**Use fetchpriority=\"high\" on your hero image** — it hints the browser to prioritize it over other resources in the head.","**Skip:** JavaScript-based IntersectionObserver lazy loading for new projects — native loading=\"lazy\" is faster and needs no JS."],"readTime":"4 min read","wordCount":950},"related":[{"slug":"how-to-optimize-images-for-web-2026","title":"How to optimize images for the web in 2026","excerpt":"Images are still the biggest source of web performance waste in 2026. This guide covers modern formats, responsive sizing, lazy loading, and tooling that makes optimization automatic.","category":"code","date":"February 25, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":319},{"slug":"how-to-speed-up-your-website-2026","title":"How to speed up your website in 2026: Core Web Vitals and beyond","excerpt":"A slow website loses visitors, conversions, and search ranking. Here are the highest-impact techniques to cut load time and pass Core Web Vitals in 2026.","category":"code","date":"April 3, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":317},{"slug":"what-is-lazy-loading-2026","title":"What Is Lazy Loading in 2026? A Practical Guide","excerpt":"Lazy loading defers loading anything, an image, a route, a script, until it is actually needed. Here is the general pattern behind it in 2026, and where it does not belong.","category":"code","date":"July 23, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":320}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"how-to-jump-start-a-car-2026","title":"How to jump-start a car in 2026: cables, jump packs, and what not to do","excerpt":"A dead car battery is one of the most common vehicle failures and one of the easiest to handle. Here is the 2026 guide to jump-starting with cables or a portable jump pack safely.","category":"guides","date":"March 31, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":295},"older":{"slug":"how-to-learn-anything-faster-2026","title":"How to learn anything faster in 2026: the science-backed system that works","excerpt":"Learning speed is not a fixed trait — it is a function of method. Here are the 2026 techniques, backed by cognitive science, that cut learning time in half.","category":"guides","date":"March 31, 2026","author":"ByteLedger Team","readTime":"6 min read","hue":115}}