2

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.

Ronny Efronny
  • 1,148
  • 9
  • 28

2 Answers2

1

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>
Bdeering
  • 338
  • 3
  • 14
  • 1
    This looks really clever. Instead of anumation the entire thing you seem to only be animating the percentage. That's rad. – Ronny Efronny Sep 14 '21 at 17:04
1

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>
A Haworth
  • 30,908
  • 4
  • 11
  • 14
  • This is a really cool solution! Will using `after` not cause issues if other things are in this `div`? Since `after` comes last usually. Would using `before` not be better? – Ronny Efronny Sep 14 '21 at 16:34
  • It depends on what you want of course. You'll probably want to position the pseudo element absolutely and set its z-index appropriately so it doesn't interfere with other stuff. And yes before would be more logical, but doesn't really make a difference if it's got absolute positioning. – A Haworth Sep 14 '21 at 16:38
  • I've edited the snippet to position the pseudo element absolutely and set its z index so it doesn't interfere with content in the div. – A Haworth Sep 14 '21 at 16:46