Auto-Height Carousel — HTML CSS JS Snippet

Auto-Height Carousel · Cards · Plain HTML, CSS & JS · Live preview

What's included

Features

The viewport smoothly animates its height between slides of genuinely different content lengths
Works around CSS's inability to transition to/from "auto" by measuring real pixel heights via JavaScript
Every slide keeps its natural, unclipped height — no fixed slide height forcing scroll or empty space
The very first paint sets height instantly (transition disabled for one frame) to avoid an unwanted pop-in animation
Recalculates on window resize, so height stays accurate if content reflows at a new viewport width
Standard translateX slide transition runs simultaneously with the height animation for a cohesive motion

About this UI Snippet

Auto-Height Carousel — Measuring Content to Animate a Property CSS Can't Animate

Screenshot of the Auto-Height Carousel snippet rendered live

CSS cannot transition height to or from auto — it's one of the oldest, most persistent limitations in the language. This carousel works around it by never using auto for the animated value at all: on every slide change, JavaScript measures the *new* active slide's real, natural height in pixels with getBoundingClientRect(), and sets that literal pixel value on the viewport. Because the viewport's height is a CSS transition-able property, animating *between two known pixel numbers* works perfectly — the trick is entirely in how that target number gets produced.

Measuring the slide, not the viewport

Each .ahc-slide sits in a flex track sized at 100% width each, so all three slides' natural heights already exist in the DOM regardless of which one is "active" — measureAndSetHeight() just reads getBoundingClientRect().height off whichever slide index is currently current. That's the one measurement this entire pattern depends on: a slide's true rendered height, taken fresh every time the active index changes.

Skipping the transition on the very first paint

If the viewport's height transition were active from the start, the browser would animate from its default (auto-derived, effectively 0 before any height is set) up to the first slide's real height — a visible pop on page load. Setting transition: none before the first render() call, then clearing it back on the next animation frame, sidesteps that: the first height is applied instantly, and only subsequent slide changes animate.

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 exactly why CSS cannot animate a height transition to or from auto, and how measuring a slide's real pixel height with getBoundingClientRect and applying it explicitly sidesteps that limitation entirely. It's also worth asking the assistant to add a ResizeObserver on the active slide so the height stays correct even if that slide's content changes dynamically after the initial render (e.g. an image loading late), instead of only re-measuring on navigation and window resize.

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 carousel in plain HTML, CSS, and vanilla JavaScript whose container smoothly animates its height to match each slide's actual content height, given that slides contain meaningfully different amounts of content — no library.

Requirements:
- A viewport container with overflow hidden wrapping a horizontally sliding track of full-width slide elements, where each slide contains a different, realistic amount of text content (varying enough that their natural heights are noticeably different from each other).
- A function that measures the currently active slide's real rendered height (using an actual DOM measurement API, not an estimate or fixed value) and applies that exact pixel value as the viewport container's height, since CSS cannot animate a height transition to or from the auto keyword — this measurement must be re-run every time the active slide changes.
- The viewport's height change and the track's horizontal slide transition must both be CSS transitions that run smoothly together whenever navigating to a new slide.
- On the very first page render, the initial height must be applied without any visible transition animation (to avoid an unwanted "pop-in" effect from an unset starting height), with the transition only becoming active for subsequent slide navigations.
- The height measurement must be re-run on window resize as well, so the displayed height stays accurate if the content reflows at a different viewport width.
- Previous/next buttons and dynamically generated indicator dots for navigation, plus Left/Right arrow key support.

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="ahc-wrap">
  <div class="ahc-viewport" id="ahcViewport">
    <div class="ahc-track" id="ahcTrack">
      <div class="ahc-slide"><h3>Short FAQ</h3><p>Do you offer refunds? Yes, within 30 days.</p></div>
      <div class="ahc-slide"><h3>A Medium One</h3><p>Our platform supports single sign-on, role-based access control, audit logs, and exports to CSV or JSON for any report you build.</p></div>
      <div class="ahc-slide"><h3>The Long Answer</h3><p>Pricing scales with active seats, not total users — invited members who never log in cost nothing. Annual billing saves 20% versus monthly, and you can switch between plans at any time; unused time on a downgrade is credited to your next invoice automatically, no support ticket required.</p></div>
    </div>
  </div>
  <div class="ahc-controls">
    <button class="ahc-btn" id="ahcPrev" aria-label="Previous">‹</button>
    <div class="ahc-dots" id="ahcDots"></div>
    <button class="ahc-btn" id="ahcNext" aria-label="Next">›</button>
  </div>
</div>

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA short FAQ appears in a card sized to fit it exactly — no extra empty space.
  2. 2
    Click nextThe card smoothly grows taller as it slides to the medium-length answer.
  3. 3
    Click next againIt grows further still for the longest answer — always sized to fit exactly, never clipped or padded.
  4. 4
    Click back to the firstThe card smoothly shrinks back down to the short answer's natural height.
  5. 5
    Add a slide with different content lengthNo height needs to be set manually — measureAndSetHeight reads it automatically.

Real-world uses

Common Use Cases

FAQ or accordion-style carousels
The exact case this snippet models — answers of wildly different lengths, each perfectly fitted.
Multi-step forms with varying field counts
Each step's card resizes to fit exactly the fields it contains, no wasted space on shorter steps.
Testimonial carousels with varying quote lengths
Long, detailed quotes and short one-liners both display in full without a fixed, compromise height.
Onboarding cards with different amounts of copy
Avoid the common onboarding-carousel bug where a fixed height clips a longer step's text.

Got questions?

Frequently Asked Questions

Browsers cannot animate a transition to or from the auto keyword — there's no defined intermediate state between "auto" and a pixel value for the browser to interpolate. Measuring the real height in JavaScript and setting an explicit pixel value is the standard, reliable workaround.

Call measureAndSetHeight() again after that content finishes loading/rendering — it always re-measures the currently active slide's real height, so it stays accurate as long as it's invoked after any layout-affecting change.

Only if the height is measured after the image has actually loaded — an image without explicit width/height attributes can cause a late reflow. Add an aspect-ratio or explicit dimensions to any image, or re-measure on that image's load event.

Without that guard, the viewport would visibly animate from its unset/zero starting height up to the first slide's real height the instant the page loads — a distracting pop-in that has nothing to do with actual carousel navigation.

Arrows and dots are real labeled buttons operable via Left/Right arrow keys — for full accessibility, ensure the animated height change doesn't interfere with a screen reader's ability to read the newly active slide's content, which it won't since content is always present in the DOM, just visually repositioned.