Menu Search
Jump to the content X X
Smashing Conf Barcelona 2016

We use ad-blockers as well, you know. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. upcoming SmashingConf Barcelona, dedicated to smart front-end techniques and design patterns.

A Pure CSS3 Cycling Slideshow

Thanks to CSS3, we can create effects and animations without using JavaScript, which will facilitate the work of many designers.

But we must be careful to avoid abusing CSS3, not only because old browsers do not support all of its properties. In any case, we all see the potential of CSS3, and in this article we’ll discuss how to create an infinitely looping slider of images using only CSS3 animation.

Sections of This Article Link

To get a solid sense of the process from beginning to end, below is an outline of the article. Please note that this effect will only work properly in modern browsers that support the CSS3 properties being used.

  1. Introduction1
    Learn basic concepts related to CSS3 transitions and keyframe animation.
  2. HTML markup2
    Create the HTML markup for the sliding images.
  3. CSS styles3
    Create the style sheet to display the slider.
  4. CSS3 keyframe animation4
    Add animation to the slider (we’ll explain the various processes happening here).
  5. Progress bar5
    Add a progress bar for our slider.
  6. Tooltip6
    Add a tooltip to display the title of the image.
  7. CSS3 transitions7
    Animate the tooltip using CSS3 transitions to make it appear to hover over the image.
  8. Pause and restart8
    Pause the slider and restart it on hover.
  9. Demo9
    Check out the slider in action.
  10. Conclusion10
    Final considerations.

Pure CSS3 Cycle Slider11
Screenshot of the pure CSS3 cycling slideshow12.

1. Introduction Link

To follow this tutorial, having a basic understanding of CSS, especially CSS3 transitions and keyframe animation, is important. Using this simple concept, we will see how to make a functional image slider.

Basic Concepts of CSS3 Transitions Link

Normally when you change a CSS value, the change is instant. Now, thanks to the transition property, we can easily animate from the old to new state.

We can use four transition properties:

  1. transition-property
    Defines the name(s) of the CSS properties to which the transitions should be applied.
  2. transition-duration
    Defines the duration over which the transitions should occur.
  3. transition-timing-function
    Determines how intermediate values of the transition are calculated. The effects from the timing function are commonly called easing functions.
  4. transition-delay
    Defines when the transition starts.

At the moment, CSS3 transitions are supported in Safari 3.2+, Chrome, Firefox 4+, Opera 10.5+ and IE 10. Because the technology is still relatively new, prefixes for browsers are required. So far, the syntax is exactly the same for each browser, with only a prefix change required. We will omit them in the snippets in this article, but please remember to include the prefixes in your code.

Let’s see how to apply a simple transition to a link:

a {
   color: #000;
   transition-property: color;
   transition-duration: 0.7s;
   transition-timing-function: ease-in;
   transition-delay: 0.3s;

a:hover {
   color: #fff;

When assigning an animation to an element, you can also use the shorthand:

a  {
   color: #000;
   transition: color 0.7s ease-in 0.3s;

a:hover {
   color: #fff;

The W3C has a list of all “Animatable Properties13.”

Basic Concepts of CSS3 Animations Link

CSS animation enables us to create animations without JavaScript by using a set of keyframes.

Unlike CSS transitions, keyframe animations are currently supported only in Webkit browsers and Firefox and soon in IE 10. Unsupported browsers will simply ignore your animation code.

The animation property has eight subproperties:

  1. animation-delay
    Defines when the animation starts.
  2. animation-direction
    Sets the animation to play in reverse on alternate cycles.
  3. animation-duration
    Defines the length of time an animation takes to complete one cycle.
  4. animation-iteration-count
    Defines the number of times an animation cycle should play before stopping.
  5. animation-name
    Specifies the name of the @keyframes rule.
  6. animation-play-state
    Determines whether an animation is running or paused.
  7. animation-timing-function
    Describes how an animation progresses over one cycle.
  8. animation-fill-mode
    Specifies how a CSS animation should apply styles to its target before and after executing.

Let’s see how to apply a simple animation to a div.

/* This is the element we are applying the animation to. */

div {
   animation-name: move;
   animation-duration: 1s;
   animation-timing-function: ease-in-out;
   animation-delay: 0.5s;
   animation-iteration-count: 2;
   animation-direction: alternate;

   -moz-animation-name: move;
   -moz-animation-duration: 1s;
   -moz-animation-timing-function: ease-in-out;
   -moz-animation-delay: 0.5s;
   -moz-animation-iteration-count: 2;
   -moz-animation-direction: alternate;

   -webkit-animation-name: move;
   -webkit-animation-duration: 1s;
   -webkit-animation-timing-function: ease-in-out;
   -webkit-animation-delay: 0.5s;
   -webkit-animation-iteration-count: 2;
   -webkit-animation-direction: alternate;

/* This is the animation code. */

@keyframes move {
   from {
      transform: translateX(0);
   to {
      transform: translateX(100px);

@-moz-keyframes move {
   from {
      -moz-transform: translateX(0);
   to {
      -moz-transform: translateX(100px);

@-webkit-keyframes move {
   from {
      -webkit-transform: translateX(0);
   to {
      -webkit-transform: translateX(100px);

But we can use the shorthand property to conveniently set all of the animation properties at once.

div {
   animation: move 1s ease-in-out 0.5s 2 alternate;
   -moz-animation: move 1s ease-in-out 0.5s 2 alternate;
   -webkit-animation: move 1s ease-in-out 0.5s 2 alternate;

Keyframes Link

Each keyframe describes how an animated element should render at a given point in the animation sequence. The keyframes take a percentage value to specify time: 0% is the start of the animation, while 100% is the end. You can optionally add keyframes for intermediate animations.

/* Animation from 0% to 100% */

@keyframes move {
   0% { transform: translateX(0); }
   100% { transform: translateX(100px); }

/* Animation with intermediate keyframes */

@keyframes move {
   0% { transform: translateX(0); }
   50% { transform: translateX(20px); }
   100% { transform: translateX(100px); }

The W3C has a lot of useful and detailed information on “CSS3 Animations14.”

Basic Structure of Our Slider Link

Now that we know how transitions and animation work, let’s see how to create our slider using only CSS3. This sketch shows how the animation should work:

Sketch animation slider function
How the animation slider functions

As you can see, the slider will be a container inside of which the images will be displayed.

The animation is very simple: the image follow a predefined path, animating the top property and changing the z-index and opacity properties when the image returns to its initial position.

Let’s dive right into the HTML markup to create the slider.

2. HTML Markup Link

The HTML markup is very simple; it’s all organized and SEO-friendly. Let’s see the full code first and then figure out in detail how everything works.

<div class="container">
   <div id="content-slider">
      <div id="slider">  <!-- Slider container -->
         <div id="mask">  <!-- Mask -->

         <li id="first" class="firstanimation">  <!-- ID for tooltip and class for animation -->
         <a href="#"> <img src="images/img_1.jpg" alt="Cougar"/> </a>
         <div class="tooltip"> <h1>Cougar</h1> </div>

         <li id="second" class="secondanimation">
         <a href="#"> <img src="images/img_2.jpg" alt="Lions"/> </a>
         <div class="tooltip"> <h1>Lions</h1> </div>

         <li id="third" class="thirdanimation">
         <a href="#"> <img src="images/img_3.jpg" alt="Snowalker"/> </a>
         <div class="tooltip"> <h1>Snowalker</h1> </div>

         <li id="fourth" class="fourthanimation">
         <a href="#"> <img src="images/img_4.jpg" alt="Howling"/> </a>
         <div class="tooltip"> <h1>Howling</h1> </div>

         <li id="fifth" class="fifthanimation">
         <a href="#"> <img src="images/img_5.jpg" alt="Sunbathing"/> </a>
         <div class="tooltip"> <h1>Sunbathing</h1> </div>

         </div>  <!-- End Mask -->
         <div class="progress-bar"></div>  <!-- Progress Bar -->
      </div>  <!-- End Slider Container -->
  1. div id="slider"
    This is the main container of the slider. It does not have a particular function, but we will need it to pause the animation.
  2. div id="mask"
    We will use this to hide everything that happens outside of the slider. In addition to hiding the content, the mask allows us to display the contents of the slider.
  3. li id="first" class="firstanimation"
    Every list item has an ID and a class. The ID displays the tooltip, and the class is tied to the animation that has to occur.
  4. div class="tooltip"
    This simply displays the title of the image. You can modify it to your needs; for example, by making it clickable and adding a short description.
  5. div class="progress-bar"
    This contains the function that shows the progress of the animation.

Now it’s time for the CSS file.

3. CSS Style Link

Let’s create the basic structure of the slider. It will have the same image size. The border property will be useful to create a frame around the image.


#slider {
   background: #000;
   border: 5px solid #eaeaea;
   box-shadow: 1px 1px 5px rgba(0,0,0,0.7);
   height: 320px;
   width: 680px;
   margin: 40px auto 0;
   overflow: visible;
   position: relative;

The mask class will hide all of the elements that lie outside of the slider; its height must be equal to the height of the slider.


#mask {
   overflow: hidden;
   height: 320px;

Finally, to sort the list of images, we’ll have position: absolute and top: -325px so that all of the images are positioned outside of the slider.


#slider ul {
   margin: 0;
   padding: 0;
   position: relative;

#slider li {
   width: 680px;  /* Width Image */
   height: 320px; /* Height Image */
   position: absolute;
   top: -325px; /* Original Position - Outside of the Slider */
   list-style: none;

With these few lines of code, we have created our slider. Now we just need to add the animation.

4. CSS3 Keyframes Animation Link

Slider Animation
Image animation for the slider

Before we begin with the animation, we have to specify some parameters in order to get the right view of the animation.

As we know, the total duration of the animation will be 25 seconds, but we have to know how many keyframes equals 1 second.

So, let’s work out a series of operations that gives us the exact number of keyframes based on the images we have and the total duration of the animation. Here are the calculations:

  1. Define the total number of images to use in the slider
  2. Define the length of animation for each image
    5 seconds
  3. Define the total duration of the animation
    Multiply the total number of images by the duration of each image:
    5 images × 5 seconds = 25 seconds
  4. Calculate how many keyframes equals one second
    Divide the total number of keyframes by the total duration of the animation.
    100 keyframes / 25 seconds = 4 keyframes
    4 keyframes = 1 second

With all of this math, we can now apply the CSS animation to the slider. We will be able to put the animation on infinite loop because each image will follow its own animation that activates once it comes up in the slider.

#slider li.firstanimation {
   animation: cycle 25s linear infinite;

#slider li.secondanimation {
   animation: cycletwo 25s linear infinite;

#slider li.thirdanimation {
   animation: cyclethree 25s linear infinite;

#slider li.fourthanimation {
   animation: cyclefour 25s linear infinite;

#slider li.fifthanimation {
   animation: cyclefive 25s linear infinite;

Once the properties of the animation have been assigned, we need to use keyframes to set the animation in motion.

Following this principle, we can connect the animations to each other even though they are separate, which will give us an infinite loop.

I’ve added the opacity and z-index properties to make the transition from one image to the next more attractive.

As you can see in the code, the first animation has more keyframes than the rest. The reason for this is that when the gallery is started, the first image is positioned to make way for the second image; but when the last image has finished its animation, the first image has to have additional keyframes in order for the user not to see a break between animation cycles.

Here is all of the code for the animations:


@keyframes cycle {
   0%  { top: 0px; } /* When you start the slide, the first image is already visible */
   4%  { top: 0px; } /* Original Position */
   16% { top: 0px; opacity:1; z-index:0; } /* From 4% to 16 % = for 3 seconds the image is visible */
   20% { top: 325px; opacity: 0; z-index: 0; } /* From 16% to 20% = for 1 second exit image */
   21% { top: -325px; opacity: 0; z-index: -1; } /* Return to Original Position */
   92% { top: -325px; opacity: 0; z-index: 0; }
   96% { top: -325px; opacity: 0; } /* From 96% to 100% = for 1 second enter image*/
   100%{ top: 0px; opacity: 1; }

@keyframes cycletwo {
   0%  { top: -325px; opacity: 0; } /* Original Position */
   16% { top: -325px; opacity: 0; }/* Starts moving after 16% to this position */
   20% { top: 0px; opacity: 1; }
   24% { top: 0px; opacity: 1; }  /* From 20% to 24% = for 1 second enter image*/
   36% { top: 0px; opacity: 1; z-index: 0; }   /* From 24% to 36 % = for 3 seconds the image is visible */
   40% { top: 325px; opacity: 0; z-index: 0; } /* From 36% to 40% = for 1 second exit image */
   41% { top: -325px; opacity: 0; z-index: -1; }   /* Return to Original Position */
   100%{ top: -325px; opacity: 0; z-index: -1; }

@keyframes cyclethree {
   0%  { top: -325px; opacity: 0; }
   36% { top: -325px; opacity: 0; }
   40% { top: 0px; opacity: 1; }
   44% { top: 0px; opacity: 1; }
   56% { top: 0px; opacity: 1; }
   60% { top: 325px; opacity: 0; z-index: 0; }
   61% { top: -325px; opacity: 0; z-index: -1; }
   100%{ top: -325px; opacity: 0; z-index: -1; }

@keyframes cyclefour {
   0%  { top: -325px; opacity: 0; }
   56% { top: -325px; opacity: 0; }
   60% { top: 0px; opacity: 1; }
   64% { top: 0px; opacity: 1; }
   76% { top: 0px; opacity: 1; z-index: 0; }
   80% { top: 325px; opacity: 0; z-index: 0; }
   81% { top: -325px; opacity: 0; z-index: -1; }
   100%{ top: -325px; opacity: 0; z-index: -1; }
@keyframes cyclefive {
   0%  { top: -325px; opacity: 0; }
   76% { top: -325px; opacity: 0; }
   80% { top: 0px; opacity: 1; }
   84% { top: 0px; opacity: 1; }
   96% { top: 0px; opacity: 1; z-index: 0; }
   100%{ top: 325px; opacity: 0; z-index: 0; }

Having created the animations, we have to add a progress bar to display the duration of each animation.

5. Progress Bar Link

Progress bar Animation for each image
The progress bar for each animation

The process of animating the progress bar is the same as it was for the slider. First, we create the progress bar itself:


.progress-bar {
   position: relative;
   top: -5px;
   width: 680px;
   height: 5px;
   background: #000;
   animation: fullexpand 25s ease-out infinite;

Don’t be afraid of the syntax here. It has the same function as from to; you can see that the keyframes set the appearance and disappearance of each image.


@keyframes fullexpand {
   /* In these keyframes, the progress-bar is stationary */
   0%, 20%, 40%, 60%, 80%, 100% { width: 0%; opacity: 0; }

   /* In these keyframes, the progress-bar starts to come alive */
   4%, 24%, 44%, 64%, 84% { width: 0%; opacity: 0.3; }

   /* In these keyframes, the progress-bar moves forward for 3 seconds */
   16%, 36%, 56%, 76%, 96% { width: 100%; opacity: 0.7; }

   /* In these keyframes, the progress-bar has finished his path */
   17%, 37%, 57%, 77%, 97% { width: 100%; opacity: 0.3; }

   /* In these keyframes, the progress-bar will disappear and then resume the cycle */
   18%, 38%, 58%, 78%, 98% { width: 100%; opacity: 0; }

6. Tooltip Link

The slider is more or less complete, but let’s add a few details to make it more functional. We’ll insert tooltips for the image titles that will be visible on hover.

Simple Tooltip on image
Simple tooltip

Here is the CSS for the tooltips:

#slider .tooltip {
   background: rgba(0,0,0,0.7);
   width: 300px;
   height: 60px;
   position: relative;
   bottom: 75px;
   left: -320px;

#slider .tooltip h1 {
   color: #fff;
   font-size: 24px;
   font-weight: 300;
   line-height: 60px;
   padding: 0 0 0 10px;

Here we’ve made only the image titles visible, but you can do the same to custom text, links or whatever you like.

7. CSS3 Transitions Link

Tooltip Animation
Animate the tooltip on hover

We have seen how to apply CSS3 transitions to elements; now let’s do it to the tooltips.

If you remember, we added an ID to each list (first, second, etc.) to have only the tooltip associated with an image appear on hover, rather than all of the tooltips appear together.

#slider .tooltip {
   transition: all 0.3s ease-in-out;

#slider li#first: hover .tooltip,
#slider li#second: hover .tooltip,
#slider li#third: hover .tooltip,
#slider li#fourth: hover .tooltip,
#slider li#fifth: hover .tooltip {
   left: 0px;

8. Pause And Restart Link

Stop slider on mouse hover
Stop slider on mouse hover

To allow users to pause to read content or look at an image, we should stop the animation when they hover over an image. (We’ll also have to stop the animation of the progress bar.)

#slider: hover li,
#slider: hover .progress-bar {
   animation-play-state: paused;

9. Demo Link

Finally, we’ve reached the end of the tutorial. The slider is now 100% complete!

Pure CSS3 Cycle Slider15
Pure CSS3 cycling slider demo

Check out the demo16. It works in Firefox 5+, Safari 4+ and Google Chrome, as well as the iPhone and iPad. You can also download the ZIP file17.

Thanks to Massimo Righi18 for his images.

10. Conclusion Link

The effect is impressive, but admittedly, this slider is not very versatile. For instance, to add more images, you have to edit all of keyframes. CSS3 has great potential, but it does have limits, and sometimes JavaScript is preferable, depending on your target users.

This slider has some interesting features, such as pausing on hover and uniques link for the images, which allow users to interact with the slider. If you want full support among browsers, this is not possible, so JavaScript is recommended. Unfortunately, CSS3 animation has many limitations; its lack of flexibility in particular will prevent its widespread use for now. Hopefully this will spur you on to further study of CSS3.

Feel free to share your thoughts in the comments section below!

(al) (il)

Footnotes Link

  1. 1 #1
  2. 2 #2
  3. 3 #3
  4. 4 #4
  5. 5 #5
  6. 6 #6
  7. 7 #7
  8. 8 #8
  9. 9 #9
  10. 10 #10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
SmashingConf Barcelona 2016

Hold on, Tiger! Thank you for reading the article. Did you know that we also publish printed books and run friendly conferences – crafted for pros like you? Like SmashingConf Barcelona, on October 25–26, with smart design patterns and front-end techniques.

↑ Back to top Tweet itShare on Facebook


Alessio Atzeni, based in Rome, Italy, is a dedicated web designer and front-end developer with a passion for CSS3. He specializes in CSS and JavaScript web development, and building search engine friendly websites. For more front-end web development tutorials and CSS3 experiments, check out his web design blog. Follow him on Twitter @Bluxart, on Dribbble or add him on Google+.

  1. 1

    Hi Alessio, Great article buddy. I was looking for just the thing. I’m working on a personal experimental project and this really helped. I understand that CSS3 is still some time away from adoption but the possibilities are lucrative. Lets keep playing with it. Thats the only way to know if its a dud or otherwise. Kudos for a step in the right direction imo. m/

  2. 2

    Krsiak Daniel

    April 25, 2012 6:46 am

    I seriously like that but honestly: too many lines :]
    I know it is to demonstrate CSS3 but we can achieve more with fewer lines of jQuery

    • 3

      You’re right, but for mobile website this is awesome stuff. Jquery animating is often way too slow on mobile devices while CSS3 animation works perfectly smooth. I’m currently working on a mobile project for which i use css3 animation combined with touch events and i’ll tell ya – it works brilliant, like a pure app!

      You have to use it at the right time. I mean if you need just a website with animations/sliders which targets audience who mainly use desktop – then yeah, jquery is the choise. But maybe you want everything as smooth on mobile devices, or you want to give IExplorer the finger, then CSS3 is the a very good way!

      Therefore, these kind of articles/demos are very good!

      • 4

        So you’d recommend to use something like this instead of JS? Does it degrade gracefully on browsers that don’t support it?

        • 5

          For the moment – unfortunately no. In my case with the mobile project i mentioned it doesn’t need a fallback for browsers which don’t support CSS3 animation.

          If you want to use CSS3 on webkit/mobile, but Jquery animate on regular browser, you could write both scripts and check with – for example – modernizr if you’re in a webkit environment or one that supports CSS3 transitions. And then deside what to use.

          Ofcourse this will cause more work to be done.

          There also are jquery plugins that extend the normal jquery animate function with CSS animation. They check if CSS animation is available and choose wether to use CSS animation or the javascript animation. BUT therefore you need to include first jquery and than the plugin, and that’s also more data to transfer for the mobile users..

          So for now it’s realy a matter of choice, personal preference and a good look at your audience.

      • 6

        I Like this line very much – “But maybe you want everything as smooth on mobile devices, or you want to give IExplorer the finger, then CSS3 is the a very good way!”

        Some time even I feel when I get bug for IE, it’s behaving ridiculous some time :(

        I’m also working for Mobile Device web apps, this will be useful for me.
        Thanks for sharing,

    • 7

      Sevban Ozturk

      April 27, 2012 12:00 am

      Excuse me but don’t forget that jQuery library itself isn’t consist of “a few lines”. This approach uses less resources and optimal for mobile development. It is fast and smooth.

  3. 8

    Hi !
    Thank you for this article.
    What about keyboard navigation ?

    This is my own (old) experimentations with a keyboard navigation (tab only) and some controls (play, stop, next, prev).

    What do you think about it ?

    Regards ;)

  4. 9

    I must say “- NICE, VERY NICE …”
    Now to fix it to my WordPress site. LOL…

  5. 10

    Dammit IE!

  6. 11

    Raksaka Indra

    April 25, 2012 10:29 am

    very-very useful and powrful, thank you… :D

  7. 12

    Philip Wallage

    April 25, 2012 6:29 am

    That makes me really happy :’)

    • 13

      Alessio Atzeni

      April 25, 2012 6:42 am

      I am glad you could be helpful :)

    • 14

      hey great tutorial! Im having a problem with only using 3 images. I take out the css and the frames for 3 and 4 all in animation.css and i take it out from style css but it continues to keep going to the 4th and 5th frame frame i guess and i dont know why it’s doing that. I even took out the HTML ids to 4 and 5, i only want to show 3 images not 5 and i really dont know it keeps cyling. pls help

  8. 15

    how about IE Support ?

    • 16

      Hey, Alessio mentioned in his article that IE is going to have trouble doing this along with, sadly, a million other things. Microsoft better catch up fast..

  9. 17

    This is just “WOW” – seems a little bit confusing in the beginning with all the percentages, but afterwards it is really easy!

    Pro: No need of jQuery ;)
    Cons: IE…

  10. 18

    Pritesh Gupta

    April 25, 2012 6:54 am

    Wow, this is quite good, one of the finest pure css3 work I have seen till now.

  11. 19

    Niels Matthijs

    April 25, 2012 7:01 am

    It’s a nice demo but it definitely lack a “don’t use this in the wild” disclaimer. As the author states the suggested method is far from flexible and will only result in maintenance hell.

    Also, since there is quite some functionality involved here (what about user controls – going back, skipping two frames etc etc) some things are probably best left to javascript. Not because it’s faster or more reliable, but because that’s what’s javascript is supposed to do.

    But judged as a pure demo … good stuff .

    • 20

      Alessio Atzeni

      April 25, 2012 7:20 am

      Exactly Niels, this demo was an experiment regarding the potential of CSS3.

      In fact, JavaScript is recommended in this case mainly because of maintenance and above all: the user control.

  12. 22

    Really nice! I guess by following this tutorial we will learn a lot of the new concepts of css3. Great job and thank you for sharing.

  13. 23

    This a great idea with CSS3 Thanks man ;)

  14. 24

    This is pretty cool, even though it’s effectiveness isn’t widespread yet.

  15. 25

    When I want to try demo or download it I get this error:

    “Host Not Configured to Serve Web Traffic”

    What’s wrong?

  16. 27

    Is there anyway we can view the demo again? This one seems really interesting and I know there are other slideshows out there. I’d just liked to see how this one works, if possible?

  17. 28

    Denis Leblanc

    April 25, 2012 6:46 pm

    Great work Alessio. You work is impeccable.

  18. 30


  19. 31

    i loved this demo. Showed the strengths of CSS3 and also the current weakness. I’ve been looking for ways to add flair to a somewhat static site and I may use this as an experiment. Either was I’m a student of CSS and I’m gathering all this in a notebook.

  20. 32

    thanks, a great demo for me !


↑ Back to top