What You'll Build

In this tutorial you'll create a CSS-only flexible accordion image card gallery — a horizontal strip of five image cards that each expand smoothly when hovered, compressing the rest to make room. The effect is achieved entirely through CSS Flexbox by manipulating the flex property on the hovered card, driven by a single transition rule using a custom cubic-bezier easing for a buttery-smooth feel.

Beyond the core accordion mechanic, each card also transitions its image from muted grayscale to full color as it expands, scales the image with a subtle zoom, and reveals a sliding description overlay that rises up from the card's bottom edge. A decorative numbered badge sits in the corner of each card, and a centered title badge flips between dark and light styling on hover to reinforce the interaction.

This is a popular pattern for image showcase sections, portfolio galleries, destination sliders, and feature comparisons. It requires no JavaScript libraries, no frameworks, and no build tools — just clean, well-structured HTML and CSS that works in every modern browser.

💡 Who Is This For? This project is perfect for beginners who understand CSS basics and want to explore the power of Flexbox for interactive layouts, and for intermediate developers looking to master CSS transitions, filter animations, and pseudo-element overlays in a single, polished component.

Key Features of This Accordion Card Gallery

📐
Flexbox Accordion
Cards share space equally via flex: 1 1 0. Hovering a card sets flex: 3.5 — the flex algorithm redistributes the remaining space automatically with no manual width calculations.
🎨
Grayscale-to-Color
Every image starts at filter: grayscale(100%) brightness(0.8) and transitions to full color on hover — a clean visual cue that this card is the active focus.
🔍
Image Zoom on Hover
The image simultaneously scales to 1.15 using CSS transform, giving a subtle Ken Burns–style zoom that adds depth and energy without JavaScript.
📄
Sliding Description
A .card-desc paragraph starts below the card's visible area at translateY(100%) and slides into view on hover, floating over a soft gradient backdrop for legibility.
🏷️
Flip-Style Title Badge
A centered title badge inverts its palette on hover — from a dark frosted-glass style to a bright near-white background — with a subtle scale transform for tactile feedback.
Shimmer Loading Effect
While images load over the network, an animated shimmer gradient plays on the image element as a skeleton placeholder. A tiny JS snippet removes it once the image fires its load event.
Keyboard Accessible
Each card's content is wrapped in a focusable anchor tag with :focus-visible styles, so keyboard and assistive-technology users experience the same visual feedback as mouse users.
📱
Fully Responsive
At tablet width the gallery shrinks gracefully. On mobile it flips to a vertical stack, disables hover logic, and reveals all content statically — a complete touch-friendly fallback with no extra JavaScript.

Full Source Code (Free)

The entire project lives in a single HTML file — no external CSS or JS files required. The HTML sets up the card structure and links images from picsum.photos for demonstration. The CSS drives every animation, transition, and responsive breakpoint. A four-line script at the bottom removes the shimmer placeholder once each image has loaded. Use the tabs below to explore the HTML and CSS sections separately.

HTML — index.html
CSS — style.css

🔓 Full Source Code unlocks in

05

Hosted on GitHub Gist — free, no sign-up required

💡 Quick Start: Copy the full code into a single index.html file. No build tools, no npm, no libraries — open it in any modern browser and the accordion gallery works immediately. Swap the picsum.photos URLs with your own images to customize it instantly.

How It Works — Step by Step

Here is a walkthrough of the eight core techniques that make this CSS accordion card gallery tick, from the Flexbox foundation to the mobile fallback strategy.

01

Flexbox Container Foundation

The .cards wrapper uses display: flex with flex-wrap: nowrap so all five cards always appear in a single row. A fixed height: 420px and overflow: hidden keep the strip constrained. border-radius: 1.2rem clips the corners of the entire group for a unified, card-like appearance.

02

Equal-Split Flex and Smooth Expansion

Each .card receives flex: 1 1 0, which tells the flex algorithm to treat all cards as identical in size, splitting the container's width five ways equally. The critical rule is transition: flex 0.6s cubic-bezier(0.4, 0, 0.2, 1) on the base card. When .card:hover sets flex: 3.5, the browser smoothly interpolates the flex value over 600ms, expanding the hovered card and proportionally compressing the others.

03

Image Grayscale Filter and Zoom

Each card's img starts with filter: grayscale(100%) brightness(0.8), visually muting the image. A transition on both filter and transform means that when .card:hover img applies filter: grayscale(0%) brightness(1) and transform: scale(1.15), both changes animate together — the image blooms into color while gently zooming in.

04

The Dark Gradient Overlay

A ::after pseudo-element on each card provides the dark overlay that makes the description text legible against the image. It uses background: linear-gradient(to top, rgba(20,15,10,0.7) 0%, transparent 55%) and starts at opacity: 0. On hover its opacity transitions to 1, revealing the gradient only when the card is active and the description is visible.

05

The Title Badge Flip

The .card-title badge is positioned with top: 50%; left: 50%; transform: translate(-50%, -50%) to center it on the card. By default it has a dark frosted-glass background. On hover, background transitions to a near-white value and color to a dark tone — effectively flipping its palette — while transform adds a subtle scale(1.08) to make it feel "pop" toward the viewer.

06

Sliding Description Overlay

The .card-desc paragraph is absolutely positioned at the card's bottom with left: 0; right: 0; bottom: 0 and transform: translateY(100%), pushing it just below the visible clipped area. A gradient background fades from opaque at the base to transparent higher up so it blends seamlessly. On hover, transition animates it to translateY(0) so it slides up into view like a caption rising from below.

07

Shimmer Skeleton Loading Effect

While each image is fetching over the network, a CSS @keyframes shimmer animation sweeps a moving gradient highlight across the element's background, mimicking a skeleton loader. A small JavaScript snippet checks img.complete on page load and also listens for each image's load event, adding a .loaded class that the CSS uses to disable the shimmer animation once the real image has painted.

08

Responsive Breakpoints and Mobile Fallback

At 768px, the container height is reduced to 360px and the expand ratio drops slightly for a tighter fit. At 520px, the cards switch to flex-direction: column and a fixed height: 220px each, stacking them vertically. Because there is no hover on touch screens, the grayscale filter is removed, the overlay opacity is set to 1, and .card-desc is forced to translateY(0) — making all content permanently visible without any interaction.

⚠️ Overflow Is Essential: The overflow: hidden on .cards is what clips the .card-desc overlay below the visible area before the hover. If you remove it, the description will be visible at all times regardless of the CSS translateY state. Similarly, each individual .card needs its own overflow: hidden to clip the image zoom without the image escaping its card boundaries.

Customization Ideas

The accordion card gallery is deliberately lean at its core, which makes it easy to adapt to a wide range of real-world use cases. Here are practical starting points.

  • Change the number of cards — Add or remove .card elements freely. Flexbox recalculates the space split automatically. If you add more than six cards, consider reducing the flex: 3.5 hover value to something like 2.5 so the expanded card doesn't crowd others to invisibility.
  • Swap the images — Replace the picsum.photos URLs with your own images. Keep object-fit: cover on the img elements so any aspect ratio fills the card without distortion.
  • Adjust the expand ratio — The flex: 3.5 on .card:hover controls how much larger the active card becomes relative to its siblings. A value of 2 gives a subtler expansion; 5 gives a more dramatic one.
  • Try a vertical layout — Change flex-direction to column on .cards and give it a fixed width instead of height. The accordion will then expand cards vertically — a great fit for sidebar or mobile-first layouts.
  • Keep cards always in color — Remove the filter: grayscale(100%) brightness(0.8) rule from the base .card img selector if you prefer full color at all times and just want the zoom and description reveal effects.
  • Add a click-to-lock state with minimal JavaScript — Toggle an active class on the clicked card to keep it expanded even after the cursor leaves, useful for touch-screen environments or when each card links to a detail view.
  • Customize the description content — The .card-desc paragraph can hold any HTML: buttons, tags, ratings, or icon + text combos. Just ensure the padding-top on the description is large enough to clear the gradient's opaque zone so text remains readable.
💡 Tip: Because the accordion state is driven entirely by CSS hover, you can combine it with the :focus-within pseudo-class on the container to keep the card expanded as long as any child element (like a button inside the description) is focused — keeping accessibility seamless without any JavaScript.

Best Practices

Following these guidelines will help you ship the accordion gallery in production with confidence and keep it maintainable as your project grows.

  • Always write descriptive alt text on every card image. Screen readers announce the alt attribute when a user navigates to the card's anchor — a vague or missing alt breaks the experience for visually impaired visitors.
  • Use loading="lazy" on off-screen images — All cards except the first visible one should defer loading so the page's initial paint is not blocked by large image files. The first card's image can use fetchpriority="high" to load it as a priority resource.
  • Respect prefers-reduced-motion — Wrap transition and animation declarations in a media query that sets transition: none !important for users who have enabled the operating system's reduced-motion preference. This is both an accessibility requirement and a performance optimization on lower-end devices.
  • Keep image dimensions consistent — Cards look cleanest when all images share the same aspect ratio. Use an image host or CDN that supports on-the-fly resizing (like picsum.photos/id/N/800/600) to enforce a uniform size across all cards.
  • Avoid animating width directly — The accordion effect works by transitioning the flex shorthand, not raw width. Flex transitions are composited much more efficiently by the browser's layout engine than direct width changes, especially when multiple sibling elements resize simultaneously.

Browser Compatibility

This accordion gallery uses only well-established CSS features — Flexbox, CSS filters, CSS transitions, @keyframes, and pseudo-elements — all of which have had broad support across every major browser for years.

Browser Flexbox & Transitions CSS filter Overall Support
Chrome / Edge Yes Yes Full
Firefox Yes Yes Full
Safari (macOS & iOS) Yes Yes Full
Samsung Internet Yes Yes Full
Internet Explorer 11 Partial No Limited
💡 Note: CSS filter (used for the grayscale effect) is not supported in Internet Explorer 11, meaning images will always appear in full color there. All other aspects of the layout still function. IE11 is effectively obsolete for new projects in 2026 and is not a practical target.

Performance & Responsiveness

Despite being a visually rich component with multiple simultaneous animations, this accordion gallery is exceptionally lightweight because every effect is CSS-driven and uses GPU-compositable properties.

  • GPU-accelerated properties: transform (for the image zoom and description slide) and opacity (for the overlay) are both handled entirely on the GPU compositor thread. They never trigger a layout recalculation or paint step, so the animations remain smooth even on mid-range mobile hardware.
  • CSS filter compositing: The filter: grayscale() transition is hardware-accelerated on all modern browsers. Declaring will-change: transform, filter on the img element hints to the browser to promote these elements to their own compositor layer in advance, preventing any frame drops during the transition.
  • JavaScript animations: Because every visual state — expansion, zoom, color reveal, overlay fade, description slide — is handled by CSS transition rules, there is no JavaScript animation loop, no requestAnimationFrame, and no risk of dropped frames from script execution.
  • Lazy image loading: The loading="lazy" attribute on non-primary images defers their network requests until they are near the viewport, improving initial page load time and reducing bandwidth on slower connections.
  • Responsive without JavaScript: The mobile breakpoint is achieved entirely through CSS media queries. Switching the stack from horizontal to vertical, forcing images into color, and revealing descriptions permanently are all handled in CSS — no resize event listeners or layout recalculation in script.
💡 Key Takeaway: Whenever multiple elements animate simultaneously — as they do when one card expands and four compress at once — reaching for transform and opacity (plus filter where supported) instead of width, height, or left is what keeps multi-element CSS transitions smooth across the full performance spectrum of devices.

Frequently Asked Questions

How does the accordion expand effect work using only CSS?
The accordion effect relies entirely on CSS Flexbox. Each .card is given flex: 1 1 0 so all cards share the container's width equally. On hover, the targeted card receives flex: 3.5, which tells the flex algorithm to allocate it 3.5 times as much space as its siblings. Combined with a transition: flex 0.6s on the base .card rule, this produces a smooth, animated expand-and-compress accordion effect — no JavaScript needed.
How is the grayscale-to-color hover effect achieved?
Each card image starts with filter: grayscale(100%) brightness(0.8), which drains all color and slightly darkens the image. When the card is hovered, CSS transitions the filter to grayscale(0%) brightness(1), restoring full color and normal brightness. Because filter is an animatable CSS property, the browser smoothly interpolates between the two states over 0.6 seconds using the cubic-bezier easing defined in the transition.
What is the shimmer loading animation and how does it work?
The shimmer is a CSS background animation that makes a light gradient sweep across the image placeholder while the actual image file loads over the network. It uses a linear-gradient background with background-size: 200% 100% and a @keyframes shimmer rule that animates background-position from its starting point to -200% 0. A small JavaScript snippet listens for each image's load event and adds a .loaded class, which the CSS uses to disable the shimmer once the image is ready.
How does the sliding description overlay appear on hover?
The .card-desc paragraph is absolutely positioned at the bottom of the card with transform: translateY(100%), pushing it fully below the card's clipped visible area. It also sits inside a gradient background that fades from a semi-opaque dark color at the bottom to transparent at the top. On hover, CSS transitions it to transform: translateY(0), causing it to slide up into view from the card's bottom edge.
How does this accordion card gallery behave on mobile devices?
At screen widths below 520px, a media query switches the .cards container to flex-direction: column, turning the horizontal strip into a vertical stack. Each card is given a fixed height: 220px and the hover-based flex expansion is disabled. Since mobile users cannot hover, images are shown in full color, the gradient overlay is visible by default, and .card-desc is forced to translateY(0) so all content appears without any interaction.
Is this accordion card gallery accessible for keyboard users?
Yes. Each card wraps its image in an anchor tag, which is naturally focusable via the Tab key. The CSS includes :focus-visible styles on the anchor that show a visible outline, apply the full-color image filter, and update the title badge styling — mirroring the hover state for keyboard and assistive-technology users. The card images also include descriptive alt attributes for screen reader support.

Conclusion

This CSS flexible accordion image card gallery is a compelling demonstration of just how much a modern browser can do with nothing but Flexbox, transitions, and CSS filters. By leveraging the flex algorithm's proportional space distribution, a single hover rule drives an entire accordion — no JavaScript toggle, no width math, no animation library.

The techniques here — transitioning flex for layout animation, combining grayscale filters with transform for image reveal, and using translateY for slide-in overlays — are reusable building blocks you'll reach for across countless future projects: hero sections, team galleries, destination showcases, and feature comparison strips.

Ready to keep exploring pure CSS interactions? Check out the Animated Floating Action Button Menu for CSS keyframe animations with a JS toggle, or the Neon Cursor Animation for advanced pointer-tracking effects.

Found this useful? Explore more HTML & CSS projects in the sidebar or browse the full project library.