webdevpuneet.com

Caption Crossfade Carousel — HTML CSS JS Snippet

Caption Crossfade Carousel · Carousels · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<div class="ccc-wrap" id="cccWrap">
  <div class="ccc-image" id="cccImage"></div>
  <div class="ccc-caption">
    <h2 id="cccTitle"></h2>
    <p id="cccText"></p>
  </div>
  <div class="ccc-dots" id="cccDots"></div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Background and caption crossfade on genuinely independent transitions, not one shared opacity change
Caption text is swapped only while fully invisible — no jump-cut mid-fade
requestAnimationFrame forces a real paint of the hidden state before the fade-back-in begins
Heading and description have staggered transition delays for a more deliberate, less mechanical entrance
Autoplay via setInterval that cleanly resets on any manual navigation, dot or keyboard
Fully data-driven slide content from one array — no duplicated markup per slide

About this UI Snippet

Caption Crossfade Carousel — Two Independently-Timed Fades, Not One

Screenshot of the Caption Crossfade Carousel snippet rendered live

A naive crossfade carousel just swaps everything — image and text — at the same instant behind one opacity transition, which makes the caption feel like it's cutting rather than fading. This snippet treats the background image and the caption as *two separate transitions on two separate clocks*: the background crossfades via a plain CSS background transition, while the caption is explicitly hidden, has its text content swapped while fully invisible, and is only then faded back in — its heading and paragraph carrying their own staggered transition-delay values so the title settles slightly before the description does.

Why the text swap happens inside a requestAnimationFrame, not immediately

Removing .ccc-show (starting the caption's fade-out) and changing textContent in the very same synchronous line would mean the browser never actually paints the "faded out" state before the new text appears — the fade-out transition would have nothing to visibly transition from. Wrapping the text swap in requestAnimationFrame forces a real paint of the hidden state first, so the *subsequent* fade back in is genuinely animating from invisible-with-new-text, not skipping straight to visible.

Autoplay that resets cleanly on manual interaction

A setInterval drives automatic advancing, but every manual navigation — a dot click or an arrow key — calls resetTimer(), which clears and re-creates that interval. That's what stops a slow reader's manual click from being immediately overridden by an autoplay tick that was already halfway through its countdown before they interacted.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA hero appears with its background and caption both fading into view.
  2. 2
    Wait for autoplayEvery 4.5 seconds, the background crossfades while the caption independently fades out, changes, and fades back in.
  3. 3
    Click a dotJump directly to that slide — the autoplay timer resets so it doesn't interrupt too soon afterward.
  4. 4
    Use arrow keysLeft/Right navigate manually, also resetting the autoplay timer.
  5. 5
    Watch the stagger closelyNotice the heading finishes fading in slightly before the description — a deliberate delay offset, not a coincidence.

Real-world uses

Common Use Cases

🎯
Marketing hero carousels
Give a hero a more polished feel, where the background fades on its own timer while the caption fades out, swaps while invisible and fades back in.
📰
Editorial rotators
Use staggered caption entrances for magazine-style editorial features, with heading and description on separate transition delays for a deliberate feel.
🖼️
Portfolio hero banners
Showcase several projects, with requestAnimationFrame forcing a real paint of the hidden state before the fade back in.
📱
App feature banners
Rotate feature headlines with captions that never jump-cut mid-fade, since text is only swapped while fully invisible.
🎓
Two-transition teaching
Study why independent staggered transitions feel more deliberate than one shared opacity change applied to image and text together.

Got questions?

Frequently Asked Questions

Removing the visible class and changing textContent in the same synchronous step would mean the browser batches both changes into one paint — there's no visible "faded out" moment for the fade-back-in to animate from. Deferring the text change to the next animation frame forces the hidden state to actually render first.

Change the 4500 (milliseconds) passed to setInterval in two places — the initial timer creation and inside resetTimer, which must both use the same value to stay consistent.

The transition-delay values in the CSS (.15s for the heading, .28s for the paragraph) control how much later each element starts its fade-in relative to when .ccc-show is added — increase the gap between them for a more pronounced stagger.

Without resetTimer(), a manual navigation could be immediately followed by an autoplay tick that was already most of the way through its own countdown — resetting gives a full autoplay interval after every manual interaction, so a reader always gets a fair amount of time before the next automatic change.

Dots are real labeled buttons and the carousel is fully operable via Left/Right arrow keys; add prefers-reduced-motion handling to shorten or remove the fade transitions, and consider pausing autoplay entirely for users who've requested reduced motion.