Definition
This is a technique for a horizontal carousel with many images, used when fetching every off-screen slide image at once slows down the first paint. Carousel viewport image deferral means that, in a horizontal slider, for slides not currently in the viewport (the region actually visible on screen right now), the <img> (or image component) is not attached to the DOM (not mounted) at all, leaving only a fixed-height placeholder (an empty box that reserves the space). The first visible slide (usually the LCP = largest contentful element candidate) keeps eager (loaded immediately without deferral) and high priority (high download priority).
Why it matters
The thumbnail of the first carousel card is often the page's largest content (LCP) element. But if you attach an image for every slide, the browser and the preload scanner (a mechanism that scans the document before render to discover resources to fetch ahead of time) request several large images simultaneously, increasing total transfer size and the main thread's image-decoding burden — and the arrival of the truly important first image gets delayed. loading="lazy" (an attribute that defers loading until an element is near the viewport) alone can still leave priority contention because, once an <img> is already in the DOM, the browser discovers it. So it is more reliable to conditionally not mount off-screen slides at all.
How it works
- Derive the in-view index from a carousel library (Embla, Swiper, etc.) or an
IntersectionObserver. - Render the Image component only when
shouldLoad = inViewSet.has(index). - The outer wrapper has a fixed height — it preserves layout even when the image is absent (preventing pop-in CLS).
- index 0 (first visible):
fetchPriority="high",loading="eager".
| Slide | Image mount | Priority |
|---|---|---|
| First visible | Yes | high |
| Scrolled into view | Yes | lazy/auto |
| Out of view | No (placeholder) | — |
Practical application
Embla example: update state with emblaApi.slidesInView() + the slidesInView event.
Verification: check Network transfer before/after, and confirm via a trace that the LCP element is still the first thumbnail.
Trade-offs
| Choice | Benefit | Cost |
|---|---|---|
| slidesInView defer | Transfer·decode ↓ | placeholder→image pop-in on scroll |
| all lazy | Simple to implement | mount·discover cost remains |
| all eager | Fast scroll preview | Worse LCP·bandwidth |
To reduce pop-in, the placeholder and the image must share the same aspect box (absolute inset-0).
When not to use it
- Only 1–2 slides (negligible benefit).
- All slides are visible simultaneously on a narrow viewport.
- Thumbnails are already very small and total transfer is negligible.
Common mistakes
- Applying only lazy while still mounting Image nodes off-viewport.
- Putting
priorityon every card — only one LCP candidate should be high. - Deferring without a placeholder height → CLS on scroll.
Related concepts
- largest-contentful-paint — identifying the LCP candidate
- resource-priority — scope of fetchpriority·preload
- cls-skeleton-layout-reservation — the placeholder box model