Creating seamless animation with CSS linear gradient

3.3k Views Asked by At

div {
  border-radius: 2rem;
  width: 10rem;
  height: 10rem;
  background-color: #0dd;
  background-image: 
    linear-gradient( 
      -45deg, 
      rgba( 0,0,0,0.125 ), transparent, rgba( 0,0,0,0.125 ), transparent
    );  
}

div {
  animation-name: diagonal_move;
  animation-duration: 6s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
@keyframes diagonal_move {
  0% {
    background-position: 0rem 0rem;
  }
  100% {
    background-position: 10rem 10rem;
  }
}
<html>
  <head>
    <style>
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
      }
      html, body {
        height: 100%;
      }
      body {
        display: flex;
        justify-content: center;
        align-items: center;
      }
    </style>
  </head>

  <body>
    <div></div>
  </body>
</html>

As the linear gradient above animates the edges of the gradient can clearly be seen - opposed to blending seamlessly with its surroundings.

A solution attempted to hide the edges was to overlay additional gradients on top:

div {
  border-radius: 2rem;
  width: 10rem;
  height: 10rem;
  background-color: #0dd;
  background-image: 
    linear-gradient( #0dd, transparent, transparent, transparent, #0dd ),
    linear-gradient( 90deg, #0dd, transparent, transparent, transparent, #0dd ),
    linear-gradient( 
      -45deg, 
      rgba( 0,0,0,0.125 ), transparent, rgba( 0,0,0,0.125 ), transparent
    ); 
}

div {
  animation-name: diagonal_move;
  animation-duration: 6s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
@keyframes diagonal_move {
  0% {
    background-position: 0rem 0rem;
  }
  100% {
    background-position: 10rem 10rem;
  }
}
<html>
  <head>
    <style>
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
      }
      html, body {
        height: 100%;
      }
      body {
        display: flex;
        justify-content: center;
        align-items: center;
      }
    </style>
  </head>

  <body>
    <div></div>
  </body>
</html>

The issue with this approach is it hides much of the original gradient along with the seams. It also creates bright lines where the seams would be.

So is there any way to flip or mirror gradients when they end to create a seamless pattern? Or perhaps the original gradient could be larger and zoomed out to give the illusion of a seamless pattern. How could this be implemented?

2

There are 2 best solutions below

0
On BEST ANSWER

Your gradient consists of 3 parts (between 4 reference points/color definitions), which creates a kind of "asymmetrical" structure since there's a different color at the end than at the beginning. If you add another reference point / color (same as first one), the gradient has the same color at the beginning and end and also in the other two corners of the square, and therefore the animation works smooth:

div {
  border-radius: 2rem;
  width: 10rem;
  height: 10rem;
  background-color: #0dd;
  background-image: 
    linear-gradient( 
      -45deg, 
      rgba( 0,0,0,0.125 ), transparent, rgba( 0,0,0,0.125 ), transparent, rgba( 0,0,0,0.125 )
    );  
}

div {
  animation-name: diagonal_move;
  animation-duration: 6s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
@keyframes diagonal_move {
  0% {
    background-position: 0rem 0rem;
  }
  100% {
    background-position: 10rem 10rem;
  }
}
<html>
  <head>
    <style>
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
      }
      html, body {
        height: 100%;
      }
      body {
        display: flex;
        justify-content: center;
        align-items: center;
      }
    </style>
  </head>

  <body>
    <div></div>
  </body>
</html>

0
On

In such case better consider a repeating gradient that is twice bigger than the element so you don't have to bother with specific values inside background-position:

.box {
  border-radius: 2rem;
  width: 10rem;
  height: 10rem;
  background-color:;
  background: 
    repeating-linear-gradient( 
      -45deg, 
      rgba( 0,0,0,0.125 ), transparent, rgba( 0,0,0,0.125 ) 25%
    ) bottom right/200% 200%
     #0dd;  
  animation: diagonal_move 6s linear infinite;
}

@keyframes diagonal_move {
  100% {
    background-position: top left;
  }
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin:0;
}
<div class="box"></div>

Related for more details around the values and the calculation: Using percentage values with background-position on a linear-gradient