CSS中如何实现伪随机?

5,207 阅读4分钟

今天看《CSS揭秘》,学到了一个有趣的知识点:怎么实现伪随机?

觉得既有趣,又有启发,这里记录分享一下。

问你个问题,什么叫随机呢?

我们可以从相反的角度来思考,先回答什么叫不随机。

不随机就是有一定规律可循,比如下图中的颜色出现就是有规律的:

从图上可以看出红绿蓝这三种颜色,每隔六次就整体重复一遍。

上图是我使用 CSS 实现并截图的。这里仔细看一下源码:

div:nth-child(n){
  background: red;
}
div:nth-child(2n+1){
  background: green;
}
div:nth-child(3n+2){
  background: blue;
}

因为 1、2、3的最小公倍数是 6,所以颜色分布规律的周期是 6。

这里要强调的我们说的颜色整体分布规律,是不考虑 CSS 层叠机制带来的影响。

比如如下的代码:

div:nth-child(2n){
  background: red;
}
div:nth-child(n){
  background: green;
}
div:nth-child(3n+1){
  background: blue;
}

产生如下的颜色分布:

但我们仍然可以说它的周期是 6,哪怕这里很特殊,其最小周期是 3。

原理

如何让颜色分布不太有规律呢?

不太有规律,就是随机的概念。

也就是说,你看着图像,却一时半会找不到有啥规律。

如果只限定这三种颜色(这个前提很重要),一个可行办法是让最小公倍数大一些,比如说 35。

因为我们目前的 div 总共才 24 个。而整体重复周期为 35 的话,那么这 24 个颜色其效果必然就很像随机了。当然也只是“像”而已,所以是伪随机。

35 的因子是 5、7。其中 5 和 7 都是素数。

素数是很好的选择,因为是素数的整数倍,比如 5n 和 7n 在 35 之内基本没有冲突的。

同时 5n+a 与 7n+b 发生冲突的次数也会尽可能的少。进而如果 a 与 b 也都是素数的话,冲突会更少。比如 5n+3 与 7n+5 只有在 33 处冲突。

比如这种颜色分布:

其代码是:

div:nth-child(n){
  background: red;
}
div:nth-child(5n+1){
  background: green;
}
div:nth-child(7n+4)
{
  background: blue;
}

当然,上述效果中,默认颜色红色太多。主要原因是每种颜色的周期内,我们只应用了一次。这里可以相应增加频次:

div:nth-child(n){
  background: red;
}
div:nth-child(5n+1),
div:nth-child(5n+4){
  background: green;
}
div:nth-child(7n+4),
div:nth-child(7n+6)
{
  background: blue;
}

产生的效果如下:

以上效果是限定在 3 种颜色之内的随机方案。

如果允许增加其他的颜色的话,这里我们可以增加其他素数因子即可。

应用

这种伪随机还有其他应用吗?

《CSS揭秘》中有两个例子。

1.伪随机背景

css 中可以使用线性渐变实现条纹,比如:

background: repeating-linear-gradient(90deg, 
  red, red 15px, 
  green 0, green 30px, 
  blue 0, blue 45px);

效果是:

也可以使用多重背景来实现:

background:
  linear-gradient(90deg, red 15px, transparent 0),
  linear-gradient(90deg, green 30px, transparent 0),
  linear-gradient(90deg, blue 45px, transparent 0);
background-size: 45px 100%;

接下来我们让颜色出现随机些,设置背景大小为素数版的:

background-size: 41px 100%, 61px 100%, 83px 100%;

效果如下,其中默认背景颜色是白色。

同时也可进一步设置颜色宽度:

background:
  linear-gradient(90deg, red 11px, transparent 0),
  linear-gradient(90deg, green 23px, transparent 0),
  linear-gradient(90deg, blue 41px, transparent 0);
background-size: 41px 100%, 61px 100%, 83px 100%;

具体请看其在线例子

2 动画组合

我们知道动画属性 animation 与 background 属性一样,也支持多套值。

而在同一个元素上应用多套动画,我们也可让其整体周期更大些,进而每一帧的状态都是随机的组合。

比如:

animation: 1s spin, .7s radius, 1.1s color, 1.3s width;

具体请看其在线例子

蝉原则

通过素数增加随机性的这种方法,书中管它叫蝉原则。

百度了一下,张鑫旭老师也介绍了:《“蝉原则”与CSS3随机多背景随机圆角等效果》

大体说来,之所以叫“蝉”原则,是因为人家蝉的生命周期(主要还是爆发周期)是那种 13 或 17年的。周期又大,又是素数。这样就能与其天敌的周期尽可能相避开(周期是一年的话,就没法避开了?)。

最后列一下其他有用的资料。