Vanilla JavaScript Slideshows

Display mode

Back to Articles

Many sites introduce a dynamic element to their content by including a "slide-show" subsection: a list of items or pictures which can be scrolled through and viewed in portions, and which repeats to the first item when the last item is visible. An example of such a slide-show is show below.

«
  • Al-Qaeda 'kills British hostage'
    03 June 2009 09:47
    Downing Street says there is "strong reason to believe" that a British citizen has been killed by al-Qaeda militants in Africa.
  • Government still working - Harman
    03 June 2009 10:07
    Harriet Harman hits back at claims the government is in its "death throes" after ministers' decisions to stand down.
  • Broadband 'essential' to UK
    03 June 2009 02:24
    Consumers consider broadband internet as important a utility as water or electricity, a government advisory panel finds.
  • Obama embarks on Mid-East mission
    03 June 2009 04:03
    President Barack Obama heads to the Middle East on a visit aimed at increasing US engagement with the Islamic world.
»
Figure 1: Slide-show in use as a news ticker

In the above sample, the window is controlled by left and right anchors, which each give a direction for the window to move in by one step. It may seem complicated to implement such a slide-show, but this article will show you the basic pieces of code that go into making the slide-show work.

Viewing the world though a window

In order for the slide-show to operate, it's important to conceptualise what must be achieved. Each item in the section is joined horizontally to the next, to form a line of items. The user will see this line through a "window" which slides over the line, making a small portion visible.

Window over the items
Figure 2: Items seen through a window

The task of the slide-show is to control where this window lies, and when to move it. This can be achieved through simple use of HTML and JavaScript: a DIV block will act as the window, and the list of items is contained within the window.

HTML for window and list

<div id="window" style="overflow:hidden">
 <ul>
  <li><img src="item1.jpg"></li>
  <li><img src="item2.jpg"></li>
  <li><img src="item3.jpg"></li>
  <li><img src="item4.jpg"></li>
  <li><img src="item5.jpg"></li>
 </ul>
</div>

The inline style placed on the window DIV demonstrates what will occur if the window is set to be a smaller width than the list contained within: the remainder of the list will be cut-off, and hidden from view.

Moving the window

In order to move the window over the list of items, repeated small steps must be taken: moving the window in one operation will result in a simple change of view, as opposed to the desired slide. This effect of repeated steps can be achieved by the judicious use of timeouts: the function responsible for making a small step sets a timer which will, after a short while, run the same function again to make the next step.

For this to work properly, the function must be able to detect when a full item has been scrolled into view, and it's time to stop moving further. In this article, I'll assume that the items in the list are all the same width, and that this width has been defined for the JavaScript function; it's possible, though more time-consuming, to record the positions of the list items in relation to each other, and detect the edge of an item by checking the window position against these item positions.

Moving the window over the list

timestep = 50;
pos = 0;
posstep = 4;
curtravel = 0;

step = function()
{
  timer = setTimeout(function(){step();}, timestep);
  curtravel += posstep;
  if(curtravel >= itemwidth)
  {
    curtravel = 0;
    clearTimeout(timer);
  }

  pos += posstep;
  if(pos >= listwidth) pos = 0;
  document.getElementById('window').style.left = pos+'px';
};

Note that in the above code, the window movement code will detect whether the window has reached the end of the list; if so, it will wrap to the start, and the first item will again be displayed.

Wrapping the list items

A problem presents itself with this simple approach: when approaching the end of the list, blank areas are shown before the first item appears once more. This is because the window is being positioned such that a part of it is past the end of the list, whereas the first item of the list is (as expected) at the start.

Non-wrapping list
Figure 3: Window positioned past the end of the list

This issue can be alleviated by repositioning the items in the list, to allow for the first item to be rendered after the end of the list, and thus for the window to encapsulate the area while showing that the list is wrapping to the start. In order to do this, the items in the list must have their positions checked for each step through the movement of the window: if the item is positioned on the "wrong" end of the list to the window movement, it must be moved to the other side.

CSS to allow for movement of list items

#window ul {
  position: relative;
}

#window li {
  position: absolute;
}

Step function including item repositioning

step = function()
{
  /* Initialise a timer, to do the step after this one */
  timer = setTimeout(function(){step();}, timestep);

  /* Set the window's new position */
  pos += posstep;
  if(pos >= listwidth) pos = 0;

  /* Check each item in the list, to see if it's outside the bounds of the window
     and if so, move it to the other side of the window to allow for scroll-in */
  items = document.getElementById('window').getElementsByTagName('ul')[0].getElementsByTagName('li');
  for(var i=0; i<items.length; i++)
  {
    if(pos >= 0)
    {
      itempos = i*itemwidth;
      if(itempos+pos > windowwidth)
        itempos -= listwidth;

      if(iempos+pos < -(windowwidth+itemwidth))
        itempos += listwidth;

      items[i].style.left = itempos+'px';
    }
  }

  /* Check if we're at the end of a scroll; if so, stop the timer */
  curtravel += posstep;
  if(curtravel >= itemwidth)
  {
    curtravel = 0;
    clearTimeout(timer);
  }

  /* Set the new window position */
  document.getElementById('window').style.left = pos+'px';
};

Moving both ways

The above code allows for the window to move rightwards over the list, which corresponds to a visual effect of pushing the list off-screen to the left, and bringing more items on-screen from the right. It's important that the code also allow for items to be scrolled to the right, which would involve moving the window leftwards over the list. This can be achieved by modifying the step function somewhat, to include clauses for the reverse direction of travel.

Step function allowing for reverse travel

step = function(stepdir)
{
  timer = setTimeout(function(){step(stepdir);}, timestep);
  items = document.getElementById('window').getElementsByTagName('ul')[0].getElementsByTagName('li');

  if(stepdir < 0)
  {
    /* Handle moving the window left; the same as before, but
       with all the comparison and addition signs flipped */
    pos -= posstep;
    if(pos <= listwidth) pos = 0;

    for(var i=0; i<items.length; i++)
    {
      if(pos <= 0)
      {
        itempos = i*itemwidth;
        if(itempos+pos < -listwidth)
          itempos += listwidth;

        items[i].style.left = itempos+'px';
      }
    }
  }
  else
  {
    /* Handle moving the window right; this code is the same as before */
    pos += posstep;
    if(pos >= listwidth) pos = 0;

    for(var i=0; i<items.length; i++)
    {
      if(pos >= 0)
      {
        itempos = i*itemwidth;
        if(itempos+pos > windowwidth)
          itempos -= listwidth;

        if(iempos+pos < -(windowwidth+itemwidth))
          itempos += listwidth;

        items[i].style.left = itempos+'px';
      }
    }
  }

  curtravel += posstep;
  if(curtravel >= itemwidth)
  {
    curtravel = 0;
    clearTimeout(timer);
  }

  document.getElementById('window').style.left = pos+'px';
};

Now all that must be remembered is that moving left entails a positive step direction, and that moving right is a negative step direction.

Caveats and extensions

In principle, it's quite easy to adapt this slideshow to travel vertically instead of horizontally. However, the fact that this system relies on a fixed width for each list item is a disadvantage when it comes to vertical travel: as can be seen in the above sample, items will differ in height depending on their content.

To alleviate this, the system previously mentioned can be employed: a list is maintained of the positions of the items in the list, and these are used to check the bounds of the window. If an item's initial position combined with the window's position is outside the window, this will force it to move to the other side of the list.

This system can easily be extended to allow for image slideshows, by changing the contents of the list to a list of images of the same width; be combining the images with anchors, a thumbnail slideshow can be created. Feel free to extend the code to your heart's content.

Imran Nazar <tf@imrannazar.com>, 2009