Fan-Expand Card Carousel — HTML CSS JS Snippet

Fan-Expand Card Carousel · Carousels · Plain HTML, CSS & JS · Live preview

What's included

Features

Position derived entirely from a running total of preceding card widths — never hardcoded coordinates
Opening a card widens it and compresses its neighbors, a genuine fan motion rather than a slide
Responsive by computing a scale factor from real container width, no media queries needed
Recalculates automatically on window resize, keeping the fan pixel-perfect at any size
z-index assigned by distance from the open card so it always renders on top of its neighbors
Any card is directly clickable to become the new open one — no separate next/prev controls needed

About this UI Snippet

Fan-Expand Card Carousel — Width, Not Position, Does the Work

Screenshot of the Fan-Expand Card Carousel snippet rendered live

Most carousels move cards *sideways*. This one keeps every card's left position derived from the *widths* of everything before it — so opening one card doesn't slide it into view, it makes it physically wider while its neighbors compress to make room, the way a hand of playing cards fans open around the one you pull forward.

Position as a running total of width

layout() walks the cards left to right, keeping a running x offset. Each card is placed at the current x, then x increases by *that card's own width* — openW for the active one, collapsedW for every other. Because position is derived from width rather than the two being set independently, a card can never overlap its neighbor or leave a gap: the math guarantees a perfect edge-to-edge fan every time, at any open index.

Responsive without a media query

Rather than hardcoding breakpoints, layout() computes a scale factor from the wrapper's *actual* rendered width divided by the fan's natural total width, and multiplies every card's width by it. The fan always fits its container exactly, on any screen size, without a single @media rule — and it re-runs on resize so it stays exact if the container itself changes size.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain why layout() computes every card's left position from a running total of the widths before it, rather than each card knowing its own position independently — and what would break if that running total were replaced with fixed, hardcoded left values per card. It's also worth asking the assistant to convert the clickable divs into real, keyboard-accessible buttons with proper aria-expanded state, or to add a subtle auto-cycle that opens each card in turn on a timer, pausing on user interaction.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a fan-expand card carousel in plain HTML, CSS, and vanilla JavaScript where a stack of narrow cards fans open by widening the clicked card and compressing the others — no library.

Requirements:
- A row of card elements, each with a fixed collapsed width, all positioned absolutely inside a relatively-positioned wrapper.
- A single layout function that computes every card's horizontal position by walking through the cards in order and accumulating a running total of the widths of all preceding cards — the currently "open" card uses a wider width constant in this running total, every other card uses the narrow collapsed width constant. No card's position may be hardcoded independently of this running total.
- Clicking any card must set it as the new "open" card and re-run the layout function, causing it to animate to its wider width while every other card animates back to (or stays at) the narrow collapsed width, with all position changes flowing automatically from the updated running total.
- The open card's extra width must visually push its later neighbors to the right in the same animation, and the open card must render above its neighbors via z-index.
- The whole fan must be responsive without using media queries: compute a scale factor from the wrapper's actual current rendered width divided by the fan's natural (unscaled) total width, and multiply both the collapsed and open width constants by that scale factor every time the layout function runs, including on window resize.
- The open card must reveal additional content (e.g. a description paragraph) that stays hidden (via opacity) while that card is collapsed.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

<div class="fec-wrap" id="fecWrap">
  <div class="fec-card" data-i="0" style="background:linear-gradient(160deg,#6366f1,#4338ca)"><span class="fec-icon">🎧</span><h3>Audio</h3><p>Studio-grade headphones with active noise cancelling.</p></div>
  <div class="fec-card" data-i="1" style="background:linear-gradient(160deg,#ec4899,#9d174d)"><span class="fec-icon">📷</span><h3>Photo</h3><p>Full-frame mirrorless with a 45MP stacked sensor.</p></div>
  <div class="fec-card" data-i="2" style="background:linear-gradient(160deg,#0ea5e9,#0369a1)"><span class="fec-icon">⌚</span><h3>Wear</h3><p>Always-on display with a week of real battery life.</p></div>
  <div class="fec-card" data-i="3" style="background:linear-gradient(160deg,#10b981,#047857)"><span class="fec-icon">🎮</span><h3>Play</h3><p>4K/120fps console with instant resume across titles.</p></div>
  <div class="fec-card" data-i="4" style="background:linear-gradient(160deg,#f59e0b,#b45309)"><span class="fec-icon">💻</span><h3>Work</h3><p>All-day laptop battery with a fanless silent chassis.</p></div>
</div>

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSFive narrow cards appear side by side, the first one already open and showing its description.
  2. 2
    Click any collapsed cardIt widens smoothly while the others compress to make room — a real fan-open motion.
  3. 3
    Click the open card's neighborThe fan re-centers on the new card, closing the previous one back to its narrow width.
  4. 4
    Resize the windowThe whole fan rescales to keep fitting its container, with no layout break.
  5. 5
    Add a sixth cardAdd one more .fec-card — the width math adapts automatically to fit six cards instead of five.

Real-world uses

Common Use Cases

Feature or service overviews
Let a visitor open exactly the feature they care about while glancing at the icons of the rest.
Category browsers
A compact way to preview several product categories with one expanded for detail at a time.
Team or department showcases
Fan out team members or departments, opening one to read a short bio.
Portfolio project previews
Show several projects as narrow labeled strips, opening one for a description and thumbnail.

Got questions?

Frequently Asked Questions

Change the initial value of the openIndex variable at the top of the JS (zero-based) before layout() first runs.

Change the collapsedW and openW constants (in pixels) — layout() derives everything else, including the responsive scale factor, from those two values.

Yes — each card is a real clickable element, so tapping works identically to clicking. No drag gesture is required to open a card.

Yes — swap left/width for top/height in both the CSS and the layout() function, and switch the wrapper to a fixed width with a computed height instead.

Each card is a clickable element — for full accessibility, change them to real <button> elements (or add role="button" and tabindex="0" with an Enter/Space key handler) and add aria-expanded reflecting each card's open state.