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

Tyler On 8th October 2008 at 21:10
Hi, I’m getting a margin on the list items. I have set both the margin and padding to zero. It seems to be the white-space : nowrap that is causing it. I was wondering if there were any ways of getting rid of that?
Fredrik W On 9th October 2008 at 21:10
If you’re having trouble getting this to work with the latest jQ and the jQUI try the following:
maxValue and minValue have been changed to max and min, respectively.
The slide: function (ev, ui) { ul.css(’left’, ‘-’ + ui.value + ‘px’); } callback will cause your slider to jump before smoothly scrolling when you click somewhere in the scrollable area (without dragging). The following callback solves that:
slide: function (ev, ui) { ul.animate({’left’: -ui.value + ‘px’}, 1); },
yoni On 13th October 2008 at 21:10
this is great! is there any way to make the image slide to the next one when you click on it??
seo nedir On 20th October 2008 at 15:10
i have seen its similar from google’s teenth year page.
Jonathan Delves On 21st October 2008 at 14:10
Thanks for the tutorial, works really well and is REALLY easy to install, keep up the good work.
dix On 21st October 2008 at 15:10
download personalized jquery ui (core + slider)
modification to move incrementally: (see Yosh above)
$(".control.prev").click(function(){ $('.slider', container).slider("moveTo","-=250px"); });PoZel On 29th October 2008 at 09:10
thanks!!
everyones improvements and suggestions are great!
thanks to dix, RealtorBen, Leif Miltenberger and everyone else!
great tutorial!!!
Chad On 29th October 2008 at 14:10
Is it possible to drag and drop the images out of the slider i.e. into a cart? I have attempted this but it will not drag out of the sliderGallery div bc of the overflow: hidden style.
IC619 On 29th October 2008 at 18:10
This is a great script. But i’ve got a couple of issues:
In response to Anthony’s post ‘For a vertical slider, change var itemsWidth = ul.innerWitdth() - container.outerWidth(); to:
var itemsHeight = ul.innerHeight() - container.outerHeight();’
I am having trouble getting the above to work. If possible, can someone post the whole script with the necessary modificationso I can copy and modify it to my pwn needs?
Another question: Is there a way to put more than one of these sliders on a page. For instance, 3 per page, each one 50px below or besides the other?
Chris On 30th October 2008 at 02:10
In IE 7 the slider bar ignores the margin-top. Use (top: 100px;) instead, and it works in all browsers. :)
David.Wu On 5th November 2008 at 03:11
Hi Dear Remy it’s really an amazing blog and demonstration I got one question here, the slider does not consider the padding of the container, therefore, it will move to the left more than before, any solution?
nambi On 13th November 2008 at 10:11
excellent job… remy… keep it up. i haven’t tried this yet. But the way you explained is very good.
Notsuj On 26th November 2008 at 21:11
I have read a couple posts asking about compliance with Opera. I have gotten the script and CSS to perform exactly the same across all browsers (opera, ie6. ie7, ie8, ff, chrome).
The Problem from my end was an undefined ul width. If left undefined Opera will use a width based on the slider width and push any li elements down the frame (below the slider and partially out of view). For prototype reasons I have just defined the width based on the contents of the ul.
Domenic On 5th December 2008 at 20:12
I might have a solution for Opera users but it requires that you use jQuery 1.2.6 and jQuery UI 1.5.3. Using these versions would only require you to use “jquery-1.2.6.js” and “jquery.ui.all.js” within the “ui” section of jQuery UI 1.5.3.
The issue seems to be in jquery.ui.all.js within the Slider function. It appears to be a bind function found on line 6668. The “type” is entered as “mousedown” which works in FF 2+, IE 6+ and Safari 3.1.2 (all Windows XP SP3). However testing on Opera 9.02 produces an interesting result. Clicking on the “handle” will initially produce the desired result. However, releasing the handle and then clicking it once again causes the handle to remain static. Clicking anywhere else on the screen (other than the handle and slider) will allow you to once again click on the handle and operate it accordingly.
The current, albeit premature solution that I’ve come to appears to be changing the “bind type” to “click” within the Slider function on line 6668 once again. This produces the desired effect in all aforementioned browsers. Again though; I’ve done limited testing. I’m using browser detection to alter the function for Opera users only. Everyone else will still use the same function unaltered.
Domenic On 5th December 2008 at 20:12
Oh, and Remy, this is absolutely brilliant. Thank you very much!
studio On 6th December 2008 at 23:12
Hi! Thanks very much for this excellent jquery use. I’ve a problem with IE7. It works with FF2 FF3 ie6
IE7 only says : Argument not valid on line 1120 the line is this: elem[ name ] = value;
Please help me, I’ve spending a lot of time… googling… coding.. but I can’t fix it.
URL : http://estudio.seaweb.es/ecaps/Montaje%20Web/ I use jquery 1.2.6 Thanks again.
studio On 7th December 2008 at 00:12
Ufff! finally I fixed it!.
At some moment I replace the overflow: none with overflow:hidden like Alex… SO ALERT ! don’t change overflow:none; with overflow:hidden; Remove if you want but don’t change.
:)
Thanks.
Motiv Web Designs On 10th December 2008 at 01:12
Thanks for the informative post. I am going to have to try this out. I have basically been using plugins within my CMS to achieve this sort of gallery, but of course those are always limited to what that developer put into it. I hope to be able to customize my own with this technique. I will let you know how it turns out.
Physalia On 12th December 2008 at 18:12
Nice tutorial !
Is-it possible to add text behind each image of the slider ? I tried to put some text in the <li> but the scroller exploded…
Eric On 12th December 2008 at 20:12
Very nice. That is incredibly simple. Excellent tutorial. Nice job.
Chris Butchart On 23rd December 2008 at 11:12
-Remy, Great work. Very neat. Cheers. -Chad, I don’t know if you found the answer to your question, so I thought I’d try to help as I’ve just been through the same thing over the past couple of days. You need to change the “appendTo” property of the draggable element. By default jQuery appends the element to the parent of the original element. Add a new element to your page structure (setting a higher z-index than the other containers) and append the draggable to this element. You’ll also probably want to resize the elements in your source element area after you’ve dragged them onto your cart. The only way I found to do this was by destroying the slider and recreating. I don’t know if there is a better way to do this. Chris
bmatto On 15th January 2009 at 20:01
This is great!, I have a question … say I simplified the dimension part of the function to look something like
All I am wanting is to return the productWidth value for use elsewhere … how would I return that value outside of $()
pls help!
Tiago Ficagna On 23rd January 2009 at 18:01
Hi. Your script is superb. Works nice. Thanks for sharing this precious information!
Arjan On 24th January 2009 at 21:01
Hi all!
I need some help her, new to Jquery …. I got it all to work with jquery-1.2.6.js ….. but when I try to get it working with the current UI core and Widget slider in Stable mode (downlaoding jquery-ui-personalized-1.5.3.min.js) it doens’t seem to work …
So maybe someone could give a quick overview of the current teps to get this great effort working!
Tnx
Tom On 2nd February 2009 at 11:02
Nice tutorial!
One question I have is I need to be able to put text under the images (captions), similar to apples version. Is there away a to do this, whilst keeping the images inline?
Cheers Tom