CSS carousel with JS controller


CSS3 JavaScript jQuery Carousel

While I could (and will) create a pure-CSS carousel, this time I'll show you how to create a simple yet powerful carousel javascript-controlled.

Let's face it: carousels almost never make you happy, for one reason or another... they may have limited elements, they may be too much hardcoded to style them up... or whatever else you dislike. Most of the time looking at the code doesn't help you at all because you don't understand on-the-fly the logics behind it.

Speak no more! Let's project and build up this carousel!

First of all, I thought about a div with fixed height and width, call it "container". This element will define the user's view and will contain a much more wide, "moving" mid-div. To be precise, its width property will match the container per the actual carousel elements (we'll setup it in JS) and will contain the actual carousel elements, or panels.

The idea is indeed to let this mid-div scroll horizontally (hiding the overflowed parts) clicking on the carousel's controller and thus showing the different panels, one at a time.


Attention: this work is under the Creative Commons Attribution 3.0 Unported licence


Live demo: preview, code

css_js_carousel.html (contains engine-specific CSS properties).


This will thus be our HTML skeleton:

:::html
<!-- outer div with fixed height and width, our "view" -->
<div id="carousel">
    <!-- our "mid" div, as wide as the inner elements per the view's width -->
    <div>
        <!-- our carousel elements. Let's use awful colors to differentiate them! -->
        <div style="background-color: red;">
            Carousel element n.1
        </div>
        <div style="background-color: white;">
            Carousel element n.2
        </div>
        <div style="background-color: orange;">
            Carousel element n.3
        </div>
        <!-- we could continue "ad libitum" -->
    </div>
    <!-- this paragraph will contain our carousel's controller -->
    <p></p>
</div>

And this will be our stylesheet (plain CSS3, no engine-specific properties):

:::css
#carousel, #carousel > div, #carousel > div > div {
    box-sizing: border-box;
}

/* container */
#carousel {
    text-align: center; /* to center the JS controller */
    width: 960px; /* put the width you wish */
    height: 400px; /* same... */
    overflow: hidden; /* important: will avoid the scrollbar */
}

/* mid-element */
#carousel > div {
    position: relative; /* this will let the controller edit the left property */
    height: 100%; /* keep the div 100% height */
    /* the width is being dynamically calculated in JS */
    transition: left 1s ease; /* this will create a panel switch transition */
}

/* carousel elements */
#carousel > div > div {
    text-align: left; /* reset to left (see #carousel) */
    height: 100%; /* always fit the parent's height */
    width: 960px; /* use the same value as #carousel to fit it */
    float: left; /* display one after the other */
}

/* controller */
#carousel > p {
    position: relative;
    bottom: 3em;
    margin: 0 auto; /* to horizontally center it (#carousel text-align: center) */
}

/* some really useless controller style */
#carousel > p > a {
    margin: 0 5px;
    font-size: 3em;
    text-decoration: none;

    color: brown;
    transition: text-shadow .5s ease;
}
#carousel > p > a.active {
    text-shadow: 0 0 .1em black;
}

At this point we should have almost everything. What we're still missing is:

We will handle all of this in JavaScript. For rapidity and because I'm lazy, I used jQuery. You can easily convert it in plain JS, but I think this framework really makes your life easier.

:::javascript
// get the carousel's width
var width = $("#carousel").width();
// get the carousel elements' number
var num_panels = $("#carousel > div > div").size();

// set the mid-div's size
// depending on the number of panels
$("#carousel > div").width(width*num_panels);

// create dots as the carousel's controller in the carousel's paragraph
// we will inject also the attribute "data-panel" so that we'll know which
// panel the dot refers to when it will be clicked
for(i = 0; i < num_panels; i++) {
    $("#carousel > p")
        .html($("#carousel > p").html()+"<a href='#' data-panel='"+i+"'>•</a>");
}

// set the default active anchor (optional, pure CSS styling)
$("#carousel > p > a").first().addClass("active");

// setup the carousel's controller
$("#carousel > p > a").click(function () {
    // clear the anchors' "active" class (optional)
    $("#carousel > p > a").each(function () {
        $(this).removeClass("active");
    });
    // set the clicked anchor as active (optional)
    $(this).addClass("active");

    // get the panel's reference
    var offset = $(this).attr("data-panel");
    // use it to calculate the left offset of the mid-element
    // and set it. DONE!
    $("#carousel > div").css("left", -width*offset);

    // prevent the default link click behavior (don't go to #)
    return false;
});

That's it!

- 5th June 2013

> back