转自:使用三角函数的 CSS 中的随机性 (hypersphere.blog)
过去,我已经使用模运算在CSS中介绍了伪随机性的主题,并使用质数创建了一个自动计数器,可用于为每个对象生成不同的值。多亏了这一点,我们可以独立计算每个元素的伪随机值。
尽管此解决方案功能强大,但它几乎没有缺点:
- 模函数不连续
- 它过于复杂:需要 3 个变量和我们想要生成的每个随机值的定义
@property - 需要使用尚未得到广泛支持的
@property
幸运的是,我们可以做得更好!在本文中,我想提出一个使用三角学的更好的解决方案。
更好的方法#
自从我上次探索这个主题以来,CSS 中出现了新的惊人功能。最令人兴奋的新增功能之一是三角函数。他们解锁了许多以前不可能完成的任务。它们也是 CSS 中原生支持的第一个有界连续函数,使其成为创建伪随机生成器的绝佳工具。
随机性与伪随机性#
显然,这里提供的解决方案仅生成伪随机值。所有值均使用预定常量计算。正如我在上一篇文章中所描述的,我们可以添加一个额外的变量并从系统外部更改它(例如,在加载时在 JavaScript 中设置它)以提供不太确定的结果,但 CSS 不提供任何非确定性方法。也就是说,该解决方案应该足以为动画、位置等获得足够的伪随机值。如果你想用它来解决你的加密函数,你可能没有使用适当的技术开始 😉--seed
正弦函数的特征#
正弦和余弦函数很有趣,原因有很多。它们在涉及圆圈和旋转的各种操作中非常有用。不过,在我们的例子中,我们可以将它们的属性用于其他目的。
有界函数#
正弦和余弦的一大特性是结果值始终限定在 -1 和 1 之间。这意味着,无论您传递给它的值有多大或多小,结果将始终是此范围内的值。然后,我们可以对范围执行简单的归一化。有了归一化值,我们可以使用它来表示任何值,使用简单的线性映射。[0,1]
--x: calc(0.5 + 0.5 * sin(var(--n) * 342.06184 + 23.434));
/* Then we can use it as following */
background: rgb(calc(50 + var(--x) * 100), 0, 0);
/* Red will be in the range of 50-150.
上面的代码使用我在上一篇文章中介绍的计数器,其中我使用质数来创建一种在 CSS 中自动创建计数器变量的有效方法。var(--n)
然后将该值乘以并偏移一些任意值以提供伪随机大数(这些值并不重要,您可以根据需要更改它们以获得不同的结果)。之后,我们使用正弦函数将其映射到 范围 .最后,如下面的动画所示,我们可以通过应用简单的代数变换将其映射到范围。一旦我们从范围中获得值,我们就可以使用线性映射将其映射到任何其他期望的值。[-1, 1]``[0, 1]``[0, 1]
连续性#
正弦函数的另一个特征是连续性。您可以在此处探索连续性的完整形式定义,但为了简单起见,您可以认为正弦或余弦函数输入中的小变化最终会导致输出的微小变化。多亏了这一点,我们可以在动画时实现值的逐渐变化,同时仍然让系统随机运行。
例子#
以下是一些示例,演示了使用三角函数生成伪随机值的潜力。
圆圈网格#
第一个示例显示了操作中的正弦属性。生成的值是随机的,但在颜色和大小动画方面,我们仍然可以保持顺序和连续感。
代码的关键部分是x,y,z和w变量的计算,这些变量分别用于表示红色,绿色,蓝色和宽度。
div::before {
--x: calc(0.5 + 0.5 * sin(4.284 * var(--n)));
--y: calc(0.5 + 0.5 * sin(7.284 * var(--n)));
--z: calc(0.5 + 0.5 * sin(4 * var(--n) + 2 * var(--t)));
--w: calc(0.5 + 0.5 * sin((0.2 * cos(var(--t)/100) + 0.8) * 49.123 * var(--n) + var(--t)));
background: rgb(
calc(50 + 100 * var(--x)),
calc(200 + 30 * var(--y)),
calc(120 + 100 * var(--z))
);
width: calc(50% + var(--w)*50%);
}
最后 2 个变量,除了我们的计数器 ,使用时间变量,该变量是通过运行逐渐更改变量的动画获得的:--n``--t
@property --t {
syntax: '<number>'; /* <- defined as type number for the transition to work */
initial-value: 0;
inherits: true;
}
:root {
--t: 0;
}
@keyframes timeOn {
50% {--t: 30}
}
html {
animation: 30s timeOn infinite linear;
}
这是代码中唯一使用 .为了使它在所有浏览器中都能正常工作,我们可以简单地在 JavaScript 中更新这个变量,而不会失去在普通 CSS 中计算其他所有内容的能力。@property
斑点#
随机性也可以与 SVG 元素一起使用,使其成为与 SVG 过滤器结合使用时的强大工具。下面的演示灵感来自一篇令人惊叹的 CSS 技巧文章 粘稠效应.
每个单独斑点的位置使用简单的公式确定。唯一的区别是我们使用 cx、cy、r 和填充来设置它们的样式,因为它们是 SVG 元素。
.blobs > circle {
--x: calc(sin(var(--t) + var(--n) * 74.543 + 432.43312));
--y: calc(cos(var(--t) + var(--n) * 2.34 + 1.432));
--v: calc(0.5 + 0.5 * sin(var(--n) * var(--n) * 4.343 + 2.673));
cx: calc(10vw + var(--x) * 80vw);
cy: calc(10vh + var(--y) * 80vh);
r: calc(var(--v) * 5vw + 1vw);
}
为了达到粘稠的效果,我们使用以下 SVG 滤镜:
<filter id="goo">
<feGaussianBlur in="SourceGraphic" result="blur" stdDeviation="15" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 22 -11" result="goo" />
<feBlend in2="goo" in="SourceGraphic" result="mix" />
</filter>
孟菲斯模式#
最后一个演示是我之前尝试在 CSS 中实现随机性时使用的示例的更新版本,其中我使用了模运算符。使用新的解决方案,计算更容易理解和修改。