Riding A Carousel

I had an idea for a client’s site this week, where a series of images would scroll across, fade in and out, and link to another page. I’d seen carousels like this before, but I figured there was a non-Flash solution somewhere that would accomplish the task.

I was right. jCarousel is an extremely configurable plugin for jQuery which makes possible these types of effects:

This goes beyond the standard things you’ll do with jCarousel, so let me share what I found to get this working.

The carousel itself is pretty standard HTML markup, just an unordered list. I’m using some images here with some additional text for captions:

<ul class="jcarousel-skin-none" id="mycarousel">
  <li><a href="http://example.com/">
    <img alt="" src="http://dummyimage.com/100x100/000/fff&amp;text=1" /></a>
    <a class="caption" href="http://example.com/"><br />
      <b>Title One</b><br />
      Caption i</a></li>
  <li><a href="http://example.com/">
    <img alt="" src="http://dummyimage.com/100x100/123456/fff&amp;text=2" /></a>
    <a class="caption" href="http://example.com/"><br />
      <b>Title Two</b><br />
      Caption ii</a></li>
  <li><a href="http://example.com/">
    <img alt="" src="http://dummyimage.com/100x100/789012/fff&amp;text=3" /></a>
    <a class="caption" href="http://example.com/"><br />
      <b>Title Three</b><br />
      Caption iii</a></li>
  <li><a href="http://example.com/">
    <img alt="" src="http://dummyimage.com/100x100/901234/fff&amp;text=4" /></a>
    <a class="caption" href="http://example.com/"><br />
      <b>Title Four</b><br />
      Caption iv</a></li>
</ul>

Of course, there’s some CSS involved. I just took an existing jCarousel skin and removed the selectors I wasn’t using:

ul#mycarousel {
  /* Degrade if Javascript is disabled */
  display: none;
}

.jcarousel-skin-none .jcarousel-direction-rtl {
  direction: rtl;
}

.jcarousel-skin-none .jcarousel-container-horizontal {
    width: 410px;
    padding-top: 15px;
    border-top: 1px solid #aaa;
    border-bottom: 1px solid #aaa;
}

.jcarousel-skin-none .jcarousel-clip {
  overflow: hidden;
}

.jcarousel-skin-none .jcarousel-clip-horizontal {
  width:  410px;
  height: 150px;
}

.jcarousel-skin-none .jcarousel-item {
  width: 130px;
  height: 150px;
  font-size: 11px;
  line-height: 13px;
  font-family: Verdana, Helvetica, Arial;
  opacity: 0.3;
}

.jcarousel-skin-none .jcarousel-item .caption {
  opacity: 0;
}

.jcarousel-skin-none .jcarousel-item a.caption {
  color: black;
  text-decoration: none;
}

.jcarousel-skin-none .jcarousel-item-horizontal {
  margin-left: 0;
  margin-right: 10px;
}

.jcarousel-skin-none .jcarousel-direction-rtl .jcarousel-item-horizontal {
  margin-left: 10px;
  margin-right: 0;
}

jcarousel-skin-none .jcarousel-item-placeholder {
  background: #fff;
  color: #000;
}

When the page first loads, the captions won’t be visible (opacity: 0) and the images will be at 30% opacity.

The code to initiate the carousel is simple—three items are visible and the carousel scrolls one item at a time automatically every second, with the animation lasting one second…

$(document).ready(function () {
  $('#mycarousel').css('display','block');
  $('#mycarousel').jcarousel({
    visible: 3,
    auto: 1,
    scroll: 1,
    animation: 1000,
    wrap: 'circular',
    initCallback: myInitCarousel,
    itemFirstInCallback: {
      onBeforeAnimation: myBeforeAnimation,
      onAfterAnimation: myAfterAnimation
    }
  });
});

…but it’s the callbacks that add some jQuery goodness:

function myInitCarousel(carousel) {
  $('#mycarousel li').hover(
    function(){
      carousel.stopAuto();
      $(this).fadeTo(1,1);
      $(this).children().fadeTo(1, 1);
      $(this).siblings().fadeTo(1,.3);
      $(this).siblings('li').children('.caption').fadeTo(1,0);
    },
    function(){
      carousel.startAuto();
      $(this).fadeTo(1,.3);
  });
};

function myBeforeAnimation(carousel, item, first, state) {
  second = first+1;
  third = first+2;
  if(third > 4) third = 1;
  $(".jcarousel-item-" + second).fadeTo(1000,1);
  $(".jcarousel-item-" + second + " .caption").fadeTo(1000,1);
  $(".jcarousel-item-" + first).fadeTo(1000,.3);
  $(".jcarousel-item-" + first + " .caption").fadeTo(1000,0);
}

function myAfterAnimation(carousel, item, first, state) {
  second = first+1;
  third = first+2;
  if(third > 4) third = 1;
  if ( state == 'init') return;
  $(".jcarousel-item-" + first).fadeTo(1000,.3);
  $(".jcarousel-item-" + first + " .caption").fadeTo(1000,0);
  $(".jcarousel-item-" + third).fadeTo(1000,.3);
  $(".jcarousel-item-" + third + " .caption").fadeTo(1000,0);
}

The initCallback has the code which stops and starts the scrolling when the user hovers the pointer over the carousel. It also fades in the image and caption that’s being hovered over and fades out the elements.

The animation callbacks figure out which elements aren’t in the center and fade those out, while fading in the center elements. If more than three items are visible at a time, you’ll need to add the appropriate code for those elements.