squirrelscan
GitHub

Hidden carousel slides still download: eager images inside

Images in inactive carousel slides loaded eagerly, so the browser fetches them anyway. squirrel walks up eight ancestors to find them.

Why a hidden slide still downloads

display: none and aria-hidden change what is painted and what is announced. Neither stops a fetch. An <img> inside slide four of a carousel is requested as soon as the parser reaches it, competing for bandwidth with the image on slide one that the visitor can see.

loading="lazy" is what defers it. The browser holds the request until the element comes within its loading distance of the viewport, which for an off-screen slide usually means when the slide is shown. The first slide should stay eager, because deferring the visible one delays the paint that matters.

What squirrel checks

The rule runs on every crawled page and emits one check:

  • carousel-hidden-eager: warns with the message N eagerly-loaded image(s) inside hidden carousel slides, listing up to ten src values and recording any further count in the details. Otherwise it passes with No eager images in hidden carousel slides.

An image is flagged only when all of this holds: it is not loading="lazy", it has a src that is not a data: URI, and within eight ancestor levels there is both a carousel container and a hidden element. The carousel signal is a class name matching a known library, meaning swiper, splide, glide__, glide--, slick, flickity, embla__, keen-slider, owl-carousel or tns-, or the whole word carousel or slideshow. Bare slide and slider are deliberately excluded because they match unrelated interface code.

Hidden means aria-hidden="true", a hidden attribute, or an inline style containing display:none or visibility:hidden. A class that hides an element through an external stylesheet is not detected, so the rule only sees the inline case. A page with no parsed document emits nothing at all.

Elements inside <noscript> are skipped: a browser with scripting enabled reads <noscript> content as plain text, so nothing in it loads or renders. See content inside noscript.

How to fix it

<div class="swiper-slide" aria-hidden="true">
  <img src="/slide-4.jpg" loading="lazy" width="1200" height="630" alt="" />
</div>

Add loading="lazy" to every slide except the first. Most carousel libraries have an option that does this for you, which is more reliable than marking them by hand.

The limit worth knowing is a slide hidden by a class rather than an inline style, which this rule cannot see and so does not report. The finding is a floor rather than a total, and there is no common false positive in the other direction.

Rule IDperf/carousel-hidden-eager
CategoryPerformance
ScopePer-page
Severitywarning
Weight4/10

Enable / disable

Disable this rule

[rules]
disable = ["perf/carousel-hidden-eager"]

Disable all Performance rules

[rules]
disable = ["perf/*"]

Enable only this rule

[rules]
enable = ["perf/carousel-hidden-eager"]

enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.

Performance findings ship in every audit next to the SEO, security and agent experience rules. See Core Web Vitals for how an agent works through a report.

References

Check your site

Run squirrel audit https://example.com and open the Performance section of the report. Every eager image in a hidden slide is listed by URL. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.

Type to search…

↑↓ navigate↵ openesc close