Back

探索 CSS random() 函数

探索 CSS random() 函数

当需要随机性时,CSS 一直依赖 JavaScript——分散的位置、变化的动画延迟、不可预测的颜色变化。这种依赖可能很快会减少。CSS random() 函数是 CSS Values and Units Module Level 5 规范的一部分,它允许样式表直接生成随机数值,无需脚本。

它是实验性的。浏览器支持有限。但现在值得了解。

核心要点

  • CSS random() 函数在样式表中原生生成随机数值,在许多视觉随机性场景中消除了对 JavaScript 的需求。
  • 语法接受最小值、最大值和可选的步进值——所有参数必须共享相同的单位类型。
  • 缓存系统控制随机值是在匹配元素之间共享、按元素分配还是跨特定属性共享,让你能够精细控制随机性的分布。
  • 浏览器支持目前有限,Safari 26.2 现已提供稳定支持。始终使用 @supports 提供降级方案。

CSS random() 函数实际做什么

核心思想很简单:你定义一个最小值、一个最大值,以及可选的步进增量。CSS 从该范围中选择一个数字并应用它。

.card {
  top: random(5rem, 20rem);        /* 5rem 到 20rem 之间的任意值 */
  rotate: random(0deg, 360deg);    /* 随机旋转 */
  animation-delay: random(0s, 3s); /* 交错的动画时间 */
}

就是这样。不需要 Math.random(),不需要内联样式,不需要 JavaScript 循环生成数百个 :nth-child() 规则。

一个重要的约束:所有参数必须共享相同的单位类型。 你不能混合 rempx,或者 %em。选择一个单位并保持一致。

语法

random(<caching-options>?, <min>, <max>, [by <step>]?)

当前的草案规范更正式地定义了这个函数,但这种简化形式是在实践中理解它的最简单方式。

by 参数控制步进。没有它,你可能会得到像 13.47px 这样的小数值。有了它,你可以将输出限制为可预测的序列:

/* 可能的值:10px, 20px, 30px, 40px, 50px */
padding: random(10px, 50px, by 10px);

注意:使用步进时,最大值并不总是可达的。random(100px, 200px, by 30px) 只能产生 100px130px160px190px——永远不会是 200px

控制随机性的共享方式

这是 CSS random() 函数真正有趣的地方。默认情况下,样式表中的每个 random() 实例都会解析为一个单一的缓存值,由所有使用该样式的元素共享。

要让每个元素获得自己的唯一值,请使用 per-element 关键字或破折号标识符:

/* 每个元素获得自己的随机值 */
.item {
  top: random(per-element, 2rem, 15rem);
}

/* 两个属性在一个元素内共享相同的值 */
.box {
  width: random(--size, 100px, 200px);
  height: random(--size, 100px, 200px); /* 匹配 width */
}

/* 所有匹配的元素全局共享相同的命名值 */
.badge {
  width: random(--element-shared, 50px, 150px);
}

per-element 关键字是一个内置的缓存选项,告诉浏览器为每个匹配选择器的元素解析一个不同的随机值。像 --size 这样的破折号标识符将多个 random() 调用绑定在一起,使它们在给定元素内解析为相同的值——当你想要一个具有随机但一致的宽度和高度的正方形时很有用。像 --element-shared 这样的破折号标识符也可以作为跨匹配元素的命名缓存键。

这个缓存系统是经过深思熟虑且设计良好的——但这也是容易产生混淆的地方。尽早理解它可以节省后续的调试时间。

CSS random() vs. SCSS random()

如果你在 Sass 中使用过 random(),其行为在几个关键方面有所不同:

特性CSS random()SCSS random()
何时运行页面加载时编译时
最小/最大范围都需定义仅最大值(从 1 开始)
步进支持是(by)
重新加载时刷新

CSS random() 在每次页面加载时生成新值。SCSS 在构建时锁定值。它们服务于不同的目的。

浏览器支持

截至 2026 年初,CSS 中的 random() 已在 Safari 26.2 中发布。更广泛的跨浏览器支持尚未得到保证,因此你仍应将其视为实验性功能,并使用 @supports 进行渐进增强,提供合理的降级方案:

.element {
  top: 10rem; /* 降级方案 */
}

@supports (top: random(1rem, 5rem)) {
  .element {
    top: random(5rem, 20rem);
  }
}

CSS 工作组在 2022 年采纳了该函数,规范仍在不断演进。仍存在未解决的问题,最终语法在广泛实现之前可能还会发生变化。

结论

CSS random() 函数不会取代 JavaScript 用于逻辑驱动的随机性或任何需要加密不可预测性的场景。但对于纯粹的视觉变化——分散的布局、有机的动画时间、生成式背景——它是一个简洁、声明式的解决方案,属于样式表的范畴。

在 Safari 26.2 中尝试它,保留降级方案,并关注规范的进展。实验性和广泛可用之间的差距正在缩小。

常见问题

不能可靠地全面使用。截至 2026 年初,Safari 26.2 已发布该功能,但更广泛的跨浏览器支持仍然有限。你现在可以尝试它,但任何生产环境使用都应包含可靠的降级值和 @supports 检查,以避免在不支持的浏览器中出现布局错误。

该函数将无效,浏览器将忽略该声明。传递给 random() 的所有参数,包括最小值、最大值和可选的步进值,必须使用相同的单位类型。你不能将 rem 与 px 或百分比与 em 组合。选择一个单位并在所有参数中一致使用它。

默认情况下,一个 random() 实例会解析为一个缓存值,由所有使用该样式的元素共享。要为每个元素获取唯一值,请使用 per-element 关键字。要在特定属性之间共享值,请使用像 --size 这样的破折号标识符。理解缓存对于获得你期望的视觉变化至关重要。

是的。与 SCSS random() 不同,后者在编译时锁定值并将其嵌入到输出的 CSS 中,原生 CSS random() 函数在每次页面加载时解析一个新值。这使其适合创建在访问之间变化的视觉多样性,而无需任何 JavaScript 参与。

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay