0

I'm animating a background gradient by moving the background-position via animation. However, the transition from the end of the animation to the start of the next cycle isn't smooth. It should appear as if it's on a continuous loop. What am I missing?

CodePen

.gradient {
  width: 200px;
  height: 30px;
  background-image: linear-gradient(
      to right,
      red 8.33%,
      #ff9900 16.67%,
      yellow 25%,
      red 41.67%,
      #ff9900 58.34%,
      yellow 75.01%,
      red 83.34%
    );
    -webkit-animation: flow 3s ease infinite;
    -o-animation: flow 3s ease infinite;
    -ms-animation: flow 3s ease infinite;
    -moz-animation: flow 3s ease infinite;
    animation: flow 3s ease infinite;
    -webkit-animation: flow 3s ease infinite;
    background-size: 400% 100%;
    overflow: hidden;
}

@-webkit-keyframes flow {
    0% {
      background-position: -100% 50%;
    }
    100% {
      background-position: 100% 50%;
    }
  }

  @keyframes flow {
    0% {
      background-position: -100% 50%;
    }
    100% {
      background-position: 100% 50%;
    }
  }
<div class="gradient" />
imvain2
  • 15,480
  • 1
  • 16
  • 21
shainanigans
  • 872
  • 1
  • 6
  • 17
  • Change the background size, to something like " background-size: 50% 100%;" you'll see a smooth ease animation. I suggest making the background-gradient much larger -- to right, red 8.33%, #ff9900 16.67%, yellow 25%, red 41.67%, #ff9900 58.34%, yellow 75.01%, red 83.34% make this go to 100%, and only once through the cycle – d36williams Jul 07 '23 at 16:22

2 Answers2

1

You have set the width to 400% but you are only moving the background by a total of 200%.

Try making them match. This snippet just sets the keyframe translation to -400%.

.gradient {
  width: 200px;
  height: 30px;
  background-image: linear-gradient( to right, red 8.33%, #ff9900 16.67%, yellow 25%, red 41.67%, #ff9900 58.34%, yellow 75.01%, red 83.34%);
  -webkit-animation: flow 3s ease infinite;
  -o-animation: flow 3s ease infinite;
  -ms-animation: flow 3s ease infinite;
  -moz-animation: flow 3s ease infinite;
  animation: flow 3s ease infinite;
  -webkit-animation: flow 3s ease infinite;
  background-size: 400% 100%;
  overflow: hidden;
}

@-webkit-keyframes flow {
  0% {
    background-position: -400% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

@keyframes flow {
  0% {
    background-position: -400% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}
<div class="gradient" />

There is of course the question of whether you really want that stop-start effect brought on by the ease function - maybe you do but if not look at using linear.

A Haworth
  • 30,908
  • 4
  • 11
  • 14
  • This is so obvious I am ashamed of myself! Thanks for your help! – shainanigans Jul 07 '23 at 18:04
  • @shainanigans it's not really obvious because actually the correct value is not 400% but 133.33% (100% * 4/3) but since 400% is a multiplier of 133.33%, it will also work but the gradient will make 3 loops in the same animation – Temani Afif Jul 07 '23 at 19:52
0

I would first simplify your gradient using a repeating one since you are repeating some of the colors then the correct formula to update the position and have a cycle is (s/(s-1))*100% where s is the size factor.

In your case, s = 4 because you are using 400% so you need to move by 400%/3

.gradient {
  width: 200px;
  height: 30px;
  background-image: repeating-linear-gradient(90deg,red,#ff9900 12.5%,yellow 25%,red 50%);
  background-size: 400% 100%;
  animation: flow 2s linear infinite;
}

  @keyframes flow {
    100% {
      background-position: calc(400%/3);
    }
  }
<div class="gradient" ></div>

Related to get more detail about the calculation: Using percentage values with background-position on a linear-gradient

Temani Afif
  • 245,468
  • 26
  • 309
  • 415