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!
You should follow me on Twitter here I tweet about jQuery amongst the usual tweet-splurges!
Related screencasts
Demo
If you find this demo doesn't work as expected, it's possibly due to the demo running from within an iframe. Try running the demo in it's own window.
Source Code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Slider Gallery</title>
<style type="text/css" media="screen">
<!--
body {
padding: 0;
font: 1em "Trebuchet MS", verdana, arial, sans-serif;
font-size: 100%;
background-color: #212121;
margin: 0;
}
h1 {
margin-bottom: 2px;
}
#container {
background-color: #fff;
width: 580px;
margin: 15px auto;
padding: 50px;
}
/* slider specific CSS */
.sliderGallery {
background: url(http://static.jqueryfordesigners.com/demo/images/productbrowser_background_20070622.jpg) no-repeat;
overflow: hidden;
position: relative;
padding: 10px;
height: 160px;
width: 560px;
}
.sliderGallery UL {
position: absolute;
list-style: none;
overflow: none;
white-space: nowrap;
padding: 0;
margin: 0;
}
.sliderGallery UL LI {
display: inline;
}
.slider {
width: 542px;
height: 17px;
margin-top: 140px;
margin-left: 5px;
padding: 1px;
position: relative;
background: url(http://static.jqueryfordesigners.com/demo/images/productbrowser_scrollbar_20070622.png) no-repeat;
}
.handle {
position: absolute;
cursor: move;
height: 17px;
width: 181px;
top: 0;
background: url(http://static.jqueryfordesigners.com/demo/images/productbrowser_scroller_20080115.png) no-repeat;
z-index: 100;
}
.slider span {
color: #bbb;
font-size: 80%;
cursor: pointer;
position: absolute;
z-index: 110;
top: 3px;
}
.slider .slider-lbl1 {
left: 50px;
}
.slider .slider-lbl2 {
left: 107px;
}
.slider .slider-lbl3 {
left: 156px;
}
.slider .slider-lbl4 {
left: 280px;
}
.slider .slider-lbl5 {
left: 455px;
}
-->
</style>
<!-- updated to jQ 1.2.6 and UI 1.5.2 2008-11-28 -->
<script src="jquery-1.2.6.js" type="text/javascript" charset="utf-8"></script>
<script src="jquery-ui-full-1.5.2.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
window.onload = function () {
var container = $('div.sliderGallery');
var ul = $('ul', container);
var itemsWidth = ul.innerWidth() - container.outerWidth();
$('.slider', container).slider({
min: 0,
max: itemsWidth,
handle: '.handle',
stop: function (event, ui) {
ul.animate({'left' : ui.value * -1}, 500);
},
slide: function (event, ui) {
ul.css('left', ui.value * -1);
}
});
};
</script>
</head>
<body>
<div id="container">
<h1>Slider Gallery</h1>
<p>This shows a demonstration of a slider widget from the jQuery UI library used to create the same effect used on <a href="http://www.apple.com/mac/">Apple's web site</a>.</p>
<p><a href="/slider-gallery">Read the article, and see the screencast this demonstration relates to</a></p>
<div class="sliderGallery">
<ul>
<li><img class="pb-airportexpress" src="http://static.jqueryfordesigners.com/demo/images/pb_airport_express.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_airport_extreme.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_timecapsule_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_keyboards20070807.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_mighty_mouse.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_cinema_display20071026.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_mac_pro_20070622.jpg" /></li>
<li><img class="pb-macmini" src="http://static.jqueryfordesigners.com/demo/images/pb_mac_mini.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_macbook20071026.jpg" /></li>
<li><img class="pb-macbookair" src="http://static.jqueryfordesigners.com/demo/images/pb_macbookair_20080115.jpg" /></li>
<li><img class="pb-macbookpro" src="http://static.jqueryfordesigners.com/demo/images/pb_macbook_pro20071026.jpg" /></li>
<li><img class="pb-imac" src="http://static.jqueryfordesigners.com/demo/images/pb_imac20071026.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_macosx_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_ilife_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_dot_mac_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_iwork_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_quicktime.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_aperture20080212.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_final_cut_studio2_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_final_cut_express_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_logic_studio_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_logic_express_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_shake_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_apple_remote_desktop_20080115.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_xserve.jpg" /></li>
<li><img src="http://static.jqueryfordesigners.com/demo/images/pb_xserve_raid.jpg" /></li>
<li><img class="pb-xsan" src="http://static.jqueryfordesigners.com/demo/images/pb_xsan_20080115.jpg" /></li>
<li><img class="pb-macosxserver" src="http://static.jqueryfordesigners.com/demo/images/pb_macosx_server20071016.jpg" /></li>
</ul>
<div class="slider">
<div class="handle"></div>
<span class="slider-lbl1">Wi-Fi</span>
<span class="slider-lbl3">Macs</span>
<span class="slider-lbl4">Applications</span>
<span class="slider-lbl5">Servers</span>
</div>
</div>
</div>
</body>
</html>

Play QuickTime version
Play Flash version

Chris Carvache On 6th May 2008 at 19:05
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…
Remy On 7th May 2008 at 22:05
@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).Erik On 18th May 2008 at 14:05
Hi! I love that tutorial. Can you make a “full code” of this? Or even a .zip-file for download?
I love that script, but I set it up, and it woudnt work.
:)
Toan On 21st May 2008 at 15:05
Awesome job!
After watching your screencasts, i don’t think it “Simple stuff.” anymore
Axel On 23rd May 2008 at 14:05
It tooks me quite a long time to make that work. I figured out why: as overflow:none is not a valid CSS property, I replaced it with overflow: hidden. This was working on FF3 and Safari but not on FF2 or IE7
Thks
Axel
Abdel Olakara On 3rd June 2008 at 04:06
Great tutorial! Thanks
Mark On 5th June 2008 at 17:06
How do you make this thing auto scroll initially?
Don On 5th June 2008 at 18:06
thanks for this man; i recently started to learn JS and tutorials like this make it so much easier
tanicos On 12th June 2008 at 02:06
hey nice one take a look of mine http://www.tanicos-webbdesign.com/forums/
Christoph On 16th June 2008 at 09:06
To make it work with the new UI-Release, change the params
“minValue” and “maxValue” in the options to “min” and “max”
just a tip :)
greetings from germany.
nice tutorial, thank you!
Lars On 18th June 2008 at 12:06
Thank you for this great tutorial!
Is it somehow possible to start with an initial value for the slider or the list? Just like http://www.apple.com/mac/ where it starts with “Macs”?
Lars On 18th June 2008 at 13:06
Ok, got it:
$(’div.slider’,container).slider(”moveTo”,”250px”);
Rob C On 21st June 2008 at 20:06
Excellent tutorial!!!
I am just getting into jquery and am absolutely loving it. It’s great to have such extensive tutorials like this around on the web.
Your time taken to put such tutorials and code together is greatly appreciated!
R.
Val On 24th June 2008 at 16:06
Great Job! Thanks for posting this.
Has anyone used this slider gallery together with traditional expandable menus. In other words, use the slider to scroll through all first level menu categories and then click on one to see it drop down and display the 2nd level for the selected menu?
Thanks, S.
k3k On 1st July 2008 at 07:07
Very interesting tutorial. JQuery it’s a fantastic solution for unobtrusive javasript.
Thanks
Andrea Vit On 1st July 2008 at 08:07
That’s a fantastic solution for developing emotional navagation system without using Flash. It’s a technique that provides Search Engine Optimization and accessibility. Great job! Greetings from Italy!
jp kelly On 2nd July 2008 at 03:07
I am trying to figure out how to have the page open with the slider in a certain position. I am guessing that I should use the moveTo (class? function?) from ui.slider.js but i don’t know the syntax to call it. A bit of a js newbie here.
jp kelly On 2nd July 2008 at 04:07
I see Lars says to use
$(’div.slider’,container).slider(”moveTo”,”250px”);
but I am not sure how or where to use it.
jp kelly On 2nd July 2008 at 04:07
I see Lars wrote to use
$(’div.slider’,container).slider(”moveTo”,”250px”);
I am not sure how or where to use it. Help?
Lars On 14th July 2008 at 10:07
Instead of “250px” you could also use “container.outerWidth() / 2″ for example. This would move the Gallery to its middle…
geezi On 15th July 2008 at 14:07
Hi,
I am using this script for a page but with a small description below each image. The moment we add block elements (div / p / h1?) the script goes haywire. Without a block element I cant add the width property within which the text will flow. Any suggestions?
Remy plspls reply to this one!
Kyle On 15th July 2008 at 20:07
Hey Guys/Girls-
Just wanted to share two fixes I made when doing my iteration of the drawer for my project (see site).
1) I use MooTools for my left sidebar accordion but that library was interfering with jQuery. All I had to was change all occurrences of “$” with “jQuery” in the internal javascript. Simple fix.
2) Firefox 2 wouldn’t show my entire UL for some reason. So I just applied “width: 1550px;” to “.sliderGallery UL” to get it to work.
Thanks to the author of this tutorial. I made sure to credit you in my global credits file.
~Kyle~
caruso_g On 18th July 2008 at 17:07
Hi there, which components should I select with new jQuery UI download builder? http://ui.jquery.com/download_builder/
Andy Davis On 22nd July 2008 at 19:07
Has anyone gotten this script to work in IE6?
Chris On 28th July 2008 at 14:07
Anyone having trouble with IE7? The slider handle moves but the gallery images do not. I made several adjustments already mentioned above (’overflow:none’ changed to ‘overflow:hidden’ and minValue/maxValue changed to min/max). Oddly enough, it works in IE6, FF, and Safari. Thanks!