The graphical news slider: something used often, everywhere, for everything. It was one of my first jQuery projects and one of my first tutorials. In a nutshell, this jQuery slider will take images and associated text, put them in a navigation bar, and periodically scroll through the images with slide-in or fade-in effects. The navigation bar may be hidden until the mouse enters the slider. The slides are set to change automatically every 7.5 seconds or when a slide is clicked.

View a live demo of the final product.

Preface

This tutorial was written in 2010 using jQuery 1.4.2. It supports Internet Explorer 6 and still functions the same to this day in modern browsers, as evidenced by the live demo above. Some of the coding examples put forth in the coming sections may not seem optimal, and you’re right. They do not make use of such technologies as flex boxes, alpha-opacity, or box-sizing. These simply did not exist at the time. However, as a result, this tutorial is backwards compatible by more than a decade. While I would no longer recommend a lot of these practices, there is no need to re-invent the wheel. The product in this tutorial is in working order and a rewrite would achieve nothing more than sacrificing backwards compatibility.

The HTML

Since the algorithms are dependent on the DOM structure, this will be a good place to start:

We wrap all of the elements in a div.news-slider element. Since we’ll be needing timeouts in JavaScript to change the background and text periodically, we will need a unique identifier ( div#news-slider1 , div#news-slider-2 , etc.) to refer to which slider needs to change from within the timeout.

div.padding is to prevent an error in older versions of Internet Explorer that before box-sizing was a CSS attribute, when this guide was originally written.

div.background2 is a dummy element used for transition effects. During transitions, two backgrounds are displayed: the new that is one coming into focus and the old one that is leaving. Thus, we’ll need two elements: div.background for the new background and div.background2 for the old background. Since div.background will be the new background that is in-focus, I’ve placed it after div.background2 . By placing it after (and then shifting it upward via the CSS top attribute), it will appear on top of div.background2 , thus hiding the old background when the new one comes into focus.

div.navigation.bar is merely a colored bar on top of which the navigation images appear. I gave it a separate element from the images themselves because it will be translucent, so the viewer is able to see the background image of div.background . I did not place the images inside div.navigation.bar , because I did not want the images to be translucent. Again, this guide was written for an era before alpha-opacity background colors were possible. Therefore, like with div.background , I placed the images in the proceeding element, then visually shifted them on top of div.navigation.bar . Since div.navigation.bar and div.navigation.icons share so many attributes (height, width, position), I gave them the common class .navigation . The separate class .bar is used for coloring the navigation bar, while .icons is unused and merely there for convenience of anyone who wants to stylize it.

img.image# are semi-unique class names that will be used in jQuery to gather information about the image, e.g. its src via $('#news-slider-1 img.image1').attr('src') . I say semi-unique, because it is not unique to the page (therefore using class instead of ID), merely unique to the slider. Each slider only has one .image1 , one .image2 , etc.

div.text is the text that will display. The div element inside of it is similar to div.padding . Oddly enough, it is not to appease Internet Explorer, but to appease jQuery. In order to position div.text toward the bottom or right of div.news-slider , we will need to know its widths and height. Unfortunately, jQuery does not include border or padding in its calculations of width and height, thus will not calculate the visible width and height of the element, thus not position div.text where we want to position it. To fix this, we use a div element inside of div.text for border and padding. This will cause div.text to stretch and the .width() and .height() of div.text to change, incorporating the border and padding of its inner div.

The CSS

Now that you know what the elements are, we must set their default styles to position them appropriately!

The attributes of the slider itself are pretty self-explanatory. margin: 0 auto; is to center it. If you are using multiple news sliders with multiple widths, use #news-slider-1 , #news-slider-2 , #news-slider-3 , etc. to set the height and width values.

The two backgrounds are very similar elements and thus have the same attributes. We don’t want the background to repeat so that we can see both at the same time. If the background repeated, we would just see the one positioned on top of the other. The bottom margin must be set to the negative of the height. This will “pull” anything below it on top of it, essentially giving it a “height” of 0, even though it is still visible. Therefore, div.background2 ’s negative margin-bottom will cause div.background to render on top of it, while div.background ’s negative margin-bottom will cause div.navigation.bar to render on top of it.

Here we have the shared attributes of the navigation bar and its icon wrapper. The height is the same as the background height. The position is relative so that it can be placed on the left or right of the slider. The bottom margin “pulls” div.navigation.icons on top of div.navigation.bar and div.text on top of div.navigation.icons . The centered alignment centers the images in div.navigation.icons . The width can be whatever you like.

The background color of the navigation bar. You can also use a background image if you want, but keep in mind that it will translucently overlay div.background .

These are the attributes of the images in the navigation bar. The height and width are based on how many images are going to appear in the bar. This takes a bit of calculation to determine:

The height of the navigation bar is 300. The number of images is 4. The padding between the images is 10. The border width of the images is 2.

Multiply the padding (10) by the number of images (4): 40. Add the padding (10) to include the additional padding at the bottom of the navigation bar: 50. If you have 4 images, you’ll want 10px above the first image (10), 10px above the second image (20), 10px above the third image (30), 10px above the fourth image (40), and 10px below the fourth image (50).That comes out to be 50 pixels of the total 300 height that will be dedicated to padding. Multiply the border width (2) of the images by 2: 4.If you have a border width of 2, that’s 2px on the border top and 2px on the border bottom. That comes out to be 4px total added to the vertical height of the image. Multiply that number (4) by the number of images (4): 16. Subtract that number (16) and the total padding (50) from the height (300): 234.This is how much of your navigation bar is not border or padding. This is how much of your navigation bar can actually be used for images. Divide that number (234) by the number of images (4): 58.5. Round that number (58.5) if necessary: 58. This is the height of each individual image. The width of each image can be calculated using the height-to-width ratio of the original image and this new height.

Lastly, these are the attributes of the text that displays with each image. By default, it is hidden, as it will become displayed when the image appears. It and its inner div are floated left so that their widths will match their text instead of being 100% and so it may be positioned ( position: relative ) from the left of the news slider to its appropriate location (e.g. the right side of the slider).

The Object and Important Variables

The news slider is placed in an object instead of a function. It requires at least two variables — one function to create the slider and one array to keep track of the timeouts used in changing slides. By using an object, we can store both of these in a single variable, while allowing the extensibility of storing other variables in the object for convenience.

newsSlider.create is simply the function used to create the slider and output the HTML. Unless you are writing custom mods, this will be the only part of the object you will ever call. An example of such a call and its parameters is explained in the following section.

newsSlider.htmlSpecialChars is a function, similar to PHP’s htmlspecialchars . It is used to store HTML in the image’s alt attribute by temporarily stripping out the HTML. newsSlider.specialChars is a variable used by newsSlider.htmlSpecialChars . For an in-depth explanation of this function and variable, give htmlspecialchars in JavaScript a read.

newsSlider.timeouts is an array of timeouts created by setTimeout . These need to be stored so that they may be cleared via clearTimeout when necessary.

newsSlider.total is merely an integer of the total news sliders on the page. It is used in the code to determine what ID should be used for the news sliders, but may also prove useful for any modification you may create: $(“#news-slider-” + newsSlider.total) will reference the last slider created.

With timeouts being an empty array, total being 0, and htmlSpecialChars and specialChars being given to you in the aforementioned tutorial, the only code left is newsSlider.create . Besides it, this object is done.

The Call

Before we can create newsSlider.create , we need to know what we’re working with. What is a simple interface for the developer to manipulate? How many variables with which will we be working, and what will they be called? To figure out this information, I’ve added the call prior to the final bit of code: newsSlider.create .

The parameters are all passed as an object, for simplicity’s sake, as opposed to memorizing an arbitrary order of parameters.

align is the location of the navigation bar. It may be either left or right. The text will align oppose the navigation bar’s alignment. If you set this parameter to left, the navigation bar will be on the left, and the text will be on the right. If you set this parameter to right, the navigation bar will be on the right, and the text will be on the left.

backgrounds is an array of images. These are the images that will appear in the navigation bar, and the images that will appear in the background of the slide.

direction is a value used for the sliding animation. It is the direction the div.background slides as it overlaps div.background2 . It can be any of eight values: top , top-right , right , bottom-right , bottom , bottom-left , left , or top-left . It may also be set to random , or false which is synonymous with random .

effect is the transitional animation. It may be either false , fade , slide , or random . Again, false is synonymous with random here.

hide is a boolean for whether or not you want to hide the navigation bar. If false , the navigation bar will always appear. If true , the navigation bar will only appear when you place your mouse over the news slider.

text is the text/HTML that will display with the corresponding backgrounds. When backgrounds[0] is being displayed, text[0] will be displayed; when backgrounds[1] is being displayed, text[1] will be displayed.

valign is the vertical alignment of the text. This supports top or bottom .

Creating and Styling the Elements

Now we will tackle the foundation of the newsSlider.create function, albeit not the important algorithms yet. This section will cover the creation of variables that need to be set with JavaScript, the creation of the elements, the style of the elements that can only be calculated with JavaScript, and establishing the final event listener. The following code snippets go inside create: function(data) { } .

Store the entire object in the data parameter with data.object = this; so that it may be accessed and manipulated in the future. When in an element’s event listener, this will no longer refer to the news slider object as it does here, but instead to the element itself. Because of this, we are left with no ability to reference the news slider object. (Especially if the newsSlider variable is renamed!)

div.news-slider ’s data() on the other hand, can be accessed from within event listeners. Thus by storing the object in the data, we will be able to reference it in future event listeners.

Output the HTML. You may want to manipulate this section to modify another element’s inner HTML instead of document.write if you plan on using this post-page-load.

The images are also written into the navigation bar. The text is stored in the images’ alt attributes to be retrieved when necessary.

Get the newly created news slider as a jQuery object for some JavaScript-required editing and store the data for future retrieval.

If the navigation bar is on the right, position it as such.

The navigation bar’s position from the left is the width of the background minus the width of the navigation bar. This aligns the right side of the navigation bar with the right side of the background.

If the navigation bar is to be hidden by default, bind the event listeners for mouseenter and mouseleave , then hide it.

When the mouse enters the news slider, make the bar translucent and the icons opaque. When the mouse leaves the news slider, hide the navigation.

If the navigation bar is not to be hidden, merely make the bar translucent.

Lastly, we need the event listener for changing the slides:

When the images in the navigation bar are clicked, we’ll change the slide. To start the slider as soon as it loads, we’ll click the first image instantly using jQuery’s trigger function.

All that’s left to do is setting up the event listener for clicking images, covered in the next section.

Changing Slides Event Listener

To finish the code, we need to populate the click bind for div.navigation img . I’ll separate this into three parts: the fade algorithm, the slide algorithm, and everything else. The “everything else” is basic CSS calculations and setting timeouts and as such will be discussed first.

Being the event listener, this code will go inside the function of the click bind, i.e. inside last.find("div.navigation img").bind("click", function() { }); .

First things first, if the image is already selected, we don’t want to do anything at all. Thus, we wrap the entire event listener in this conditional. Nothing is outside of this conditional, because nothing at all happens if the image is already selected.

Inside of the conditional, we’ll need to get the parent div.news-slider . jQuery’s closest() function will return the first parent that matches the selector. Remember, $(this) refers to the image clicked. The closest parent div with the class .news-slider is the wrapper element. This will be used to select other elements that need to be manipulated in the slider. Also important, we will use the div.news-slider to retrieve the data() of the slider, which contains important variables like the slider’s integer ID, the newsSlider object, and the parameters passed when creating the slider.

.animating is a class used to determine if the slider is currently between slides. If it is, we don’t want to choppily interrupt it. Many timeouts exist to cause the animation, and there’s no way to seamlessly stop the animation to transition to a new slide. What we can do is wait for the current animation to complete, then immediately change to the slide clicked.

We have the conditional to do this. If the slider isn’t animating, change slides. Otherwise, try again every 20 milliseconds. Here is the first use of timeouts. data is the object returned by data() . object is the newsSlider object stored into data() (remember data.object = this ). timeouts is the array of timeouts. Since the animation timeouts won’t be cancelled, they are not stored in timeouts. Timeouts that may be cancelled are the clicks, such as the 20-millisecond-retry. Even though the timeout won’t exist when the click is automatically retried in 20 milliseconds, we must clear the timeout anyway in case the user manually clicks the image again.

Inside the .animating conditional:

When the slider isn’t animating, remove the .selected class from the previously selected image, set the newly selected image’s class to .selected , and set the slider’s class to .animating .

The text, which is going to change, fades out. Once it has disappeared, we’ll change the contents to the selected image’s alt attribute, in which we stored the associated text when creating the image elements earlier. The second parameter of htmlSpecialChars tells the function to convert the escaped text back to HTML, i.e. convert the string <a href="https://charlesstover.com/">Charles Stover</a> to <a href="https://charlesstover.com/">Charles Stover</a> .

Once the new text has been put in the image, we must position it. Surely with the new text, the width is not going to be the same; if the text is long enough for it to wrap to a new line, the height won’t be either. The position of the next text is determined with a simple formula:

If the navigation bar is on the left ( data.align ), we must position the text on the right. To do this, we take the width of the background/slide and subtract the width of the text. Similar to a right-aligned navigation bar, this will position the right side of the text with the right side of the background. We then subtract another 10 pixels for padding. If the navigation bar is not on the left, we merely position it 10 pixels of padding from the left.

If the text is vertically aligned at the bottom ( data.valign ), we take the height of the background/slide and subtract the height of the text. This will position the bottom of the text with the bottom of the background. We then subtract another 10 pixels for padding. If the text is not vertically aligned at the bottom, we merely position it 10 pixels of padding from the top.

Remember, the text is still hidden. It won’t fade back in until the slide has changed, because running multiple jQuery animations at the same time causes enormous lag in older versions of Internet Explorer.

Now that the text is taken care of, we must calculate the direction and effect used. These are given their own variables because making manipulations to data.direction or data.effect will alter the object in future calls as well. That is, if data.effect is set to “random,” and the code set data.effect to “fade” for this current animation, then all future animations would be “fade” as well, as data.effect in future calls would be “fade” instead of “random.”

If there is no effect, then set one at random. The algorithm Math.floor(Math.random() * max) is used to calculate a random number from 0 to max - 1. In this slider, there are a total of 9 different animations: fade, slide top, slide top-right, slide right, slide bottom-right, slide bottom, slide bottom-left, slide left, and slide top-left. Thus there should be a 1 in 9 chance of effect being “fade,” with the other chances of effects being “slide.” However, if a direction is set (e.g. data.direction is set to “left”), then there are only two different possible animations: fade and slide direction (e.g. fade and slide left). In our algorithm, if the direction is random (false), we create a 1 in 9 chance of the effect being fade. However, if the direction is fixed, we create only a 1 in 2 chance of the effect being fade.

We must then determine the direction if it is set to random (false). Simply give it an array of possible values, and tell it to choose one of the 8 at random.

The Fade Algorithm

The fade algorithm is very simple, since there is only one way to fade and eight ways to “slide.”

Since we are changing slides, we need to manipulate the backgrounds. In order for the previous slide ( div.background ) to fade into the current slide ( $(this).attr("src") ), the new slide will need to appear behind the old slide while the old slide fades away. div.background2 , being behind div.background , must take on the background image of the soon-to-be current slide, i.e. the source of the image clicked, $(this).attr("src") .

Now with the background-behind-the-background set to what we want, we just need to fade div.background . Once it has faded away, three things need to be done.

The element that was created to contain the current background ( div.background ) needs to be set appropriately. Therefore div.background takes on the background of div.background2 and is set to full opacity. The user will notice no difference, because we are overlaying an image with the exact same image. However, this needs to be done for future transitions. div.text needs to fade back in. It faded out before the slides transitioned; now that the slide has finished transitioning, it should fade back in. Once the text has faded back in, we can safely remove the .animating class from the slider.

And you’re done fading between two images! All that’s left is sliding between two images, and unfortunately the algorithm is not quite as easy.

The Slide Algorithm

The slide algorithm shall take place in the else conditional of the aforementioned if (effect == "fade") { } . I decided that each animation should take place every 10 milliseconds. Generally, 20 milliseconds is fast enough to be seamless to the eye, but I did happen to notice some choppiness, so I upped it to every 10 milliseconds. That is, every 10 milliseconds, the new background will reposition closer to its final position in the middle of the slider. Since it will take 2,000 milliseconds to complete the slide (arbitrary time that I also used in the fade transition), and there will be one animation every 10 milliseconds, that makes for 200 animations – 200 repositions of the background.

per is merely the number of pixels the background will move with each animation. If the width is 600, and there are 200 animations, that’s 3 (600 divided by 200) pixels per animation. per.horizontal is the number of pixels to move the slide horizontally per animation. per.vertical , of course, is the number of pixels to move the slide vertically with each animation.

There are two types of slide animations — basic vertical/horizontal (top, right, bottom, left) sliding and diagonal (top-right, bottom-right, bottom-left, top-left) sliding.

The Diagonal Algorithm

We move the current slide from div.background to div.background2 so that we may cover it with the newly selected slide. We then set the background of position of div.background so that you cannot see the background image. Then, the background image of div.background is changed to the new slide. We are left with the old slide appearing in the background and the new slide out of view in the foreground. All we have to do is move the foreground image into view, and with each animation, it will further cover up the old slide.

Now we loop for each step in the animation: all 200 of them (again, 200 steps times 10 milliseconds per step makes for a two second complete animation).

For each step, we must calculate the shift in the background, i.e. the new background position. We multiply the current step ( x ) by the number of pixels per step ( per.horizontal and per.vertical ). Thus, shift.horizontal is the new horizontal position while shift.vertical is the new vertical position.

As an example, say we move 3 pixels to the left or right per animation ( per.horizontal = 3 ). The first animation ( x = 1 ) will have a shift.horizontal value of 3 ( x * per.horizontal = 1 * 3 = 3 ). The second animation ( x = 2 ) will have a shift.horizontal value of 6 ( x * per.horizontal = 2 * 3 = 6 ).

Now for the long timeout. The timeout will execute at x * 10 milliseconds (one step per 10 milliseconds). The first step ( x = 1 ) will be in 10 milliseconds; the last step ( x = 200 ) will be in 2,000 milliseconds.

In the timeout, I will break down the command: '$("#' + slider.attr("id") + '").find("div.background").css("background-position", "' + (direction.match(/left/) ? width - shift.horizontal : shift.horizontal - width) + 'px ' + (direction.match(/top/) ? height - shift.vertical : shift.vertical - height) + 'px");'

$("#' + slider.attr("id") + '") tells jQuery to get the slider with the same ID as the one in which the image was clicked. slider is the variable $(this).closest("div.news-slider") .

tells jQuery to get the slider with the same ID as the one in which the image was clicked. slider is the variable . .find("div.background") tells it to get the newly-created slide, so that we can position it closer to the center of the slider.

tells it to get the newly-created slide, so that we can position it closer to the center of the slider. .css("background-position", "..."); is the reposition algorithm that moves it closer with each step.

is the reposition algorithm that moves it closer with each step. (direction.match(/left/) ? width - shift.horizontal : shift.horizontal - width) constitutes the horizontal position of the background. If the direction of the slide is to move to the left, then set the new position to the width minus the horizontal shift. The position is going to start at the far right side, and for every step, it will move to the left. If the direction of the slide is to move to the right, then set the new position to the horizontal shift minus the width. An easier way to think of this may be -width + shift.horizontal . The start position is negative the width, so that it cannot be seen, and each step moves it further to the right.

constitutes the horizontal position of the background. If the direction of the slide is to move to the left, then set the new position to the width minus the horizontal shift. The position is going to start at the far right side, and for every step, it will move to the left. If the direction of the slide is to move to the right, then set the new position to the horizontal shift minus the width. An easier way to think of this may be . The start position is negative the width, so that it cannot be seen, and each step moves it further to the right. (direction.match(/top/) ? height - shift.vertical : shift.vertical - height) constitutes the vertical position of the background.The algorithm is essentially the same as the horizontal algorithm.

This concludes the diagonal algorithm. All that’s left is the horizontal and vertical movement, which has a slight tweak.

The Horizontal and Vertical Algorithm

Unlike the diagonal algorithm, in which the new slide covers the old slide, the horizontal and vertical algorithm will have the two slides connected. In single-direction animations, the new slide gives the appearance as though it’s “pushing” the old slide out of view. This cannot be elegantly done in a diagonal slide, thus the new slide merely covers the old one in the diagonal algorithm. If you do not know the difference between the two animation types, watch them animate in the live demo linked at the top of this article.

Since the horizontal and vertical algorithm are different than the diagonal algorithm, it is placed in the else conditional of if (direction.match(/\-/)) { } .

This all functions exactly the same as the diagonal algorithm, except for the timeout. Two hundred animations, in which the shift is calculated, and a step is set to execute every 10 milliseconds.

The timeout can be split into two sections, div.background and div.background2 .

$("#' + slider.attr("id") + '").find("div.background").css("background-position", "..."); gets the previous slide and alters the background position as such: (direction == "left" ? '-' + shift.horizontal + 'px' : (direction == "right" ? shift.horizontal + 'px' : '0')) If the direction to slide is left, move the old slide shift.horizontal pixels to the left.If the direction to slide is right, move the old side shift.horizontalpixels to the right.If the direction is neither left or right (i.e. top or bottom), don’t move it in any horizontal direction (0 pixels). (direction == "top" ? '-' + shift.vertical + 'px' : (direction == "bottom" ? shift.vertical + 'px' : '0')) If the direction to slide is top, move the old slide shift.verticalpixels to the top.If the direction to slide is bottom, move the old slide shift.vertical pixels to the bottom.If the direction is neither top or bottom (i.e. left or right), don’t move it in any vertical direction (0 pixels). $("#' + slider.attr("id") + '").find("div.background2").css("background-position", "..."); gets the new slide and alters the background position in a similar way as div.background . The only difference between the two is that, while the start position of div.background is 0 pixels from the left and 0 pixels from the top, the start position of div.background2 is out-of-view.If it’s sliding from the left, its position will be negative its width (placing it out of view to the left). If it’s sliding from the right, its position will be positive its width (placing it out of view to the right). If it’s sliding from the top, its position will be negative its height (placing it out of view to the top). If it’s sliding from the bottom, its position will be positive its height (placing it out of view to the bottom).Outside of these start positions, the algorithms are precisely the same. (direction == "left" ? (width - shift.horizontal) + 'px' : (direction == "right" ? (shift.horizontal - width) + 'px' : '0')) If the direction to slide is left, position the new slide at the width of the slide (start position) minus shift.horizontal pixels.If the direction to slide is right, position the new slide at shift.horizontal minus the width of the slide, i.e. negative the width of the slide (start position) plus shift.horizontal .If the direction is neither left or right (i.e. top or bottom), don’t move it in any horizontal direction (0 pixels). (direction == "top" ? (height - shift.vertical) + 'px' : (direction == "bottom" ? (shift.vertical - height) + 'px' : '0')) If the direction to slide is top, position the new slide at the height of the slide (start position) minus shift.vertical pixels. If the direction to slide is bottom, position the new slide at shift.vertical pixels minus the height of the slide, i.e. negative the height of the slide (start position) plus shift.vertical . If the direction is neither top or bottom (i.e. left or right), don’t move it in any vertical direction (0 pixels).

Once the horizontal or vertical slide is complete (after 2,000 milliseconds), we must move the new slide from div.background2 to div.background for future transitions:

We also reset the background-position of div.background , which was altered in the animation, to 0 0.

There is still one step left in the animation! This goes for both the diagonal and horizontal/vertical algorithm (therefore goes after/outside the diagonal/horizontal/vertical else block, but still inside the else block for the slide effect).

Conclusion

Last but not least there is a final tidbit of code that needs to execute for all animations (both fade and slide). Since it will execute for both, it will need to go after/outside the effect == "fade" else code; it goes inside and at the end of the if (!slider.is("div.animating")) conditional block.

Simply, we take the next image ( $(this) is the current image, making $(this).next() the next image in the navigation bar). If there is no next image (i.e. the current slide is the last image in the navigation bar), then we take the first image ( .image1 ). With this image, after 7.5 seconds, we trigger its click event. This will set the slide to automatically change every 7.5 seconds. Of course, we clearTimeout in case they manually click a slide.

Now, you’re done. This is a complete news slider script. Thanks for reading!

If you enjoyed this, you may follow me on LinkedIn, Medium, and Twitter, or check out my portfolio on CharlesStover.com.