Background
Michiel Kenis requested a tutorial explaining how to create a similar effect used to showcase the products on the Apple web site.
This 'product slider' is similar to a straight forward gallery, except that there is a slider to navigate the items, i.e. the bit the user controls to view the items. Simple stuff.
jQuery already has the plugins to create these effects so we don't have to go about creating them ourselves from scratch.
How to Solve the Problem
To create the slider controlled gallery, we need the following:
- Markup that allows us to place several items within a list, and that overflows out of sight.
- A slider widget to control what subsection of products we can see.
- Logic to translate the sliders position to slide the products inversely (i.e. we slide left-to-right, the products go right-to-left).
I've provided a screencast to walk through how create this functionality. Details on how and what I used can be found below.
Watch the slider gallery screencast (alternative flash version)
View the demo and source code used in the screencast
jQuery UI
jQuery UI is "a set of themable widgets and interactions". For this task, we don't need much of jQuery UI, but for the UI slider widget, we'll need the following:
- jquery.dimensions.js
- ui.mouse.js
- ui.slider.js
Of course we'll still need the latest jquery.js.
All the above scripts can be extracted from the jQuery UI download.
HTML Markup
The markup for the example is straight forward. It boils down to a ul holding the items you want in the gallery, and a div with another nested div, for the slider and it's handle.
<div class="sliderGallery">
<ul class="items">
<li>Item one</li>
<li>Item two</li>
<li>Item three, etc...</li>
</ul>
<div class="slider">
<!-- the handler to action the slide -->
<div class="handle"></div>
<!-- labels appear against the slider, as pointers to the user -->
<span class="slider-lb1">slider label 1</span>
<span class="slider-lb2">slider label 2</span>
<span class="slider-lb3">slider label 3</span>
</div>
</div>
CSS
One key feature about the CSS used: in my example, I assumed that I would not have a predefined width to the ul element. As such, I can't float the li elements and have set widths. To ensure everything flows horizontally, I make use of white-space: nowrap.
I've only included the required CSS to create the sliding gallery effect. If you want to see the complete CSS used in the screencast just view the source for the demo
Slider Gallery Container
The overflow ensures the items are hidden, and the position: relative is used to absolutely position the ul element within it.
.sliderGallery {
overflow: hidden;
position: relative;
padding: 10px;
height: 160px;
width: 960px;
}
Slider Gallery Items
The white-space: nowrap is what allows us to work with an unknown width in the ul element.
.sliderGallery UL {
position: absolute;
list-style: none;
overflow: none;
white-space: nowrap;
padding: 0;
margin: 0;
}
.sliderGallery UL LI {
display: inline;
}
Slider Handle
In the screencast, the example uses a background image for the slider handle, and in particular from the example, the width of the handle is larger than the image to allow it to overlay on the left and right arrows.
.handle {
position: absolute;
cursor: move;
top: 0;
z-index: 100;
/* bespoke to your own solution */
height: 17px;
width: 181px;
}
jQuery
As stated above, we will need to include a series of plugins from the jQuery UI download, then we will add our dash of jQuery to create the sliding gallery effect.
Required Plugins
<script src="jquery.js" type="text/javascript"></script>
<script src="jquery.dimensions.js" type="text/javascript"></script>
<script src="ui.mouse.js" type="text/javascript"></script>
<script src="ui.slider.js" type="text/javascript"></script>
Slider Code
$(function () { // see note below
$(window).ready(function () {
$('div.sliderGallery').each(function () {
var ul = $('ul', this);
var productWidth = ul.innerWidth() - $(this).outerWidth();
var slider = $('.slider', this).slider({
handle: '.handle',
minValue: 0,
maxValue: productWidth,
slide: function (ev, ui) {
ul.css('left', '-' + ui.value + 'px');
},
stop: function (ev, ui) {
ul.animate({ 'left' : '-' + ui.value + 'px' }, 500, 'linear');
}
});
});
});
Please note during the screencast I used $(function () {}) - but I've had to since change this to $(window).ready. This is because I'm using white-space: nowrap and the width isn't calculated until after the images are loaded. jQuery's document ready function fires before the images are loaded - to allow the JavaScript access to the DOM as early as possible.
This wasn't a problem in the demo because the images were loaded from a local server, and thus loaded fast enough to allow the code to work out the width correctly.
The code breaks down as follows:
window.onload = function () {
When the DOM and images are ready (note that if you don't use white-space: nowrap then you should use the standard $(document).ready() method).
$('div.sliderGallery').each(function () {
Loop through all the div.sliderGallery elements. This code design sets us up to convert our code to a reusable plugin.
var ul = $('ul', this);
Search for the ul in the context of this - which is currently a div.sliderGallery.
var productWidth = ul.innerWidth() - $(this).outerWidth();
.innerWidth() and .outerWidth() come from jquery.dimensions.js. We're subtracting the current div.sliderGallery width because when we slide, we want it to stop once the last item is visible, rather than sliding it all the way left until it's out of sight.
var slider = $('.slider', this).slider({
.slider() comes from ui.slider.js.
handle: '.handle',
The class of our slider handle.
slide: function (ev, ui) {
ul.css('left', '-' + ui.value + 'px');
},
As the handle is moved, we move the ul of items, note that it moves negatively, creating the scrolling effect.
stop: function (ev, ui) {
ul.animate({ 'left' : '-' + ui.value + 'px' }, 500, 'linear');
}
We use this for when slider area has been clicked, to create the scroll effect.
Taking it Further
When I have a working version of the code, I often try to think how the interaction could be better. Here's a list of ways it could be improved, in no particular order - if you fancy a challenge:
- Better scrolling effect, in particular, fast scroll for the bulk of the animation, and slows down when it's settling on the final item.
- Turn it in to a plugin.
- The arrow can be turned in to handlers to slide the handle only part of the distance, rather than all.
- A nice effect the Apple version has, is the jump labels, within the slider element, change class given the distance they are from the slider handle. They appear brighter as they're closer and duller as they are further away from the handle.
- Anything else you can think of!
February 19, 2008 at 03:54
Hi,
GREAT!! tutorial!
I havnt read it completely yet but looking at the demo version...will it be possible to make the items controlled by the slider, clickable?
thank!
February 19, 2008 at 10:59
@Jacob - absolutely. You've got license to do anything you want within the
ulelement. I just used pictures as a demonstration, you should be able add all kinds of content - text, images, links, etc.February 20, 2008 at 13:49
i want to know is there any way to grab the images from a system folder and displaying as animated image through jquery. Pls help us using jquery and (with out providing any image path in the code) and it should grab the image.Its like, if any one insert a new image in folder it should reflect in the animation.
February 29, 2008 at 21:29
Remy,
I'm playing with a mod to this. Nice work by the way. On your example, IE7 has the scrollbar above the items. In Opera 9.25, after you drag the scroller once, it locks. You can then only scroll from then on by the arrows and actually clicking on the slider bar. I was having the same Opera issue, so i just checked your example and it does the same thing. I'm still working out some positioning kinks in my test so i haven't tried to sort out Opera yet.
March 9, 2008 at 09:46
Hello, I've been going mad for the last few days about making the arrows go steps instead of all the way. I haven't been able to figure out how to do it at all: I suppose I'm missing something general about the JS syntax. Please give it a look if possible. Thanks!
March 11, 2008 at 00:32
Remy,
Thank you for this tutorial and code. I love it.
I was wondering if you know of a way to incorporate reflection.js into this gallery so I don't have to edit images each time, adding their reflections.
Whenever I try it (even when i put the header code after the slider js entries) it does not work. I have been searching for a work-around, but to no avail.
You can find a test page I created using your code here:
http://www.therealduckie.net/damian/slider.html
Some images were made in Photoshop to see what the reflection would look like. Others are just jpg’s. (please excuse the silly rap music images..it’s for a client)
I appreciate anything you can do.
Cheers
March 13, 2008 at 14:49
Any idea if it's possible to make this work with slideToggle? IE6/IE7 have problems with the absolute/relative positioning of elements of the slider, so the animation won't work properly...
March 19, 2008 at 14:48
It seems not properly work in Opera (you cannot roll slider twice).
March 21, 2008 at 04:36
Will this work?
$(document).load(function() { // startup code here })
April 4, 2008 at 02:22
Hi,
nice script, but in IE7 the slider bar is over the images and in opera the slider can´t "drag&drop".
April 10, 2008 at 09:39
Hi Remy,
I love your blog! The Slider Gallery and Image Loading were exactly what I was looking for. I find screencasts extremely useful and easy to understand than reading tutorials. Its also nice that you don't edit out the debugging process as it helps us to learn and look out for similar problems in our own code. Its very refreshing to hear a British voice too (most of the ones I've watched were American). Keep up the good work, I'll definitely be keeping my eyes peeled and waiting eagerly for your next post.
Best wishes, Sim
April 11, 2008 at 17:15
Hi! very impressed by this tutorial.
I tried to do the same with a vertical slider and .... failed.
if, by chance, you have a couple of minutes to spend on it, here is the page i am struggling with since too many days.
Thank you
http://a_renaut.club.fr/slider/index.html
April 12, 2008 at 01:02
Please forgive my ignorance, but do I need a license to use this? Or under what license is this?
Thanks.
Rob.
April 12, 2008 at 13:20
@Rob - no license is required. However, I wouldn't recommend using the style directly from Apple. Make it your own and make it even better! :-)
April 14, 2008 at 18:20
Great tutorial. But there's one thing that makes this one inferior to the one used on Apple's site - accessibility and graceful degradation.
If you go to Apple's site and disable Javascript, the fancy scrollbar disappears, and you see a regular scrollbar. So it's still functional without js. With this one, disabling js renders it useless.
April 14, 2008 at 19:36
@Dean - thanks - that's an important point.
I would always advocate starting with JS and CSS turned off and working your way from there (for the screencasts there's quite a bit of work behind the preparation, and since I'm demonstrating the jQuery side it's not always practical).
However! Thinking about it, to make this solution accessible, the overflow on the UL should be set in the JavaScript, and the DOM elements that make up the handle and slider navigation should also be built in JS - that way it should degrade without JS. Next stop - checking it without CSS!
I've been toying with the idea of adding a preface to the site that states that as designers you should start with the accessible working version, and only then should you start applying the "whizz-bang" :-)
April 14, 2008 at 20:25
Hi Remy! Thanks for your response!
I'm confused since the download package JQUERY UI DOWNLOAD comes with two licenses a GPL and a MIT one. So which one should I take into consideration especially since I'm using this on a commercial site?
Thanks for your help!
April 14, 2008 at 22:35
Hi Remy. I think I've got a handle on how to make it degrade gracefully. The problem I'm having now is making it work with a table inside the sliderGallery, rather than a ul. Changing the references in the js from "ul" to "table" doesn't seem to do it. Any suggestions?
April 16, 2008 at 10:12
Hi great stuff,....I successfully reverse engineer it to make it work for my project (with a little addition) Thank You So Much for this tutorial.
Quick question: How can make the arrows next to the scroller work? Clicking it would make it slide one image at a time...Thanks again
April 18, 2008 at 01:40
Awesome work Remi! Now how about all the other goodies on the Apple site? Can't wait.
I'm looking for some kind of slider/slideshow thing I can use for switching videos in a div, and I'm gonna see if I can make this slider work for that.
April 19, 2008 at 21:17
Hi Remy. Great tutorial! I've been playing around with this for a few days (first introduction to jquery and js for that matter). What I can't figure out is:
1.. How to slide the handle on mousedown instead of mouseup.
2.. How to highlight the labels as the handle gets closer.
Thanks.
April 24, 2008 at 10:25
Hi, this is superb, thank you Remy.
Quick response to Alan and Markus's comments about the scrollbar appearing above the images in IE7.
If you just play with the css to fit your own design you will be able to easily overcome this problem.
Alternatively for testing purposes, you could simply add a blank tag () above the slider class in the html. This should do the trick.
Cheers,
Simon B
April 24, 2008 at 10:27
ammendment to last post . . . it should read a blank div tag.
April 25, 2008 at 17:19
Hi Remy. Great tutorial! I not speak english very well. I have a question for you, how put text on [<div id"sliderGallery" - <ul></ul>] not images only text content. I experiment but not work very well. I need change the css codign? Please, help me.
Thank you so mouch.
Abraços from Brazil,
Dan
May 6, 2008 at 17:47
Hi,
First, thanks for the excellent tutorial!
I think I've found a solution for the problem that some of the earlier posters mentioned with the slider/handle positioning in IE6/7. In the CSS, if you change this:
.slider { width: 542px; height: 17px; margin-top: 140px; margin-left: 5px; padding: 1px; position: relative; background: url(images/productbrowserscrollbar20070622.png) no-repeat; }
to this:
.slider { width: 542px; height: 17px; padding: 1px; position: relative; top:140px; left:5px; background: url(images/productbrowserscrollbar20070622.png) no-repeat; }
It should fix the problem.
In terms of a wishlist for improvements, I'd love it if the size (width) of the slider handle adjusted automatically based on how many items are in the carousel. But that's for someone smarter than me to figure out.
Cheers!
May 6, 2008 at 19:15
Does the window.onload function conflict with the $(window).ready event handler? I've noticed that in some libraries it will... I just haven't tried it yet...
May 7, 2008 at 22:50
@Chris - the answer is yes, but in fact the best method is to use
$(window).readysince this is different from$(document).readybecause it fires once the images are loaded - which is what we want (I only recently found this out).