Is it possible to use <hue-interpolation-method> with animations or transitions?

76 Views Asked by At

Is it possible to specify a <hue-interpolation-method> for anything other than gradients; specifically: transitions or animations?

.box {
  width: 300px;
  height: 50px;
}

.box.gradient {
  background: linear-gradient(90deg in hsl longer hue, red, blue);
}

.box.transition {
  background: red;
  transition: 1s all;
}
  .box.transition:hover {
    background: blue;
  }
  
.box.animation {
  animation-name: color;
  animation-duration: 2s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

@keyframes color {
  0% {
    background: red;
  }
  100% {
    background: blue;
  }
}
Linear-gradient using hue interpolation:
<div class="box gradient"></div>
<br><br>
Transition (hover) -- how do I get it to use the hue interpolation?
<div class="box transition"></div>
<br><br>
Animation -- how do I get it to use the hue interpolation?
<div class="box animation"></div>

2

There are 2 best solutions below

0
Kaiido On BEST ANSWER

There is an active discussion to add a transition-interpolation property that should cover it, but it's not yet ready.

One other property that does use the<hue-interpolation-method> is the color-mix() function, which actually has even better browser support than in gradients.

However to animate this is not that easy.

One way is to define @property variables that we'll use as the percentage parameters of color-mix and animate the custom variables instead.

@property --red {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}
@property --blue {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}
.box {
  width: 300px;
  height: 50px;
  --red: 100%;
  --blue: 0%;
  background: color-mix(in hsl longer hue, red var(--red), blue var(--blue));
  transition-duration: 2s;
  /* Do not set background-color here ! */
  transition-property: --red, --blue;
}
.box.transition:hover {
  --red: 0%;
  --blue: 100%;
}
.box.animation {
   animation: anim 2s infinite;
}

@keyframes anim {
  from {
    --red: 100%;
    --blue: 0%;
  }
  to {
    --red: 0%;
    --blue: 100%;
  }
}
transition<div class="box transition"></div>
animation<div class="box animation"></div>

For browsers that don't support the @property rule and thus animating custom variables (basically Gecko based browsers), you can create an animation with a lot of keyframes:

const FPS = 60;
const duration = 2000;
const frames = FPS / (1000 / duration);
const keyframes = Array.from({ length: frames }, (_, i) => {
  const start = (i / frames) * 100;
  const end = 100 - start;
  return {
    background: `color-mix(in hsl longer hue, red ${end}%, blue ${start}%)`
  };
});
document.querySelector(".transition").addEventListener("mouseenter", (evt) => {
  const anim = evt.target.getAnimations()[0];
  if (anim) {
    anim.reverse();
  } else {
    evt.target.animate(
      keyframes,
      { duration, iterations: 1, fill: "forwards" }
    );
  }
});

document.querySelector(".transition").addEventListener("mouseout", (evt) => {
  const anim = evt.target.getAnimations()[0];
  if (anim) {
    anim.reverse();
  }
});

document.querySelector(".animation").animate(
  keyframes,
  { duration, iterations: Infinity }
);
.box {
  width: 300px;
  height: 50px;
  background: red;
}
transition<div class="box transition"></div>
animation<div class="box animation"></div>

1
Temani Afif On

One hacky idea is to keep using the gradient and transition the position:

.box {
  width: 300px;
  height: 50px;
  background-image: linear-gradient(90deg in hsl longer hue, red, blue);
}

.box.transition {
  background-size: 10000% 100%; /* a very big width to see only colors and no transitions */
  background-position: left;
  transition: 1s all;
}

.box.transition:hover {
  background-position: right;
}

.box.animation {
  background-size: 10000% 100%;
  animation-name: color;
  animation-duration: 2s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

@keyframes color {
  0% {
    background-position: left;
  }
  100% {
    background-position: right;
  }
}
Linear-gradient using hue interpolation:
<div class="box gradient"></div>
<br><br> Transition (hover) -- how do I get it to use the hue interpolation?
<div class="box transition"></div>
<br><br> Animation -- how do I get it to use the hue interpolation?
<div class="box animation"></div>