CSS - infinite animation (moving to right loading gradient) is flickering

Viewed 12014

I was following this tutorial here: https://cloudcannon.com/deconstructions/2014/11/15/facebook-content-placeholder-deconstruction.html

to create a dummy loader. unfortunately this tutorial includes fixed pixel-values and I want it to work on screens of all sizes. so I adjusted the animation like this:

@keyframes placeHolderShimmer {
  0% {
    background-position: -30vw 0
  }
  100% {
    background-position: 30vw 0
  }
}

.c-animated-background {
  animation-duration: 1.5s;
  animation-fill-mode: forwards;
  animation-iteration-count: infinite;
  animation-name: placeHolderShimmer;
  animation-timing-function: linear;
  background: fff;
  background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%);
  height: 100%;
  width: 100%;
  position: relative;
  padding-top: 50px;
  -webkit-backface-visibility: hidden
}
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="style.css">
  <script src="script.js"></script>
</head>

<body class="c-animated-background">
</body>

</html>

Unfortunately on animation end after 1.5s, the grey area jumps either forward or back, depending on the keyframe-background-position values that I set. How can I prevent that and make the transition smooth? also, the animation seems to be more intense on the performance than I thought - when I want to inspect the background-element in dev mode in chrome with my macbook 2016', it hangs for around 15 seconds. should I perhaps use a transition/transform-animation instead?

Here is a plunker: https://plnkr.co/edit/X8PBIUYmAC11LCUV9uTy?p=preview

6 Answers

Please check the updated answer hope it is helpful to you. Currently i don't think it is necessary to move body. But you can define a division inside it and make it absolute which is relative to body.

VW doesn't work well when defined in negative value. Please check the updated answer

@keyframes placeHolderShimmer {
  0% {
    background-position: 0px 0;
  }
  100% {
    background-position: 100em 0;
  }
}

.c-animated-background {
  animation-duration: 3s;
  animation-fill-mode: forwards;
  animation-iteration-count: infinite;
  animation-name: placeHolderShimmer;
  animation-timing-function: linear;
  background: fff;
  background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%);
  height: 100%;
  width: 100%;
  position: absolute;
  padding-top: 50px;
  -webkit-backface-visibility: hidden;
  left:0;
  right:0;
  top:0;
  bottom:0;
}
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="style.css">
  <script src="script.js"></script>
</head>

<body>
 <div class="c-animated-background">
 </div>
</body>

</html>

There is no issue about the duration. Here you started with -30vh so end it with 70vh(100-30) as simple as for smooth transition. Check below snippet for reference.

@keyframes placeHolderShimmer {
  0% {
    background-position: -30vw 0
  }
  100% {
    background-position: 70vw 0
  }
}

.c-animated-background {
  animation-duration: 1.5s;
  animation-fill-mode: forwards;
  animation-iteration-count: infinite;
  animation-name: placeHolderShimmer;
  animation-timing-function: linear;
  background: fff;
  background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%);
  height: 100%;
  width: 100%;
  position: relative;
  padding-top: 50px;
  -webkit-backface-visibility: hidden
}
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="style.css">
  <script src="script.js"></script>
</head>

<body class="c-animated-background">
</body>

</html>

After 1.5 seconds the animation will start from 0. That's why it's flickering.

this works in jsfiddle:

0% {
  background-position: -30vw 0
}
100% {
  background-position: 70vw 0
}

See JSFiddle to make it more clear. It depends on the width of the screen.

Goodluck,

Fabian #Web-Stars

@keyframes placeHolderShimmer {
  0%   { background-position:  100%; }
  100% { background-position: -100%; }
}

.c-animated-background {
  animation: 3s linear infinite placeHolderShimmer;
  background: linear-gradient(to right, #eeeeee 0%, #dddddd 8%, #eeeeee 16%, #eeeeee 50%, #dddddd 58%, #eeeeee 66%);
  background-size: 200%;
  height: 100%; width: 100%;
}
<body class="c-animated-background"></body>

Try this piece of code.

What I did is converted keyframe values to from-to pairs because you only have 2 threshold values and there is no need to use % values.

Second,I gave width & height value according to viewport using viewport units.

If any issue comment below.

@keyframes placeHolderShimmer {
  from {
    background-position: -468px 0
  }
  to {
    background-position: 468px 0
  }
}

.animated-background {
  animation-duration: 1s;
  animation-fill-mode: forwards;
  animation-iteration-count: infinite;
  animation-name: placeHolderShimmer;
  animation-timing-function: linear;
  background: #f6f7f8;
  background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%);
  background-size: 800px 104px;
  width: 100vw;
  height: 100vh;
  position: relative;
}
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="style.css">
  <script src="script.js"></script>
</head>

<body>
  <div class="animated-background"></div>
</body>

</html>

test this:

@keyframes placeHolderShimmer{
    0% {
        background-position: -50vw 0
    }

    100% {
        background-position: 50vw 0
    }
}
Related