CSS: Animate Partial Linear Gradient Background

Viewed 352

I have a div where the background is divided as follows:

div {
  width: 200px;
  height: 50px;
  background: linear-gradient(135deg, gray 0%, gray 70%, blue 70%, blue 85%, red 85%);
}

div:hover {
  animation: animate .5s ease forwards;
}

@keyframes animate {
  0% {
    background: linear-gradient(135deg, gray 0%, gray 70%, blue 70%, blue 85%, red 85%);
  }
  
  100% {
    background: linear-gradient(135deg, gray 0%, gray 50%, blue 50%, blue 75%, red 75%);
  }
}
<div></div>

As you can see, I would like the stripes in the background to shift on hover (and, indeed, shift back on leave). I saw all the tutorials suggesting to use background-size and background-position but as I need the proportions to actually change, I don't know that that is the solution here.

I'd like the gradient proportion to animate smoothly, instead of just clipping like they do in the above snippet.

2 Answers

Take a look at the second and third answers from this post. By animating the opacity of two different gradients or using css variables alongside a transition, you should be able to get the desired result.

I've set up an example of the second method using your code:

@property --gb { /* grey/blue */
  syntax: '<percentage>';
  inherits: false;
  initial-value: 70%;
}
@property --br { /* blue/red */
  syntax: '<percentage>';
  inherits: false;
  initial-value: 85%;
}

div {
  --gb: 70%;
  --br: 85%;
  
  width: 200px;
  height: 50px;
  transition: --gb 2s, --br 2s;
  background: linear-gradient(135deg, gray 0%, gray var(--gb), blue var(--gb), blue var(--br), red var(--br));
}

div:hover {
  --gb: 50%;
  --br: 75%;
}
<div></div>

As you have disovered, linear gradients as you have them don't animate.

One simple way of getting a similar but smooth effect is to use scale, which is animatable.

This snippet draws the linear-gradient on a pseudo element and transitions the scale on that, having put the transform origin to the bottom right hand corner. The div has overflow set to hidden.

    div {
      width: 200px;
      height: 50px;
      overflow: hidden;
      position: relative;
    }

    div::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      display: inline-block;
      width: 100%;
      height: 100%;
      transform: scale(1);
      transform-origin: right bottom;
      transition: transform .5s ease;
      background: linear-gradient(135deg, gray 0%, gray 70%, blue 70%, blue 85%, red 85%);
      z-index: -1;
    }

    div:hover::before {
      transform: scale(1.5);
    }
<div>SOME CONTENT</div>

Related