如何在纯 JavaScript 和 CSS 中实现平滑过渡?

How to get smooth transitions in pure JavaScript and CSS?

我有 div 个带有黑色背景颜色的元素,它们获取和释放 class animated 具有动画彩色背景的 css 定义。动画工作顺利。但是从黑色到动画状态的变化并没有。我尝试了一些过渡规则,但我无法弄清楚如何获得平滑的变化。

这是我的最小示例:

let randomNumber;
let boxes = document.querySelectorAll(".dark");
let randomNumbers = [];
let milliseconds = 2000;
setInterval(function() {
  randomNumber = Math.floor(Math.random() * boxes.length);
  randomNumbers.push(randomNumber);
  boxes[randomNumber].className = boxes[randomNumber].className.replace(/(?:^|\s)dark(?!\S)/g, " animated");
  setTimeout(function() {
    boxes[randomNumbers[0]].className = boxes[randomNumbers[0]].className.replace(/(?:^|\s)animated(?!\S)/g, " dark");
    randomNumbers.shift();
  }, boxes.length * milliseconds);
}, milliseconds);
@keyframes animated_background_color {
  0% {
    background-color: #e66000;
  }
  25% {
    background-color: #ff9500;
  }
  50% {
    background-color: #ffcb00;
  }
  75% {
    background-color: #ff9500;
  }
  100% {
    background-color: #e66000;
  }
}

.box {
  height: 20px;
  margin-bottom: 4px;
  width: 20px;
}

.dark {
  background-color: black;
}

.animated {
  animation-name: animated_background_color;
  animation-duration: 3s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  background-color: #e66000;
}
<!DOCTYPE html>

<html>

<head>
  <title>Animation</title>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
</head>

<body>
  <div class="box dark"></div>
  <div class="box dark"></div>
  <div class="box dark"></div>
  <div class="box dark"></div>
  <div class="box dark"></div>
</body>

</html>

您的起始颜色和结束颜色不是黑色,这就是您看到变化的原因之一。将您的 0% 和 100% 值替换为 background-color: black;

一旦这个问题得到解决,你的 milliseconds 变量就会有问题,因为它不是动画时间的分隔符(这里是 5*2000ms,这意味着 .animated class 移除class 在 10s 当你的动画周期是 3s)


奖金:我不知道为什么我清理和修改了你的代码,但我做到了。 (我累了,丑了)

const DARK_SELECTOR = ".dark";
const DARK_CLASS = "dark";
const ANIMATED_CLASS = "animated";
const ANIMATION_CYCLE_TIME = 2000;
const TOTAL_ANIMATION_TIME = 3 * ANIMATION_CYCLE_TIME;
const TIME_BETWEEN_ANIMATIONS = 1.5 * ANIMATION_CYCLE_TIME;

function animateRandomBox(animationTime) {
  const darkBoxes = document.querySelectorAll(DARK_SELECTOR);
  const numberOfDarkBoxes = darkBoxes.length;
  if (numberOfDarkBoxes === 0) {
    return;
  }
  const randomBoxNumber = Math.floor(Math.random() * numberOfDarkBoxes);
  const randomBoxClass = darkBoxes[randomBoxNumber].classList;
  randomBoxClass.remove('dark');
  randomBoxClass.add('animated');
  setTimeout(() => {
    randomBoxClass.add('dark');
    randomBoxClass.remove('animated');
  }, animationTime);
}

setInterval(() => animateRandomBox(TOTAL_ANIMATION_TIME), TIME_BETWEEN_ANIMATIONS);
@keyframes animated_background_color {
  0% {
    background-color: #000;
  }
  25% {
    background-color: #ff9500;
  }
  50% {
    background-color: #ffcb00;
  }
  75% {
    background-color: #ff9500;
  }
  100% {
    background-color: #000;
  }
}

body {
  display: grid;
  grid-auto-rows: min-content;
  row-gap: 0.25rem;
}

.box {
  height: 1rem;
  width: 1rem;
  border-radius: 0.5rem;
}

.dark {
  background-color: black;
}

.animated {
  animation-name: animated_background_color;
  animation-duration: 2s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
<!DOCTYPE html>

<html>

<head>
  <title>Animation</title>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
</head>

<body>
  <div class="box dark"></div>
  <div class="box dark"></div>
  <div class="box dark"></div>
  <div class="box dark"></div>
  <div class="box dark"></div>
</body>

</html>

根据 of devdgehog,我决定添加更多关键帧。现在我从黑暗状态切换到动画状态,然后再次切换回来,第一个和最后一个关键帧设置深色背景,其他关键帧从橙色切换到亮橙色再到黄色再到亮橙色再到橙色连续三次。

const DARK_SELECTOR = ".dark";
const DARK_CLASS = "dark";
const ANIMATED_CLASS = "animated";
const ANIMATION_CYCLE_TIME = 6000;

function animateRandomBox(animationTime) {
  const darkBoxes = document.querySelectorAll(DARK_SELECTOR);
  const numberOfDarkBoxes = darkBoxes.length;
  if (numberOfDarkBoxes === 0) {
    return;
  }
  const randomBoxNumber = Math.floor(Math.random() * numberOfDarkBoxes);
  const randomBoxClass = darkBoxes[randomBoxNumber].classList;
  randomBoxClass.remove('dark');
  randomBoxClass.add('animated');
  setTimeout(() => {
    randomBoxClass.add('dark');
    randomBoxClass.remove('animated');
  }, animationTime);
}

setInterval(() => animateRandomBox(ANIMATION_CYCLE_TIME), ANIMATION_CYCLE_TIME);
@keyframes animated_background_color {
  0% {
    background-color: #000;
  }
  12% {
    background-color: #ff9500;
  }
  25% {
    background-color: #ffcb00;
  }
  37% {
    background-color: #ff9500;
  }
  50% {
    background-color: #ffcb00;
  }
  62% {
    background-color: #ff9500;
  }
  75% {
    background-color: #ffcb00;
  }
  87% {
    background-color: #ff9500;
  }
  100% {
    background-color: #000;
  }
}

body {
  display: grid;
  grid-auto-rows: min-content;
  row-gap: 0.25rem;
}

.box {
  height: 1rem;
  width: 1rem;
  border-radius: 0.5rem;
}

.dark {
  background-color: black;
}

.animated {
  animation-name: animated_background_color;
  animation-duration: 6s;
  animation-timing-function: linear;
}
<!DOCTYPE html>

<html>

<head>
  <title>Animation</title>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
</head>

<body>
  <div class="box dark"></div>
  <div class="box dark"></div>
  <div class="box dark"></div>
  <div class="box dark"></div>
  <div class="box dark"></div>
</body>

</html>