Responsive css only carousel

A while ago I looked at some methods to create css only carousels. Since then new css features have become widespread allowing us to do more. Here i'm revisiting the css carousel to see what we can achieve with very simple code!



First off we need to define some requirements for our carousel. This will give us our list of features:
  • Must be able to fill any width or height (responsive)
  • Multiple slides
  • Ability to switch between slides
  • Ideally using browser urls to allow linking directly to slides
  • Slide controls to indicate which slides we are on
Now we know what we are doing, lets start off by creating some html.

<div class="carousel">
    <div class="item"><h1>Item 1</h1></div>
    <div class="item"><h1>Item 2</h1></div>
    <div class="item"><h1>Item 3</h1></div>
    <div class="item"><h1>Item 4</h1></div>
</div>

And add some css to make the carousel full width/height and slides fit the space:

.carousel {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    background-color: #333;
}

.carousel .item {
    position: absolute;
    width: 100%;
    height: 100%;
    text-align: center;
}

Now we need a way of animating the slides in and out. I've name-spaced this as a separate class slide-in, which you will need to add to slides that you want to animate in:

.carousel .slide-in {
    -webkit-transform: translate3d(-90%, 0px, 0px);
    -moz-transform: translate3d(-90%, 0px, 0px);
    -ms-transform: translate3d(-90%, 0px, 0px);
    -o-transform: translate(-90%, 0px, 0px);
    transform: translate3d(-90%, 0px, 0px);
    -webkit-transition: -webkit-transform 0.5s ease-out;
    -moz-transition: -moz-transform 0.5s ease-out;
    -ms-transition: -ms-transform 0.5s ease-out;
    -o-transition: -o-transform 0.5s ease-out;
    transition: transform 0.5s ease-out;
    z-index: 1;
}

.carousel .slide-in:target ~ .slide-in {
    -webkit-transform: translate3d(90%, 0px, 0px);
    -moz-transform: translate3d(90%, 0px, 0px);
    -ms-transform: translate3d(90%, 0px, 0px);
    -o-transform: translate(90%, 0px, 0px);
    transform: translate3d(90%, 0px, 0px);
}

.carousel .slide-in:target {
    -webkit-transform: translate3d(0px, 0px, 0px);
    -moz-transform: translate3d(0px, 0px, 0px);
    -ms-transform: translate3d(0px, 0px, 0px);
    -o-transform: translate(0px, 0px, 0px);
    transform: translate3d(0px, 0px, 0px);
    z-index: 3;
}

.carousel .slide-in:target + .slide-in {
    z-index: 2;
}

To activate a slide as the current slide you need to add id's to all of your slide items. These id's can then be targeted via the hash url:

<div class="carousel">
    <div class="item slide-in" id="item1"><h1>Item 1</h1></div>
    <div class="item slide-in" id="item2"><h1>Item 2</h1></div>
    <div class="item slide-in" id="item3"><h1>Item 3</h1></div>
    <div class="item slide-in" id="item4"><h1>Item 4</h1></div>
</div>

So now you should be able to add #item1 to your url and see the item change. Next we need to add some controls so you don't need to type the url:

<div class="carousel">
    <div class="item slide-in" id="item1"><h1>Item 1</h1></div>
    <div class="item slide-in" id="item2"><h1>Item 2</h1></div>
    <div class="item slide-in" id="item3"><h1>Item 3</h1></div>
    <div class="item slide-in" id="item4"><h1>Item 4</h1></div>
    <div class="controls">
        <a href="#item1" class="btn"></a>
        <a href="#item2" class="btn"></a>
        <a href="#item3" class="btn"></a>
        <a href="#item4" class="btn"></a>
    </div>
</div>

By clicking a control, it will changed the has url to an id, which will target the correct css and show the slide. Lets add some styling to the controls so they align to the bottom and center of the carousel:

.carousel .controls {
    position: absolute;
    bottom: 0;
    width: 100%;
    text-align: center;
    z-index: 5;
}

.carousel .controls .btn {
    display: inline-block;
    background-color: #fff;
    -webkit-border-radius: 100%;
    -moz-border-radius: 100%;
    border-radius: 100%;
    width: 12px;
    height: 12px;
    vertical-align: middle;
    margin: 0px 1px 15px;
    opacity: 0.7;
}

.carousel .controls .btn:hover {
    opacity: 0.9;
}

There are only two potential limitations to this approach I can see so far. To select the first slides the default, you need to reverse the order of the slides and the animation (see jsfiddle url below). The tab indexes must be set to allow accessibility and requires more html.

You can view a working example here: