Plugins Required

Along with jQuery we’ll need the following plugins – I recommend using the minified versions for production, and perhaps even development (download links can be found at the bottom of the linked pages):

Markup

To ensure this works without JavaScript, we will use the CSS overflow property to control the effect.

This way our panels will still focus in to view if a user clicks, or if the URL refers to a specific panel.

HTML

It’s worth noting that although we could scroll the individual panels inside a single nested DIV, for the JavaScript to make the effect work, it will be a nested DIV that will scroll – not the individual panels. You can see this in the markup below:

Note also that I’m choosing to use overflow: auto; – this way, if the user does have JavaScript disabled, there will be a visual que that the panels can be scrolled. If you want to remove the horizontal scroll in IE, I would recommend changing .scrollContainer div.panel‘s width to 560px to account for the right hand scrollbar.

I also plan to include scrolling buttons to go left and right. Although the elements will be created by the JavaScript, we’ll still need the CSS to place the buttons in the right place. Our JavaScript will put the buttons before and after the outer div.scroll element. We have to use absolute positioning to place them, so this is why #slider has position: relative; applied:

jQuery

Requirement 2: Sliding panels effect without hogging browser CPU

If you try this effect using CSS, to use positioning to move the panels around it will eat up your CPU, and the browser will no likely lock up. This is why we’re using Ariel’s scrollTo pluing. The scrollTo plugin literally scrolls the element via it’s overflow (or can be used to scroll the actual window).

Note the classes I’ve applied the scrollButtons to the images so they’ll be positioned properly.

Navigation Updates Automatically

Requirement 4: Hitting the page with a specific hash highlights the right navigation

This is one of the key features that I felt was important to the slider. If I navigated to a specific panel, the navigation should match.

This is achieved using event binding. When the scroll plugin completes it’s effect, it will call our trigger function.

The trigger function will receive the ID of the element it has just shown, and search for the navigation item whose href’s hash matches the ID.

For example, if the div#sites element is shown, the ID ‘sites’ is sent to our trigger. Our trigger function will now look for links in the navigation that end with ‘#sites’: <a href="#sites">Sites</a>.

This trigger function will be attached to the onAfter property in the scroll options and called when the page loads for the first time with a hash in the URL.

By default, we’re triggering a click to the first navigation item if there’s no hash on the URL.

Any Link Triggers Effect

Requirement 5: Any link on the page that refers back to a panel should trigger the effect

Since we’re all lazy developers, we don’t want to have to specifically markup arbitrary links on the page that should trigger this effect.

This is where Ariel’s localScroll plugin comes to the rescue. By just applying that plugin with our default settings any link on the page will trigger the effect. In addition, because we’re going to trigger our ‘scrollerComplete’ function when the effect has finished, it will correctly select the navigation associated.

The jQuery Code

Here’s the code with all the above requirements added in. The code is commented to explain what we’re doing.

I’ve also decided to include a bonus requirement – to support both horizontal or vertical scrolling.

// when the DOM is ready...
$(document).ready(function () {
var $panels = $('#slider .scrollContainer > div');
var $container = $('#slider .scrollContainer');
// if false, we'll float all the panels left and fix the width
// of the container
var horizontal = true;
// float the panels left if we're going horizontal
if (horizontal) {
$panels.css({
'float' : 'left',
'position' : 'relative' // IE fix to ensure overflow is hidden
});
// calculate a new width for the container (so it holds all panels)
$container.css('width', $panels[0].offsetWidth * $panels.length);
}
// collect the scroll object, at the same time apply the hidden overflow
// to remove the default scrollbars that will appear
var $scroll = $('#slider .scroll').css('overflow', 'hidden');
// apply our left + right buttons
$scroll
.before('<img class="scrollButtons left" src="images/scroll_left.png" />')
.after('<img class="scrollButtons right" src="images/scroll_right.png" />');
// handle nav selection
function selectNav() {
$(this)
.parents('ul:first')
.find('a')
.removeClass('selected')
.end()
.end()
.addClass('selected');
}
$('#slider .navigation').find('a').click(selectNav);
// go find the navigation link that has this target and select the nav
function trigger(data) {
var el = $('#slider .navigation').find('a[href$="' + data.id + '"]').get(0);
selectNav.call(el);
}
if (window.location.hash) {
trigger({ id : window.location.hash.substr(1) });
} else {
$('ul.navigation a:first').click();
}
// offset is used to move to *exactly* the right place, since I'm using
// padding on my example, I need to subtract the amount of padding to
// the offset. Try removing this to get a good idea of the effect
var offset = parseInt((horizontal ?
$container.css('paddingTop') :
$container.css('paddingLeft'))
|| 0) * -1;
var scrollOptions = {
target: $scroll, // the element that has the overflow
// can be a selector which will be relative to the target
items: $panels,
navigation: '.navigation a',
// selectors are NOT relative to document, i.e. make sure they're unique
prev: 'img.left',
next: 'img.right',
// allow the scroll effect to run both directions
axis: 'xy',
onAfter: trigger, // our final callback
offset: offset,
// duration of the sliding effect
duration: 500,
// easing - can be used with the easing plugin:
// http://gsgd.co.uk/sandbox/jquery/easing/
easing: 'swing'
};
// apply serialScroll to the slider - we chose this plugin because it
// supports// the indexed next and previous scroll along with hooking
// in to our navigation.
$('#slider').serialScroll(scrollOptions);
// now apply localScroll to hook any other arbitrary links to trigger
// the effect
$.localScroll(scrollOptions);
// finally, if the URL has a hash, move the slider in to position,
// setting the duration to 1 because I don't want it to scroll in the
// very first page load. We don't always need this, but it ensures
// the positioning is absolutely spot on when the pages loads.
scrollOptions.duration = 1;
$.localScroll.hash(scrollOptions);
});

Wrap UP

That’s everything you need for the perfect slider. Ariel has lots of other examples of how the scroll plugins can be used on his web site so do check them out.

I’ll also be posting a follow up to last month’s survey.

If anyone has any questions, suggestions or better examples, please do share by dropping a comment on the site.

You should follow me on Twitter hereI tweet about jQuery amongst the usual tweet-splurges!