Building Carousels with CSS Only

Building Carousels with CSS Only

Mitchell Christ
Mitchell Christ
  • Web Dev
Table of Contents
  1. Basic carousels (flex or grid) with scroll snapping
  2. Tailwind carousel with full-bleed and edge fading
  3. Progressive enhancement: pagination and navigation
  4. Anchoring pagination and navigation
  5. 🎠 Closing thought

Modern CSS is making large leaps these past couple of years. Being able to replace complex layouts and interactive features that once required JavaScript or third-party plugins with native CSS is a huge step forward for web developers.

Heck, it’s not perfect—we still have to consider cross-browser quirks—but understanding these modern CSS features is well worth it. You never know when they might come in handy, or help you improve performance, readability, and maintainability in your codebase.

Today, I want to share my approach to building carousels on the web. Of course, using just CSS and zero plugins. (Swiper is still my go-to when clients need something more complex.)

Thanos holding his hand next to his face with the Infinity Gauntlet, while riding a merry-go-round horse carousel at a carnival. menacing expression

Basic carousels (flex or grid) with scroll snapping#

Let’s start simple: a horizontally scrollable carousel powered purely by CSS.
No JavaScript, no frameworks. Just overflow-x: auto and scroll-snap-*.

Below are two variations: one using Flexbox, and another using CSS Grid.
Both rely on scroll snapping to lock items neatly into place as you swipe.

Next, let’s enhance the design. Using Tailwind CSS, we can achieve a “full-bleed” layout—where the carousel stretches to the very edges of the viewport—and add a soft fade effect on the edges to hint at overflowed content.

Pro tip: On mobile, we can make it visually immersive with one of my favorite CSS snippets ever:
  • src/app.css
  • @utility full-bleed {
      width: 100vw;
      margin-inline: calc(50% - 50vw);
    }
    
    /* use as tailwind classes: full-bleed or max-md:full-bleed, etc */

    This breaks the carousel out of its parent container’s max-width, creating that beautiful edge-to-edge feel.

    Progressive enhancement: pagination and navigation#

    Now for something new and exciting—scroll-linked navigation and pagination using the latest CSS pseudo-elements.

    The new ::scroll-marker, ::scroll-marker:target-current, and ::scroll-margin(*) properties let us create interactive scroll behavior without JS.

    Think of scroll buttons as "previous" and "next" controls, and scroll markers as pagination indicators.

    CSS is finally catching up to what we’ve relied on JavaScript for—but in a cleaner, more declarative way.

    Anchoring pagination and navigation#

    Finally, let’s tie everything together with CSS Anchoring, one of the freshest additions to the language.

    Anchors allow us to position elements (like navigation arrows or pagination dots) relative to scrollable elements—even when they move. It’s a total game-changer for building complex layouts natively.

    If you want to dive deeper, check out Adam Argyle’s fantastic guide on the basics of CSS Anchors—it’s a must-read for understanding how this all fits together.

    half of a carnival carousel disappearing into dust, as if it was snapped during the Marvel movie scene

    🎠 Closing thought#

    Native CSS has come a long way—and it’s only getting better. With features like scroll snapping, masking, and the upcoming scroll markers and anchors, we’re finally seeing UI patterns once reserved for JavaScript become fully declarative and performant in pure CSS.

    Experiment with these techniques, keep an eye on browser support, and sprinkle in progressive enhancement where needed. The more we push what’s possible with CSS, the more fun (and fast) front-end development becomes.

    Got a cool CSS carousel trick of your own? Drop it in the comments—I’d love to see it spin. 🎠

    Ship your next site faster and type safer

    Built for developers who love clean structure and fast launches.