Lazyloading in 2025: Load light or load wrong?
Lazyloading has become second nature, but when poorly implemented, it hurts SEO, breaks accessibility, and kills user experience. In 2025, should we still use <noscript>? Should everything be lazyloaded by default? And what about videos? Here’s a clear breakdown, with real examples and common pitfalls to avoid.
It’s 2025. JavaScript powers entire apps, Core Web Vitals still drive SEO requirements, and web accessibility is legally enforced thanks to the European Accessibility Act.
Lazyloading isn’t just a "nice performance trick" anymore, it’s a key lever for performance, SEO, and inclusion. In short: mess it up, and your page falls flat.
So let’s break it down and clear up the confusion.
JavaScript Lazyloading
The Classic JS Pattern (IntersectionObserver) htmlCopierModifier
<img
src="blank.png"
data-src="photo.jpg"
alt="Illustrative image"
class="lazy"
width="600"
height="400"
/>
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.add('loaded');
observer.unobserve(img);
}
});
});
document.querySelectorAll('img.lazy').forEach(img => observer.observe(img));
This approach is flexible — it works on any element (<video>, <iframe>, etc.).
But without HTML fallbacks, the image is invisible to:
- Browsers without JS (yes, they still exist)
- Screen readers expecting an img[src] in the initial DOM
- Google, if rendering is too dynamic or slow
Lazyload indexing in JavaScript
When you lazyload content with JavaScript, it may not be visible to search engines or browsers without JS. In this case, you use the <noscript>
tag. It is essential whenever a visual element is injected or modified via JavaScript.
Example:
<img data-src="photo.jpg" alt="Illustrative image" class="lazy" width="600" height="400" />
<noscript>
<img src="photo.jpg" alt="Illustrative image" width="600" height="400" />
</noscript>
And to ensure correct display with JS disabled:
<noscript>
<style>
.lazy { display: none; }
</style>
</noscript>
This ensures:
- Google can index content immediately
- Screen readers get a proper, accessible image
- The page remains readable even without JS
If you’re using native lazyloading, though, <noscript>
becomes redundant. We’ll get to that...
Native Lazyloading: loading="lazy"
For a few years now, all modern browsers support the loading="lazy"
attribute on images, and iframes too.
<img
src="photo.jpg"
alt="Illustrative image"
loading="lazy"
width="600"
height="400"
/>
<iframe
src="https://www.youtube.com/embed/abc123"
loading="lazy"
width="560"
height="315"
></iframe>
Pros:
- SEO-friendly: Google sees it all — no need for
<noscript>
or JavaScript - Accessible by default (as long as
alt
and dimensions are set) - Fully supported by modern browsers
Cons:
- Not yet supported on
<video>
(at least, not standardized)
What About Videos? Clean Lazyloading in 2025
Native lazyloading for videos isn't standardized yet. But Google offers a clear method in their guide on video lazyloading: use preload="none"
and a poster
.
Example:
<video
controls
preload="none"
poster="poster.jpg"
width="640"
height="360"
>
<source src="video.webm" type="video/webm">
<source src="video.mp4" type="video/mp4">
</video>
This prevents the browser from preloading the entire video. The poster acts as a lightweight placeholder, and it might even count as your LCP image.
Preload Images Above the Fold!
Images that are visible on initial page load should not be lazyloaded. Instead, they deserve explicit loading priority to avoid being delayed by other resources.
Use <link rel="preload">
for above-the-fold visuals or poster images:
<link rel="preload" href="image.jpg" as="image" fetchpriority="high">
Anything not lazyloaded, but critical for the initial render (LCP, hero image, logo, etc.), should be preloaded.
Bonus: Animate Image Load
HTML
<img
src="photo.jpg"
alt="Illustrative image"
loading="lazy"
width="600"
height="400"
/>
CSS
img[loading="lazy"] {
opacity: 0;
transition: opacity 300ms ease;
}
img[loading="lazy"].loaded {
opacity: 1;
}
JavaScript
document.querySelectorAll('img[loading="lazy"]').forEach(img => {
if (img.complete) {
img.classList.add('loaded');
} else {
img.addEventListener('load', () => {
img.classList.add('loaded');
});
}
});
Fallback <noscript>
<noscript>
<style>
img[loading="lazy"] {
opacity: 1 !important;
}
</style>
</noscript>
Result: a smooth fade-in effect when JS is enabled, and instant visibility when it’s not.
TL;DR: Lazyloading Best Practices for 2025
- Lazyload via JS? Use
<noscript>
for SEO & accessibility - Using
loading="lazy"
? No<noscript>
needed, it's native - Never lazyload above-the-fold images
- Use
<link rel="preload">
withfetchpriority="high"
for above-the-fold content - Always define
width
andheight
to prevent layout shifts (CLS) - Set meaningful
alt
text (not generated on the fly) - For videos (no autoplay): use
preload="none"
+ poster