前几天我偶然遇到一个有趣的问题。 我想用随机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;
}
这可能非常适合您,但并不完全适合我。 预处理期间生成的随机数有一个很大的问题
Sass 中的随机数就像随机选择故事中主要角色的名字。 它只在写入时是随机的。 它不会改变。
— jake albaugh (@jake_albaugh) 2016 年 12 月 29 日
换句话说,一旦 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 中处理它要容易得多!
我真正想要的是 CSS 中的函数(不仅仅是随机数,因为它们的用例有限)以及定义它们的方法。 让我们看看 Houdini 能提供什么吧!
在看到
setTimeout
方法后,我立刻就想到了使用动画事件。 不过,由于某种原因,在 Firefox 和 Chrome 中监听animationiteration
会导致不稳定的闪烁。 https://codepen.io/jtojnar/pen/bgpNMK我在玩的时候也发现了完全相同的问题。 解决方案还没有找到。
我很惊讶您更改了 #red 中的 –animation-time,而不是 :root 中的 –animation-time。 其他使用 –animation-time 的地方可能需要相同的随机化。 只有 #red 会看到随机化,因为它在那里更改了。
如果您打算只让 #red 看到它,那么在那里定义它就足够了,无需在 :root 中定义,还是我遗漏了什么?
这说明了自定义属性的一个有趣方面:范围!
您好,
我脑子里刚想到一个不同的方法。 虽然不完全是随机的,但仍然是一个有效的想法。
您可以使用具有不同持续时间的 10 个 CSS 类。 然后使用 JS 添加其中随机的一个,或者甚至使用 PHP 将随机的一个提供给 HTML。
它不是 CSS 中的完美随机数,没错,但它仍然会产生相同的效果,而且依赖的最新功能更少。
另一种方法是使用多个元素(及其动画)和蝉原理
查看 CodePen 上 Kseso (@Kseso) 的 纯 CSS 随机动画。
由于caniuse表示 iOS 10 Safari 支持,我该如何让随机化在 iOS 10 Safari 中生效? 我一直都在得到相同的时间间隔。
我一直在阅读 Lea Verou 的 CSS secrets 一书,她使用“蝉原理”https://www.sitepoint.com/the-cicada-principle-and-why-it-matters-to-web-designers/来制作随机的背景宽度,这可以应用到这里。