The “trick” of sliding backgrounds in CSS is not new. In fact, the first time I came across it might have been a couple of years ago on the Valio Con site (the current design doesn’t have it anymore). I happened to notice it on a couple of new sites I visited today, however, and thought it would be worth sharing.
This is the effect we’re after:
See the Pen gamYOy by CSS-Tricks (@css-tricks) on CodePen.
Notice that this is different from a CSS slideshow or carousel, where the the content is separated into slides that can be stopped at. There are great examples of those all over CodePen.
This technique takes the background of one element and slides it across the x-axis infinitely in a loop to create the effect of a never-ending and always moving background.
Setting up the HTML
This is sort of a blueprint of how our HTML needs to be structured:

There is one element that fits the exact width of the viewport, and another that runs through and overflows it. That means we only need to create two elements in the HTML markup: one for the background, and another to act as a containing wrapper for that background.
<div class="wrapper">
<div class="sliding-background"></div>
</div>
Positioning the Elements
Let’s go ahead and add some CSS that will correctly position our two elements.
.wrapper {
overflow: hidden;
}
.sliding-background {
height: 500px;
width: 5076px;
}
Our .wrapper
is 100% of browser width by default (that’s how block-level elements are), and we’ve added an overflow
property that will hide anything that is visually contained outside of it. Think of it like a crop on a photograph. There may be extra stuff outside the wrapper, but the wrapper is preventing us from seeing it.
That’s where our .sliding-background
comes into play. It is set to some ridiculous width that would overflow most viewports. And that’s the trick: it should be something that would overflow the wrapper. In this case, I somewhat arbitrarily chose a 5076px
width.
Creating the Background Image
We need an image if we’re going to scroll something across the screen, right? That’s our next order of business.
Remember how I mentioned that I had somewhat arbitrarily chosen 5076px
as the width for the sliding background? Well, it is arbitrary, but intentional in the sense that it is nicely divisible by 3, which fits into the timing for a minute-long loop, which will come up a little later. That means the canvas for our background image is 5076 / 3
or 1692px
. In the end, our background will repeat a total of three times in one minute in an infinite loop. Math for the win!
The 500px
height is truly arbitrary. That can be whatever you want and will act as the height of the canvas for the background image.
Here’s the Photoshop template used in this example to get you started:
Save (and optimize!) the image. This is what we’ll use as the background image in the CSS:
.sliding-background {
background: url("..path/to/image") repeat-x;
height: 500px;
width: 5076px;
}
Great! That gives us the ginormous image that overflows the wrapper and can now be used to scroll across the screen ad infinitum.
The Sliding Effect
All right, let’s make this bad boy move. We want it to go from left to right in a loop that repeats over and over to create a seamless effect that the image goes on forever.
First, let’s define the CSS animation:
@keyframes .slide {
0%{
transform: translate3d(0, 0, 0);
}
100%{
transform: translate3d(-1692px, 0, 0);
}
}
We’re using the transform
property to position the left image at the left edge of the wrapper when the animation begins, like so:

By the time the animation has completed, it will have transformed the position negatively (from left to right) by an amount that matches the exact width of our image. And, since the .sliding-background
is three times the width of the actual image, the image repeats three times between 0% and 100% before looping again.
Note: the reason we’re using an additional <div>
at all, rather than animating background-position
on the main <div>
, is so that we can use an animated transform
to do the movement, which is much more performant.
OK, let’s round things out by calling our slide
animation on the .sliding-background
class:
.sliding-background {
background: url("..path/to/image") repeat-x;
height: 560px;
width: 5076px;
animation: slide 60s linear infinite;
}
The animation
property instructs the .sliding-background
to use the slide
animation and to run it for one minute at a time in a linear, infinite loop.
Putting it All Together
<div class="wrapper">
<div class="sliding-background"></div>
</div>
.wrapper {
overflow: hidden;
}
.sliding-background {
background: url("..path/to/image") repeat-x;
height: 560px;
width: 5076px;
animation: slide 60s linear infinite;
}
@keyframes slide{
0%{
transform: translate3d(0, 0, 0);
}
100%{
transform: translate3d(-1692px, 0, 0);
}
}
Here’s the final result:
See the Pen gamYOy by CSS-Tricks (@css-tricks) on CodePen.
Nice, i never thought about this.
Cool trick!
No undertaker?
not cool :(
Sorry man! I also inadvertently left out one of the best of them all, the Junkyard Dog.
Great article…loves these types of articles…quick easy to learn tricks with great results…Thanks for sharing this…
Thanks for the article! I’m looking for something like this but I would like to slide diagonally and zooming as well. I think it would be great to have a large (hero) image of an overview and than zoom in to a specific detail of the bigger picture.
Why is the BG div 3 times the width of the image? Double (3384px) is just enough, or am I wrong?
And the image scrolls only one time completely in the minute before it loops. I hope it makes sense. English is not my native language. :)
Yeah, it could be double, for sure. I like having an absurdly large width in the case of larger monitors, but that all depends on the design in the end. :)
Is there any benefit to using translate3d() over background-position? I’ve done the same thing with the latter, is there any reason I should’ve used translate3d() instead?
I think transform is hardware accelerated and background-position is not.
translate3d() is hardware accelerated, meaning far better performance on mobile and tablet devices.
“Remember how I mentioned that I had somewhat arbitrarily chosen 5075px as the width for the sliding background? Well, it is arbitrary, but intentional in the sense that it is nicely divisible by 3”
Is it?
Ha! Perhaps with one more pixel, eh? There go my poor math skills, fully on display. :)
Thanks for sharing. This has just made work a lot more easier for me.