CSS 中的随机数

Avatar of Robin Rendle
Robin Rendle 发布

DigitalOcean 为您的旅程的每个阶段提供云产品。 立即开始使用 $200 的免费积分!

前几天我偶然遇到一个有趣的问题。 我想用随机animation-duration来动画一个元素。 这是非随机化的起点

查看 CodePen 上 Robin Rendle (@robinrendle) 的 随机数 CSS #1

这是我用来制作动画的 CSS 代码

@keyframes flicker {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

#red {
  animation: flicker 2s ease alternate infinite;
}

到目前为止一切顺利。 但是那里没有随机化,那是固定的 2 秒。

我希望那 2 秒的动画时间是随机的。 我想写

.element {
  animation: flicker $randomNumber alternate infinite;
}

其中$randomNumber是通过编程随机生成的。

像 Sass 这样的 CSS 预处理器确实提供了一个random() 函数

$randomNumber: random(5);

.thing {
  animation-duration: $randomNumber + s;
}

这可能非常适合您,但并不完全适合我。 预处理期间生成的随机数有一个很大的问题

换句话说,一旦 CSS 被处理,随机化就结束了。 该数字永远固定在该值上(即直到预处理器再次运行)。

它不像 JavaScript 中的随机数(例如Math.random()),其中随机数是在 JavaScript 运行时生成的。

因此,在我尽可能大声地叹气后,我意识到这实际上是使用原生 CSS 变量(自定义属性)的绝佳机会! 它们本身无法更轻松地生成随机数,但正如我们将在下面看到的那样,它们仍然可以帮助我们。

如果您不熟悉它们,不用担心。 实际上,它们是内置到 CSS 语言本身的原生变量,但它们不同于您可能从 Sass 或 Less 等预处理器中熟悉的变量类型。 Chris 之前列出了许多优点

  • 您可以在无需预处理的情况下使用它们。
  • 它们级联。 您可以在任何选择器中设置一个变量来设置或覆盖其当前值。
  • 当它们的值发生改变(例如媒体查询或其他状态)时,浏览器会根据需要重新绘制
  • 您可以使用 JavaScript 访问和操作它们

最后一点对我们很重要。 我们将在 JavaScript 中生成随机数,然后通过自定义属性将其移到 CSS 中。

第一步是创建我们需要的 CSS 自定义属性,并使用默认值(如果我们稍后编写的 JavaScript 由于任何原因而失败,这将很有用)

/* set the default transition time */
:root {
  --animation-time: 2s; 
}

现在,我们可以像这样在 CSS 中使用该变量

#red {
  animation: flicker var(--animation-time) ease alternate infinite;
}

毫不奇怪,我们回到了起点。 但是,虽然此演示现在看起来与我们之前动画的 SVG 完全一样,但此演示使用的是 CSS 变量。 您可以通过更改 CSS 中的变量并观察动画更新来测试一切是否正常。

现在我们已经准备好通过 JavaScript 访问和操作该自定义属性。

var time = Math.random();

从这里我们可以找到 SVG 中的红色圆圈,并通过setProperty方法更改--animation-time CSS 变量

var red = document.querySelector('#red');
red.style.setProperty('--animation-time', time +'s');

它就在这里! 一个在 CSS 中随机生成的数字,正被应用于 SVG 动画

查看 CodePen 上 Robin Rendle (@robinrendle) 的 随机数 CSS #3

这是一项进步,因为随机数是在 JavaScript 运行时生成的,所以每次都不一样。 这非常接近我们想要的结果,但让我们更难一些:让我们在运行期间定期随机化该animation-duration

幸运的是,我们现在可以使用 JavaScript,因此我们可以随时更新该自定义属性。 以下是一个每秒更新animation-duration的示例

var red = document.querySelector('#red');

function setProperty(duration) {
  red.style.setProperty('--animation-time', duration +'s');
}

function changeAnimationTime() {
  var animationDuration = Math.random();
  setProperty(animationDuration);
}

setInterval(changeAnimationTime, 1000);

这正是我想要的结果

查看 CodePen 上 Robin Rendle (@robinrendle) 的 随机数 CSS #4

值得记住的是CSS 变量(自定义属性)的支持仍然有点零散,所以要注意。 尽管我们可以像这样逐步增强此动画

#red {
  animation: flicker .5s ease alternate infinite;
  animation: flicker var(--animation-time) ease alternate infinite;
}

如果 CSS 变量不受支持,我们仍然会看到某种动画,即使它不完全是我们想要的。


值得注意的是,CSS 变量不是随机化动画持续时间的唯一可能方法。 我们可以通过 JavaScript 访问 DOM 元素,并将随机值直接应用到style

var red = document.querySelector('#red');
red.style.animationDuration = Math.floor(Math.random() * 5 + 1) + "s";

如果需要,我们甚至可以在动画结束之前设置新的持续时间

var red = document.querySelector('#red');

function setRandomAnimationDuration() {
  red.style.animationDuration = Math.floor(Math.random() * 10 + 1) + "s";
}

red.addEventListener("animationiteration", setRandomAnimationDuration);

为了在此处添加更多可能性,您还可以使用EQCSS

@element '#animation' {
  .element {
    animation-duration: eval('rand')s;
  }
}
var rand = Math.random();
EQCSS.apply();

这是最简单的演示实际的演示


您是否希望 CSS 本身提供随机化? 我不确定是否有人讨论过这个问题。 即使有,我们也可能需要等待相当长的时间才能真正使用它。 与此类似,Philip Walton 最近写了一篇关于在 CSS 中编写真正的随机数 polyfill 的困难程度。 在 JavaScript 中处理它要容易得多!