Search

Coda Slider Effect

Posted on 3rd June 2008 — Although Panic didn’t really invent the effect, the sliding panels on the Coda is great implementation of this effect.

This article will pick apart the pieces required to create the effect, and how to better it.

How to Solve the Problem

Recreating this effect is simple to do if you know what plugins to use. There are plugins out in the wild already, but we want our jQuery to satisfy the following requirements:

  1. Degrades perfectly without JavaScript enabled
  2. Sliding panels effect without hogging browser CPU
  3. Next and previous buttons added using JavaScript because they hold no use without JavaScript
  4. Hitting the page with a specific hash (i.e. page.html#preview) shows the right tab, and highlights the right navigation
  5. Any link on the page that refers back to a panel should trigger the effect and highlight the right navigation - this should happen without any extra work

The hash is the emphasised part (including the # symbol) in: http://jqueryfordesigners.com/page.html#example

In fact, our version of this slider will be better than Panic’s and the current jQuery plugins if we can meet all of the requirements.

For example, in the Panic example linking directly to the preview pane doesn’t correctly highlight the navigation.

This whole solution is going to rely heavily on Ariel Flesler’s scrollTo plugin and particularly it’s ‘adapters’ to enhance the power of the scrollTo plugin.

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 coda slider effect screencast (alternative flash version)

QuickTime version is approx. 90Mb, flash version is streaming - I’ve also noticed the sound is slightly over to the left - I’ll fix that for next time!)

View the demo and source code used in the screencast

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

Requirement 1: degrades perfectly without JavaScript enabled

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:

<div id="slider">
  <ul class="navigation">
    <li><a href="#sites">Sites</a></li>
    <li><a href="#files">Files</a></li>
    <li><a href="#editor">Editor</a></li>
    <li><a href="#preview">Preview</a></li>
    <li><a href="#css">CSS</a></li>
    <li><a href="#terminal">Terminal</a></li>
    <li><a href="#books">Books</a></li>
  </ul>

  <!-- element with overflow applied -->
  <div class="scroll">
    <!-- the element that will be scrolled during the effect -->
    <div class="scrollContainer">
      <!-- our individual panels -->
      <div class="panel" id="sites"> ... </div>
      <div class="panel" id="files"> ... </div>
      <div class="panel" id="editor"> ... </div>
      <div class="panel" id="preview"> ... </div>
      <div class="panel" id="css"> ... </div>
      <div class="panel" id="terminal"> ... </div>
      <div class="panel" id="books"> ... </div>
    </div>
  </div>
</div>

That’s it. Without CSS this markup works perfectly for our content, almost exactly the way tabs work without JavaScript and CSS.

CSS

I won’t detail all the CSS like the navigation or shading effects - just the CSS required to correctly create the effect.

#slider {
  width: 620px;
  margin: 0 auto;
  position: relative;
}

.scroll {
  height: 250px;
  overflow: auto;
  position: relative; /* fix for IE to respect overflow */
  clear: left;
  background: #FFFFFF url(images/content_pane-gradient.gif) repeat-x scroll left bottom;
}

.scrollContainer div.panel {
  padding: 20px;
  height: 210px;
  width: 580px; /* change to 560px if not using JS to remove rh.scroll */
}

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:

.scrollButtons {
  position: absolute;
  top: 150px;
  cursor: pointer;
}

.scrollButtons.left {
  left: -20px;
}

.scrollButtons.right {
  right: -20px;
}

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).

Required Plugins

<script src="jquery-1.2.6.min.js" type="text/javascript"></script>

<script src="jquery.scrollTo-1.3.3-min.js" type="text/javascript"></script>
<script src="jquery.localscroll-1.2.5-min.js" type="text/javascript"></script>
<script src="jquery.serialScroll-1.2.1-min.js" type="text/javascript"></script>

Next and Previous Buttons

Requirement 3: Back and forward buttons added

This is easy vanilla jQuery, here’s the snippet from the final code:

var $scroll = $('#slider .scroll');

$scroll
  .before('<img class="scrollButtons left" src="images/scroll_left.png" />')
  .after('<img class="scrollButtons right" src="images/scroll_right.png" />');

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.

// bind the navigation clicks to update the selected nav:
$('#slider .navigation').find('a').click(selectNav);

// handle nav selection - lots of nice chaining :-)
function selectNav() {
  $(this)
    .parents('ul:first') // find the first UL parent
      .find('a') // find all the A elements
        .removeClass('selected') // remove from all
      .end() // go back to all A elements
    .end() // go back to 'this' element
    .addClass('selected');
}

function trigger(data) {
  // within the .navigation element, find the A element
  // whose href ends with ID ($= is ends with)
  var el = $('#slider .navigation').find('a[href$="' + data.id + '"]').get(0);
  
  // we're passing the actual element, and not the jQuery instance.
  selectNav.call(el);
}

I’ve had to separate out the selectNav function because it also be called when the user clicks on the navigation links.

To complete this requirement, once the page is loaded, we need to check whether there is a hash on the URL, and if so, trigger the ’scrollerComplete’ function:

if (window.location.hash) {
  trigger({ id : window.location.hash.substr(1)});
} else {
  $('#slider .navigation a:first').click();
}

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.

Related posts

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>Better Coda Slider</title>
<link rel="stylesheet" href="coda-slider.css" type="text/css" media="screen" title="no title" charset="utf-8">

<script src="jquery-1.2.6.js" type="text/javascript"></script>
<script src="jquery.scrollTo-1.3.3.js" type="text/javascript"></script>
<script src="jquery.localscroll-1.2.5.js" type="text/javascript" charset="utf-8"></script>
<script src="jquery.serialScroll-1.2.1.js" type="text/javascript" charset="utf-8"></script>
<script src="coda-slider.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
    <div id="wrapper">
        <h1>jQuery Coda Slider</h1>
    
        <div id="intro">
            <p>This technique demonstrates an accessible 'Coda'-like slider interface, but in addition, allows you to place links to the sliding content anywhere on the page and have the effect (and navigation) still work. <br /><a href="http://jqueryfordesigners.com/coda-slider-effect">Read the article, and see the screencast this demonstration relates to</a></p>
        </div>
    
        <div id="slider">    
            <ul class="navigation">
                <li><a href="#sites">Sites</a></li>
                <li><a href="#files">Files</a></li>
                <li><a href="#editor">Editor</a></li>
                <li><a href="#preview">Preview</a></li>
                <li><a href="#css">CSS</a></li>
                <li><a href="#terminal">Terminal</a></li>
                <li><a href="#books">Books</a></li>
            </ul>

            <div class="scroll">
                <div class="scrollContainer">
                <div class="panel" id="sites"><h2>Sites</h2><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>
                <div class="panel" id="files"><h2>Files</h2><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>
                <div class="panel" id="editor"><h2>Editor</h2><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>
                <div class="panel" id="preview"><h2>Preview</h2><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>
                <div class="panel" id="css"><h2>CSS</h2><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>
                <div class="panel" id="terminal"><h2>Terminal</h2><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. <a href="#sites">And some sites</a></p></div>
                <div class="panel" id="books"><h2>Books</h2><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>
                </div>
            </div>

            <div id="shade"></div>
        </div>

        <p>Lorem ipsum dolor sit amet, <a href="#books">books</a> consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco <a href="#sites">sites</a> laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure <a href="#terminal">terminal</a>  dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        
    </div>
</body>
</html>

Comments

  1. Sean Wright On 6th May 2009 at 13:05

    Nice widget! I love it. I DO have a question though. It seems that the container is of fixed width and height. Is there any way to allow the height to adjust to the content?? I don’t want to necessarily have a fixed height. Are scrollbars a possibility?

    Thanks!

  2. Hans van Wijk On 11th May 2009 at 19:05

    First of all, great site and tutorials…Thank you it is really useful.

    I implemented the coda slider inside one of my websites. I use it so people can watch different Youtube video’s of ongoing projects. It works fine in all major browsers except Opera.

    The overflow:hidden property seems to be useless in combination with flash movies resulting them to break out from the container div.

    I’m aware this is most likely a css problem, but i can’t find a solution for it.

    Can you help me with this one or do you know a solution.

  3. Chris On 14th May 2009 at 01:05

    I’m implementing this on one of my internal sites but having difficulty with the CSS and IE7. Taking the code as is and just modifying the internal content works great in FF, but IE7..not so much. The divs are the same as the demo. The id’s are the same too. So is the CSS. But, in IE7, the content scrolls up and down instead of left/right. FF scrolls it correctly, left and right. Is there something I need to look at in the CSS to keep get IE to behave properly?

    thanks!

  4. ose On 18th May 2009 at 05:05

    I can make the links that triggers the sliding effect just fine, but it doesnt seem to work using a flash button. any ideas?

  5. lou On 18th May 2009 at 08:05

    Great tutorial and demo, found it very helpful in implementing the slider.. I did encounter one problem, in IE and Firefox, slider is normal.. when I test it in Chrome.. the panels slide vertically instead of horizontally, any ideas?

    thanks Lou

  6. Art Insane On 19th May 2009 at 18:05

    Nice one… it really helped me a lot to design my website…

  7. Holly Feldbruegge On 20th May 2009 at 13:05

    This looks very professional…I really enjoyed the tutorial.

  8. Nathan On 22nd May 2009 at 06:05

    Great! Really well explained and just all round bloody tops!

    Thanks mate

  9. David Strang On 23rd May 2009 at 10:05

    Is there any way to have the page load on a specified panel other than the first one? I have a slider on my home page and I would like the third panel to be the starting position.

  10. Julio On 23rd May 2009 at 20:05

    I really love this tutorial… I was able to get it down… but my next step is being able to add another scroller - I’m working on a project and I want to have two scrollers but everytime I adjust it, the links always apply to the 1st scroll and not the 2nd. Even though I change the reference ID’s, it still doesn’t know that I have a secondary box that I want it to control. Any help please?

  11. Jonathan Lyon On 24th May 2009 at 10:05

    Hi I’m hoping you can help me out with an issue I’m having using coda slider in Wordpress. Basically I have a panel with 4 tabs on and when a user clicks on any given tab, I wish to load a specific sidebar.

    However I am unable to determine the current tab using php. I managed to create a hacked solution but that is causing issues of it’s own.

    In essence, I want to do this:-

    1. if tab #1 is selected then load sidebar1
    2. if tab #2 is selected then load sidebar2

    What I did was to pass a variable to the url instead f a hash tag that said ?tab= n but doing this causes the whole panel to reload everytime a click is executed.

    Here’s the example http://www.imashdigital.com/home/ (click on any of the 4 tabs)

    I guess this work if it didn’t reload each time a tab was clicked.

    I would be eternally grateful if you could help.

    Thanks

    Jonathan

  12. Edo On 25th May 2009 at 13:05

    Great effect, I think. Does anyone know of a Joomla or Wordpress template that uses this effect?

    Edo

  13. lpearce On 26th May 2009 at 12:05

    Hi,

    I too am looking for a solution to the problem of multiple coda sliders on one page. If we can get this working, this will solve alot of our content chunking, usability/readability issues!

    Anyone cracked this yet? Would love to see this working.

  14. Michael On 26th May 2009 at 23:05

    Hello there… I see that this is degrading in IE 8 with a default install.(Scroll bar is showing). Any ideas how to avoid this?

  15. Michael Sabelli On 27th May 2009 at 00:05

    I’m adding to my previous comment.. I noticed Lee Smith’s version is working fine in IE8: http://www.devsmith.com/sandbox/coda/

    I copied and tested with his Javascript and it is still degrading in IE8???? Any insight would be greatly appreciated.

    Thank you

  16. Jacob Abshire On 28th May 2009 at 06:05

    This tutorial is quite helpful. I was wondering a few things that you may be able to help me with. I wanted to the navigation anchors to execute the slide on the mouseover (hover) instead of the click. I tried changing the line: $(’#slider .navigation’).find(’a').click(selectNav) to work on the hover, but that didn’t work. What would you recommend?

  17. Matt On 31st May 2009 at 16:05

    Is it possible to use this tutorial for a commercial website. What are the restrictions?

  18. Christian On 6th June 2009 at 16:06

    Hi Remy,

    what if I wanted to link to a panel from another page? How could I accompish that?

    Thanks in advance and also thanks for the brilliant tutorial. Learned a lot!!

    Ciao, Christian]

  19. David Anderson On 9th June 2009 at 15:06

    I’m wondering about embedding a Flash video on a page that’s in the scroller. When I do that, the video appears off to the right or the left of the page. Is there a way to make it disappear, or perhaps scroll beyond the width of the screen?

  20. Ivan On 11th June 2009 at 00:06

    I think it is fantastic that you added support for vertical sliding. But, for a n00b like me, I can’t see where I need to change the code to achieve the vertical slide. I would imagine it would say something like scrollDirection = x then I would change the x to y. It apparently is slightly more involved than that. Please help :)

  21. Sean On 11th June 2009 at 14:06

    Hey,

    Just checking to see if anyone had had any luck with the following two options:

    1) Start at a specified slide, rather than the first one (perhaps at random) 2) Change the duration of the slide when it cycles back to the first one, so that the user doesn’t see the entire scrolling back to the beginning, but it looks like it just restarts

    Otherwise, this is a great script, and I’m enjoying working with it!

  22. Marty On 11th June 2009 at 21:06

    This is a great adaptation of the Coda concept. I’ve got it implemented here:

    http://www.platypus-ad.com/new2009/about/team-platypus/

    Works great in FF and Safari, but gets all wonky in IE6. The movement doesn’t work, and it seems that the CSS is all shifted. I’m slowly trying to isolate any issues and fix them. Any help would be much appreciated. Thanks.

  23. David Wallach On 14th June 2009 at 03:06

    Is there a fix in the works for the ‘panels’ not sliding into a centered position when the text is zoomed? I’ve noticed this bug in FF 3.x and Chrome 2.x.

  24. Mike On 15th June 2009 at 20:06

    Thanks for the demo. The slider is great. I’ve noticed that there has been numerous requests for multiple sliders on the page. Has anyone figured this out yet? I’ve been unsuccessful to this point and any help would be greatly appreciated.

    Thanks

    Mike

  25. Matt On 18th June 2009 at 18:06

    Hi,

    Nice Tut.

    1 Question, Would it be possible to place the navigation outside the slider?

    Thanks

    Matt.

Leave your own comment
  • http://