用 CSS random() 来掷骰子

本篇依然来自于我们的 《前端周刊》 项目!

由团队成员 嘿嘿 翻译,他的文章风格稳健而清晰,注重结构与逻辑的严谨性,善于用简洁的语言将复杂技术拆解成易于理解的知识点~

欢迎大家 进群 与他探讨 CSS random() 最新趋势,并持续追踪全球前端领域的最新动态!

原文:Rolling the Dice with CSS random()

编程语言里的随机函数真是太棒了。你可以用它们来制造变化,让东西看起来自然又有活力。但一直以来,CSS 里没法生成随机数。现在不一样了,random() 函数马上就要来了。你可以用它来创建随机的动画延时,把内容随机放在屏幕上任何位置,生成随机颜色,或者任何你想要的效果------完全不需要使用任何 JavaScript。

基本用法

这个新函数有三个参数:random(min, max, step)。你设置一个最小值和最大值,定义随机数的范围。可以用任何类型的数字(整数、百分比、长度、角度等等),只要三个参数的类型一致就行。第三个步长参数可选,想要整数的时候特别有用。

比如,random(0, 100, 2) 会选择 0 到 100 之间的偶数,而 random(0turn, 1turn) 会是一个小数角度------基本上就是 0 到 360 度之间的任意小数。

下面我们通过几个例子来看看怎么用 random()。先从用 HTML 和 CSS 做一个星空开始。

用 CSS 和 HTML 做星空

用随机放置的圆圈、发光效果和四角星做的纯 CSS 星空

xml 复制代码
<html>
<body>
    <div class=star></div>
    <div class=star></div>
    ...
    <div class=star></div>
  </body>
</html>

先给每颗星创建一个 HTML 元素。然后画出天空,用白色的小圆圈来做星星。设置成固定定位,这样就能轻松地随机放置它们了。

css 复制代码
body {
  background-color: black;
}

.star {
  background-color: white;
  border-radius: 50%;
  aspect-ratio: 1/1;
  width: 3px;
  position: fixed;
}

现在让星星分散开,把 top 和 left 属性设置成随机值。这里 top(Y 轴)设为 0-100%,left(X 轴)也是独立的随机值。默认情况下,每个 random() 函数都会用不同的随机种子生成不同的随机值。

css 复制代码
.star {
  background-color: white;
  border-radius: 50%;
  aspect-ratio: 1/1; 
  width: 3px;
  position: fixed;
  top: random(0%, 100%);
  left: random(0%, 100%);
}

随机放置的圆点

为了让效果更生动,我们也把"星星"的大小做成随机的。

css 复制代码
.star {
   background-color: white;
   border-radius: 50%;
   aspect-ratio: 1/1; 
   width: random(2px, 10px, 1px);
   position: fixed;
   top: random(0%, 100%);
   left: random(0%, 100%);
 }

注意 top 和 left 的随机值用的是百分比,但 width 用的是像素。记住,不管用什么单位,每个参数都得保持一致。上面例子里的第三个参数确保星星大小按 1px 递增,这样能得到整数,让大小分布更均匀,变化更丰富。

大小随机的圆形星星

我们还能加点特效,比如用多层阴影和混合效果给星星加上微妙的光晕。

css 复制代码
.star {
    --star-size: random(--random-star-size, 1px, 7px, 1px);
    background-color: white;
    border-radius: 50%;
    aspect-ratio: 1/1;
    width: var(--star-size);
    position: fixed;
    top: random(0%, 100%);
    left: random(0%, 100%);
    filter: drop-shadow(0px 0px calc(var(--star-size) * 0.5) oklch(0.7 0.2 random(0, 100))) 
            drop-shadow(0px 0px calc(var(--star-size) * 2) white);
    mix-blend-mode: hard-light;
}

共享随机值和自定义属性

--star-size 自定义属性让我们能重复使用生成的随机像素值,但是自定义属性配合 random() 有些重要的细节。首先,你会看到 random() 函数的第一个参数看起来像另一个自定义属性。这里用的 --random-star-size 名字叫做标识符,用来确保在其他用了相同标识符的 random() 调用中使用同样的随机值。

你可能会问,为什么需要这样?要知道,把自定义属性设为 CSS 函数跟其他编程语言里变量存储结果是不一样的。自定义属性更像是简单的文本替换。也就是说,无论你在哪里用 var() 调用这个属性,实际上更像是文本替换,把 var() 替换成你声明的属性内容。在这个例子里,意思就是又来一个 random() 调用,而不是函数的结果。

回到例子,理想的光晕模糊效果需要基于星星最终的随机大小。用 calc() 就能做到这点,用星星大小的倍数作为多层阴影的模糊大小。要做到这点就得获得同样的随机值,所以用命名标识符是对的。

第一个阴影还用 random() 通过 oklch() 选择色调,添加鲜艳的颜色,配合 hard-light 混合模式和柔和的白色光晕组合使用。这种组合给星星添加了微妙而生动的着色。

发光的随机圆形星星

用命名标识符可以在单个元素的不同属性之间共享随机值。这只是共享随机值的方法之一。random() 函数有很多种用法,看你的需求。你还可以用 element-shared 值让所有匹配的元素共享某个属性的随机值,或者两种方法混用,到处共享值。跟命名标识符不同的是,命名标识符在使用标识符的时候共享值,而 element-shared 会让所有应用这个属性的元素共享随机值。

在星空例子里看到这种效果的一个办法是加几个简单的四角星。

css 复制代码
.star.fourpointed {
    clip-path: shape(from 50% 0%,line to 50.27% 3.25%, ...);
    --star-size: random(--random-four-point-size, 20px, 60px, 1px);
    rotate: random(element-shared, -45deg, 45deg);
}

随机放置和旋转的四角星

用 CSS shape() 来定义四角星形状,裁剪掉圆形的白色背景。星星大小还是可以随机,但得放大一个数量级才好看。这些星星更逼真的样式是模仿星星图片里看到的衍射光芒。因为物理原因,它们都是同一个角度倾斜的。虽然可以设个固定角度,但随机角度更有趣更生动。要有效地做到这点,就得让所有四角星用同一个随机角度。

这就是 element-shared 派上用场的地方。element-shared 值为所有元素的这个属性生成一个共享的随机值。这样所有四角星就会以同样的随机角度旋转了。

这里是完整的星空例子,你可以试试:codepen.io/jdatapple/p...

随机放置的矩形

random() 还有很多其他用法。基于星空例子的思路,你可以试试把 random()grid 这样的布局工具结合使用。

随机放置、随机着色的矩形

在这个变化的例子里,网页区域被分成 100 行 100 列。然后随机颜色的矩形被随机放在网格里:

css 复制代码
.grid {
  display: grid;
  --rows: 100;
  --columns: 100;
  grid-template-rows: repeat(var(--rows), 1fr);
  grid-template-columns: repeat(var(--columns), 1fr);
  width: 100vw;
  height: 100vh;
}

.rectangle {
  background-color: lch(100% 90% random(0deg, 360deg));
  grid-area: random(1, var(--rows), 1) / random(1, var(--columns), 1);
}

你可以在任何支持 random() 的浏览器里看最终效果:codepen.io/ntim/pen/dP...

照片堆叠

另一个用 random() 的例子是创建看起来像是随意撒在一起的照片堆。你可以花时间精心摆放每张照片,或者让电脑在每次页面加载时自动生成。

沙漠风景照片堆,图片随机旋转和偏移放置

css 复制代码
.stack img {
    width: 100%;
    grid-column: 1;
    grid-row: 1;
    border: 10px solid hsl(0, 100%, 100%);
    box-shadow: 10px 10px 40px hsl(0, 0%, 0%, 20%);

    --random-rotate: rotate(random(-1 * var(--rotate-offset), var(--rotate-offset)));

    transition: .3s ease-out;
    transform: var(--random-rotate);
    transform-origin: random(0%, 100%) random(0%, 100%);
}

更棒的是,在交互里加入随机性也很简单。在图片的悬停状态加入随机平移,增加了趣味性:

css 复制代码
.stack:hover img {
    transform: var(--random-rotate) translateX(random(-1 * var(--translate-offset), var(--translate-offset))) translateY(random(-1 * var(--translate-offset), var(--translate-offset)));
}

幸运转盘

随机旋转示例,转盘分成 20 份,隔一个格子放一个表情符号,有个绿色的旋转按钮

random() 函数甚至能用来做需要不可预测结果的交互元素。幸运转盘演示完美地展示了这点。

css 复制代码
@keyframes spin {
    from {
        rotate: 0deg;
    }
    to {
        rotate: 10turn; /* 不支持 random() 的浏览器用这个 */
        rotate: random(2turn, 10turn, by 20deg);
    }
}

点击"SPIN"按钮时,@keyframe 动画用 random() 生成一个旋转值,决定转盘停在哪里。这个例子展示了现代 CSS 越来越强大的功能,在样式表里就能定义所有的交互、随机性和动画。

你可以在这里看实际效果:codepen.io/ntim/pen/Wb...

随机性使用参考

random() 有很多不同的用法,看你需要什么,以及想要怎样在元素之间共享随机性。

完全随机

两个属性得到不同的值,每个元素也都不同,所以你得到很多随机矩形。

css 复制代码
.random-rect {
  width: random(100px, 200px);
  height: random(100px, 200px);
}

在元素内按名称共享

使用标识符,两个属性可以得到相同值,但每个元素还是不同,所以你得到很多随机正方形。

css 复制代码
.random-square {
    width: random(--foo, 100px, 200px);
    height: random(--foo, 100px, 200px);
}

在元素间按属性共享

element-shared,两个属性得到不同值,但所有元素共享,所以你得到很多相同的随机矩形。

css 复制代码
.shared-random-rect {
    width: random(element-shared, 100px, 200px);
    height: random(element-shared, 100px, 200px);
}

按名称全局共享

同时用命名标识符和 element-shared,两个属性得到相同值,所有元素都共享,所以你得到很多相同的随机正方形。

css 复制代码
.shared-random-squares {
    width: random(--foo element-shared, 100px, 200px);
    height: random(--foo element-shared, 100px, 200px);
}

试试看,告诉我们怎么样

你现在就能在 Safari Technology Preview 里试用 random() 函数!不过要注意,CSS 工作组还在讨论规范,关于这个方法是否最适合开发者的需求,还有几个问题没解决。

虽然上面的例子展示了很棒的可能性,我们正在积极征求 Web 开发社区的反馈来帮助确定最终方向,你能帮上忙。如果你在 Safari Technology Preview 里试了 random(),我们很想听听你的体验。什么好用?什么别扭?共享值的表达方式你觉得合理吗?有什么用不上的场景吗?对 element-shared 这个名字有更好的建议吗?你的反馈会直接影响这个功能的发展方向。这是你帮助塑造 CSS 的机会------试试看,告诉我们你的想法。

相关推荐
调皮LE几秒前
可放大缩小弹窗组件,基于element-ui的vue2版本
前端
陈随易3 分钟前
10年老前端,分享20+严选技术栈
前端·后端·程序员
我的小月月9 分钟前
基于Canvas实现的网页取色器功能解析
前端
芝士加22 分钟前
还在用html2canvas?介绍一个比它快100倍的截图神器!
前端·javascript·开源
阿虎儿24 分钟前
React 引用(Ref)完全指南
前端·javascript·react.js
Ratten40 分钟前
解决 error when starting dev server TypeError crypto$2.getRandomValues
前端
coding随想43 分钟前
深入浅出DOM3合成事件(Composition Events):如何处理输入法编辑器(IME)的复杂输入流程
前端
六月的雨在掘金43 分钟前
狼人杀法官版,EdgeOne 带你轻松上手狼人杀
前端·后端
Ratten1 小时前
【npm 解决】---- TypeError: crypto.hash is not a function
前端
绝无仅有1 小时前
使用 Docker、Jenkins、Harbor 和 GitLab 构建 CI/CD 流水线
后端·面试·github