Grow your CSS skills. Land your dream job.

Infinite All-CSS Scrolling Slideshow

Published by Chris Coyier

Just for kicks I wanted to see if I could make a row of images animate across a page and repeat indefinitely. Turns out it's really not that hard. The way I did it was to make one big long graphic where the first part and the last part are visually identical.

Then you animate the left position of that image until it appears it's completed one full cycle (but really is just moved far enough to look identical), then it quickly warps back to the original position and starts over.

We just need an outer wrapper to be relative positioned and hide the overflow, then an inside container in which to animate (which is the image).

<div class="slideshow">
   <div class="images">
       A slideshow of images in here (whatever you want to say for screen readers)
   </div>
</div>
.slideshow {
  position: relative;
  overflow: hidden;
}
.images {
  background: url(slideshow.jpg);
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 300%;
  -webkit-animation: slideshow 10s linear infinite;
  -moz-animation:    slideshow 10s linear infinite;
}
@-webkit-keyframes slideshow {
  0%    { left: 0; }
  100%  { left: -200%; }
}
@moz-keyframes slideshow {
  0%    { left: 0; }
  100%  { left: -200%; }
}

View Demo

Let's squeeze some better performance out of this thing, cowboy.

The above code should work fine, but it might be a little choppy depending on the browser/platform/version/resources available. We can get better performance (at least in WebKit / Mobile WebKit) by telling the browser we are going to be using 3D transforms (even though we aren't) and then using translateX instead of left.

NOTE: This trick specifically increases the performance (that you normally wouldn't get) out of 2D transforms and opacity changes. If we weren't changing over to using translateX, we wouldn't see any benefit.

.images {
   ...
   
   /* Hey browser, use your GPU */
   -webkit-transform: translate3d(0, 0, 0);
}

@-webkit-keyframes moveSlideshow {
    0%   { 
        -webkit-transform: translateX(0);  
    }    
    100% { 
        -webkit-transform: translateX(-200%);  
    }
}
@-moz-keyframes moveSlideshow {
    0%   { 
        -moz-transform:    translateX(0); 
    }    
    100% { 
        -moz-transform:    translateX(-200%); 
    }
}

I'm not a huge fan of the fact that we essentially need to trick the browser into better performance, but as CSS folks I guess we're used to that kind of thing. I think the original way we wrote it is fine and the browser should recognize when it can be more performant and do that.

Adding Fancies

With my slideshow, I wanted to do two additional cool effects beyond just scrolling the images by. When you rolled over the slideshow it would:

  1. Speed up
  2. Change from black & white to color

To speed it up, you might just think, we'll just reduce the duration on hover! And thus:

.slideshow:hover .images {
   -webkit-animation-duration: 5s;
   -moz-animation-duration:    5s;
} 

But this is going to be jerky! By changing the animation duration you create a new timeline of what properties should be at what values and when. It figures out those new values and jumps to where they should be immediately. It does not just "speed up" from it's exact current position. I'm afraid I don't know a really solid way around this.

Instead, we'll just adjust the concept of "speeding up". If we set two slideshows on top of each other, each one running at different speeds, then hide/show the top-most faster-running on on hover, we can get a pretty decent "speeding up" effect. We'll use transitions to make the transition smoother.

<div class="slideshow">
   <div class="images-1">
       A slideshow of images in here (whatever you want to say for screen readers)
   </div>
   <div class="images-2">
   </div>
</div>
.slideshow > div {
   ...

    -moz-transition:  opacity 0.5s ease-out; 
       -o-transition: opacity 0.5s ease-out; 
  -webkit-transition: opacity 0.5s ease-out; 
      -ms-transition: opacity 0.5s ease-out; 
    
    /* Slow */
    -webkit-animation: moveSlideshow 60s linear infinite;
    -moz-animation:    moveSlideshow 60s linear infinite;
    
    ...
}

.images-1 {
    /* Fast */
    -webkit-animation: moveSlideshow 20s linear infinite;
    -moz-animation:    moveSlideshow 20s linear infinite;
}

.slideshow:hover .images-2 {
    opacity: 0;
}

For the black and white thing, what we'll just make the top-most slideshow black and white and the lower/faster slideshow color. To save an HTTP Request, we'll make both of them the same image, and just shift the background position.


Just one big image

.images-1 {
    /* Sprite */
    background-position: 0 200px;

    ...
}

So that should do it!

View Demo   Download Files

Origin

This idea came the Wufoo Hearts Tech Events page we recently did, where I wanted to show off images from several of the events we've been at recently. And, admittedly, I just wanted to play with this idea.

Comments

  1. Permalink to comment#

    First off – this is really nice CSS-work.

    Excuse me if this sounds dense; but I see all this animation being moved from JS to CSS but it just feels to me like people are doing because they can, not that it’s necessarily an improvement.

    I compare this code to something similar I wrote in JS and can’t help but think how much easier it is to troubleshoot, tweak, and moreover – just to build in general. Plus, isn’t JS around specifically for this sort of thing?

    Again, really nice work, but could someone possibly go into detail about why this is a beneficial way to do things? I’m just not seeing it.

    • That’s an interesting discussion to start.

      I’d argue the other side, in that CSS is for stuff like this and JS is not.

      In the classic conversation of “separation of concerns”, CSS is for design/styling and JS is for behavior. An animation is, if you ask me, far more a part of design/styling than it is behavior. It depends on the use of the animation though. A slideshow is pretty gray-area since there is plenty of behavior that can go along with them.

      The other thing to discuss is HOW the animation is accomplished. To animate something with JavaScript, you need to rapidly manipulate inline styles on an element. I’d say this is closer to a clever hack than an appropriate way to handle animation. As shown in this tutorial, by making animation happen in CSS, we can actually get the GPU (graphics processor unit) involved and have it handle the animation. That is almost inarguably more efficient than JavaScript =)

    • Definitely a good point.

      Although, I see a few benefits in using CSS sprite scrolls like this.
      – it could be good for those that aren’t very fluent in javascript.
      – this could be beneficial if the platform that the site is built on doesn’t allow for javascript or the appendage of JS libraries like JQuery or MooTools.

      I’ve ran into those kind of instances so this may come in handy in the case it does.

      But yes, if it was me, I would do it in JS :)
      Either way, well done CC.

    • Permalink to comment#

      Thanks, the clarification about the GPU’s involvement helps a lot.

      I guess I see the point of using CSS for stuff that is “animation”, I think it’s the interaction that I get hung up on when I see examples like this.

      Probably best to weigh every case when choosing between CSS & JS, but I guess that’s a general rule for any development. I’d love to find a post going into more detail re. this subject since it seems to be gaining momentum.

    • Chris Coyier – As usual another awesome insight in new use of CSS (transitions).

      But I’d like to add a note about GPU use. IE9 uses GPU acceleration for Javascipt animations as well. So it’s not only CSS3 animations that will benefit from GPU acceleration in the future.

  2. Alexey
    Permalink to comment#

    <marquee>?

  3. I was watching the slideshow in the fiddle Chris provided and something wasn’t right. I sat and watched a few times and took me ages to realise what was up.

    The repeated section of the image is a pixel above the original section.

    I then spent a few moments looking for the erroneous code. I felt so stupid when it struck me that the duplicated section is within the image. It is likely a quick copy issue within Photoshop so Chris could provide the demo!

    Yes that’s me in the corner, with the Dunce hat!!! :-s

  4. cnwtx
    Permalink to comment#

    Neat, now can you make controls for it? Maybe have js edit the style sheet on the fly?
    Also, when you hover over it, the fast slide is usually in a different place then the slow one, making it appear to change pictures when you hover over it, then change back once you move your mouse back. Is their any solution to this?

  5. I would’ve liked it if you did a bit more canvas magic there. I think Jeffrey Way has a tutorial on how to make a grey scale version of an image using canvas. In your case, the footprint of the tiny bit of JavaScript used to achieve that should be way lower than this sprite image with two colors. Here’s the link: http://net.tutsplus.com/tutorials/javascript-ajax/how-to-transition-an-image-from-bw-to-color-with-canvas/

  6. Very cool thing to do. I am currently using this on my portfolio site with a little x & y fun.

  7. Permalink to comment#

    I assume this can be done with just placing the images inside the HTML as well, rather than animating that background image. (It looks like it has been done like that in this demo).

    Then you can actually use it as a sufficient portfolio/featured slider. :)

  8. Cool Work!

    With CSS3 you can get really amazing effects!

  9. Jeager
    Permalink to comment#

    I’ve always figured there can be a easier way to do a slider with just css. However not working in many browsers is a bummer. Is there anyway to use Modernizr to make it work in those that do not?

    • jim vlagas
      Permalink to comment#

      modernizr see if it works , it doesnt correct the problem.. so if it is ie8 you have to use jquery or something to solve the problem because css3 not supported.

  10. Nice work!
    It’s awesome that we can make a slideshow just with CSS. Who imagined this ten years ago?

  11. The overlay image doesn’t line up? i.e. the colour one. Other than that it’s cool!

  12. Fantastic to be able to do this with CSS. It does seem to be just a little laggy (ie it will scroll for a few seconds and then pause for a few ms) on my desktop. Is anyone else seeing this, or is my desktop slow? Anyhow, its only a very small point.

    /Brian

  13. Maybe, the change from the ‘slower’ timeline to the ‘faster’ timeline can be ‘transitioned’ to avoid the ‘jerk’. The animation-duration, can it be transitioned/animated from a lower value to a higher value?

    Can the above ‘transitioning’ animation-duration be done with CSS3, or would it require resorting to JavaScript?

  14. Permalink to comment#

    Very cool CSS trick. I enjoyed it and thank you for sharing.

  15. DJ
    Permalink to comment#

    Chris… It’s interesting to watch you and see what things catch your interest. This solution is pretty out of the box and interesting. What could be done about the images not aligning following a (or several) hovers? Anything?

  16. PB
    Permalink to comment#

    Very cool, thanks for sharing!

  17. Permalink to comment#

    Is it just my machine or does this not work in IE9?

  18. Permalink to comment#

    In FF6/Win7, hovering over the slideshow causes a different portion of the image to show as colored. It’s not even close (e.g., often the B&W center of the image isn’t even shown during the color hover). Very disconcerting, almost felt like the color images were unrelated to the b&w even though i knew they weren’t.

  19. Amazing stuff:)
    Thanks a lot

  20. Came here from Smashing Mag’s twitter and having the same issue as a few other commenters have written – the colour version of the slideshow isn’t synched with the black and white version.

    Using Firefox beta 7.0, its clear both the colour and b/w versions are continuously being scrolled at their individual speeds regardless of which is currently displayed to the viewer. Screenie if it helps: http://www.damienking.net/slideshow.jpg

    Have to say, its a good use of CSS – inspiring me to delve deeper into what could be possible with CSS alone.

    • I mention that problem in the article. That is the correct behavior via the spec, and I’m not sure how to have it feel more like it’s speeding up. There may not be a practical way (or there may be, feel free to dig in to it!)

  21. Permalink to comment#

    Using ‘ease’ in the webkit animation instead of ‘linear’ has the interesting effect of gently slowing the animation for the last/first frame. This could be desirable if you wanted to give a visual emphasis to that particular image in the set.

  22. 7pearl
    Permalink to comment#

    Given Demo not working in ie6

  23. Raph
    Permalink to comment#

    Hello, this is a really great article but I can’t understand the trick.
    Which part of the code do this “then it quickly warps back to the original position and starts over.”?
    Because when I edit the jsfiddle and set 100% { left: -2000%; } to accelerate the process, at some point the image disappear!

  24. cool things, Thanks for get us some nice feature and idea to build imagination. WELL DONE,

    anyway i just try to get text instead of image like paragraph or h2 or others, ummmh let me do that

  25. Shujath
    Permalink to comment#

    I’m new to web designing!!
    I need a help. I want to have two slideshows with a logo image in middle.
    i have this code–” http://jsfiddle.net/chriscoyier/Hyg3C/1/ “please help me out to insert my logo in middle and move one sildeshow to left and other sildeshow to right. As in this website “http://www.mosa.nl/en/”. thanks in advance..

  26. sneha
    Permalink to comment#

    i want to scroll bottom to up how i can do?

  27. sneha
    Permalink to comment#

    how can i scroll it verticaly?

  28. Manan
    Permalink to comment#

    what if one want to add link on mouse hover?

  29. Joe
    Permalink to comment#

    This doesn’t work in IE, and I know that it’s from 2011 but here’s the fix (jsfiddle)

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".