Oct 26, 2016 Design + Creative

Carousels Don't Have to be Complicated

Every time a carousel is mentioned in a blog post, it’s a requirement to mention that… say it with me now:

You probably shouldn’t use a carousel.

Jared Smith made a microsite just for it, with research and rhetoric supporting the idea that you shouldn’t use them. Most of that information focuses on the fact that there is low engagement with the non-first-slide(s).

I’m not here to argue with data, but I would argue with the dogmatism of “never user them, EVER.” Swiping on mobile is an extremely common action, and what is a swipe that reveals more content? Basically a carousel. What about a carousel that doesn’t demand much interaction? Perhaps just a way to swipe through an artist’s recent work. This seems like a perfectly nice way to do that, so long as the UI is clear and accessibility is implemented.

What I am here to talk about is the situation where you do want a carousel and to resist the  temptation to reach for a wheelbarrow full of code to do so. I guarantee there are people who’ve picked an entire CMS because they thought they needed it to make a carousel. No shame. We’re all learning.

I have good news: Carousels don’t have to be complicated. They don’t have to require a ton of code or do anything that you can’t wrap your head around with basic HTML, CSS, and JavaScript knowledge.

A Super Simple Swipeable Slider

What else is a slider but a few panels to swipe or scroll through? Let’s make one with five slides. A parent div with five divs inside:

<div class="slider">
  <div>Slide #1</div>
  <div>Slide #2</div>
  <div>Slide #3</div>
  <div>Slide #4</div>
  <div>Slide #5</div>

Now we line up them up and make it work:

.slider {
  /* line them up horizontally */
  display: flex;

  /* allow for scrolling */
  overflow-x: auto;

  /* make it smooth on iOS */
  -webkit-overflow-scrolling: touch;
.slider > div {
  /* make sure the width is honored */
  flex-shrink: 0;
  width: 300px;
  height: 300px;

That’s it.


You can even add a really nice touch by adding scrolling snap points:

.slider {
  /* ... */

  /* each slide snaps into place */
  scroll-snap-points-x: repeat(300px);
  scroll-snap-type: mandatory;


Easy, right?! You don’t have to download a library just for that, let alone choose a CMS. Let’s explore some other people’s similar ideas.

Christian Heilmann’s “Keeping it simple: coding a carousel” adds basic controls with a little Vanilla JavaScript

His article has the same concept:

“In this article, I want to approach the creation of a carousel differently: by keeping it as simple as possible while not breaking backwards compatibility or have any dependencies.”

The HTML is similar. In this case, it is an ordered list of panels. Plus, some simple arrow buttons:

<div class="carouselbox">
  <div class="buttons">
    <button class="prev"><span class="offscreen">Previous</span>
    <button class="next">
      <span class="offscreen">Next</span></button>
  <ol class="content">

Christian wires up clicks on the buttons to add (and remove) a .current class to the appropriate panel. If the only JavaScript you know is how to add and remove classes on clicks/taps, that gives you a lot of design control. He adds a bit of a CSS transform and it results in this:


Remy Sharp’s “Coda Slider Effect”

I remember watching this for the first time and being absolutely captivated. These were the days when I was just learning JavaScript for the first time, by way of jQuery. Created in 2008, this video tutorial might feel a little dated. The point of this article is not reaching for libraries, right? Yes, but really, the spirit of this article is being empowered to write stuff like this yourself, and that’s exactly what Remy walks you through here.

I would emphasize just how the progressive enhancement part works. The navigation for the slider uses anchor links to jump the slider to the correct position. Check out the markup:

<div class="slider">

  <ul class="nav">
    <li><a href="#slide-1">Slide 1</a></li>
    <li><a href="#slide-2">Slide 2</a></li>
    <li><a href="#slide-3">Slide 3</a></li>

  <div class="mover">
    <div class="panel" id="slide-1"></div>
    <div class="panel" id="slide-2"></div>
    <div class="panel" id="slide-3"></div>


See how the links are anchors to the corresponding panels? If you design the slider such that the panels are in a horizontally scrolling area, the jump links will still work, scrolling that area so that the panel is in view.

The rest of Remy’s tutorial is all about enhancing that basic functionality by adding controls, smooth scrolling and more bells and whistles.


Remy did another carousel tutorial as well that’s even more clever, incorporating the idea of infinite (repeated) scrolling.

What about auto-play? See Jonathan Snook’s “Simplest jQuery Slideshow”

Heading back to the ultrasimple, Jonathan just put some images into a div:

<div class="slideshow">
  <img src="image-1.jpg">
  <img src="image-2.jpg">
  <img src="image-3.jpg">

And, with a handful of lines of jQuery, makes it an auto-playing, cross-fading slideshow:

$('.fadein img:gt(0)').hide();
  $('.fadein :first-child').fadeOut()

Easy cheesy:


I did a very similar thing, which faded in-and-out div’s instead of images directly. Great minds think alike.

Auto-play can be done in CSS as well

Check out Una Kravets’ demo, which uses @keyframes to change the translateX value of the slider for the movement.

#slide-holder {
  /* wide enough to fit all the slides */
  width: 400%;
  position: relative;
  animation: scroller 10s infinite;

/* need a step for each slide */
@keyframes scroller {
  0%   { transform: translateX(0); }
  33%  { transform: translateX(-400px); }
  66%  { transform: translateX(-800px); }
  100% { transform: translateX(0); }

I did the same exact thing, only use an image that repeated itself a little so that the carousel could be infinite.

There is plenty of trickery going on in Gallery CSS, but it’s just HTML and CSS. No dependencies. It works by utilizing the :target selector in CSS. You click an anchor link, the element with the matching ID is now “targeted”, and through clever CSS selectors involving the ~ general sibling combinator, you can hide/show the appropriate panel.


You can just snag Ben’s code to use (it’s pretty small), but it’s more useful to understand the concept at work.

<div class="gallery items-3">
  <div id="item-1" class="control-operator"></div>
  <div id="item-2" class="control-operator"></div>

  <figure class="item">

  <figure class="item">

  <div class="controls">
    <a href="#item-1" class="control-button"></a>
    <a href="#item-2" class="control-button"></a>

All the panels (.item) are hidden (except the first/default one). e.g.

.item:not(:first-of-type) {
  opacity: 0;
  visibility: hidden;

Say you click on the second link, it becomes the target, and you reveal the panel like:

.control-operator:nth-of-type(2):target ~ .item:nth-of-type(2) {
  opacity: 1;
  visibility: visible;

Opacity changing is but one possibility. You could transform them, use movement, whatever you like.

If you’re going to use a library, Dave DeSandro’s Flickity is a great choice

If you decide to go with a library, I think the time to do that is when you want something that the library makes particularly awesome and also makes it particularly easy.

I think Flickity does that very well. You don’t need to write any JavaScript at all to make it work, you just put an attribute on some HTML, like:

<div class="carousel" data-flickity>
  <div class="carousel-cell"></div>
  <div class="carousel-cell"></div>


But you can also configure it with loads of useful options, and it includes a robust API. And of course, like a good slider should be: responsive and touch-friendly.

About the Author Chris is a web designer and developer. He writes about all things web at CSS-Tricks, talks about all things web at conferences around the world and on his podcast ShopTalk, and co-founded the web coding playground CodePen. More by this Author