3

I'm trying to animate a background image position smoothly with CSS over a longer period, let's say 60 seconds:

#movingbackground {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-image: url('https://upload.wikimedia.org/wikipedia/commons/thumb/6/68/Bigsurflowers.jpg/1280px-Bigsurflowers.jpg');
  overflow: hidden;
  background-position: left center;
  animation: zoomin 60s ease-in infinite;
}

@-webkit-keyframes zoomin {
  0% { background-position: 0% center; transform: scale(1.0); }
  50% {background-position: 100% center; transform: scale(1.2); }
  100% { background-position: 0% center; transform: scale(1.0); }
}
@keyframes zoomin {
  0% { background-position: 0% center; transform: scale(1.0); }
  50% {background-position: 100% center; transform: scale(1.2); }
  100% { background-position: 0% center; transform: scale(1.0); }
}
<div id="movingbackground"></div>

The small movements in the beginning and end are "jumping" a few pixel every second instead of moving slowly (may depend on screen size).

The reason for that is probably that there is not enough movement to fill the required number of frames, especially when the animation is eased. As I think I have seen this effect working smoothly somewhere I wonder how to work around this.

Here's a Fiddle as well.

user127091
  • 2,071
  • 2
  • 9
  • 16
  • Questions seeking code help must include the shortest code necessary to reproduce it **in the question itself** preferably in a **Stack Snippet**. Although you have provided a link, if it was to become invalid, your question would be of no value to other future SO users with the same problem. See [**Something in my website/example doesn't work can I just paste a link**](http://meta.stackoverflow.com/questions/254428/something-in-my-web-site-or-project-doesnt-work-can-i-just-paste-a-link-to-it). – Paulie_D Apr 01 '19 at 15:38
  • 1
    `linear` instead of `ease-in` is probably what you are looking for – Temani Afif Apr 01 '19 at 15:42

2 Answers2

4

Animation of background-position makes browser to do layout, paint and composite.
Re-layout and re-paint are heavy on CPU and cause "jumping".

Instead of that, you might apply your background to pseudo-element (or use <img> in your HTML) and animate its transform property using 3d transformation.

It will make browser to use GPU for the animation and animation will run in composition phase pretty smoothly.

See the snippet below:

html,
body {
  margin: 0;
  padding: 0
}

#movingbackground {
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

#movingbackground:before {
  content: '';
  position: absolute;
  top: 0; left: 0; z-index: -1;
  height: 100%;
  width: 200%;
  background: url(https://upload.wikimedia.org/wikipedia/commons/thumb/6/68/Bigsurflowers.jpg/1280px-Bigsurflowers.jpg) 0 50% / cover;
  animation: zoomin 60s ease-in infinite;
}

@keyframes zoomin {
  50% {
    transform: translateX(-50%) scale(1.2)
  }
}
<div id="movingbackground"></div>
Kosh
  • 16,966
  • 2
  • 19
  • 34
  • The advantage of using background-position is that it does move the picture to the full right even on small portrait screens and it doesn't require scaling the image to 200% width on larger screens in landscape. I'll try to work around that with orientation media queries or whatever and then come back here. By the way: I think it's not just GPU vs CPU, otherwise promoting the image with translateZ or will change would do the trick as well. I guess transform enables sub-pixel movements while background-position doesn't. Anyway, it's better ;-) – user127091 Apr 02 '19 at 09:59
  • @user127091, thank you for your note! You don't have to stick to `200%`, this is just an example. Also `translateZ` is not a "magic pill" -- it won't help if browser does re-layout / re-paint. – Kosh Apr 02 '19 at 14:00
1

I did some testing and came to the conclusion that it's probably impossible. (At least with transitions or animations)

The problem is the way browsers render images on a screen. The pixels of the image apparently get lined up with those of your screen.

So the picture always "jumps" exactly one pixel at a time.

That means, that the more pixels you have in your image, the more steps it will make. But when using ease-in it will always stutter in the beginning.


As I think I have seen this effect working smoothly somewhere

That was probably not realized with css.

Johey
  • 275
  • 1
  • 8