在CSS中尝试Random()函数

Hacker News Top 工具

摘要

一篇探索新的CSS random()函数的博客文章,该函数允许将属性设置为随机值以实现创意设计,包含演示和浏览器支持详情。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/06/28 10:56

# 在 CSS 中使用 `random()` 函数进行实验 来源:https://polypane.app/blog/experimenting-with-random-in-css/ CSS 正在引入一个 `random()` 函数,它允许你为属性设置随机值,从而创造出有趣且富有创意的设计。你可以在 Polypane 29+ 中测试该功能,也可以在启用实验性功能后的 Chromium 148+ 中使用。Safari 26.2+ 也支持 `random()`,但并未完全支持本文中展示的所有演示。Firefox 目前暂不支持 `random()`。 > 使用 Polypane 29+、Safari 26.2 或启用了实验性功能的 Chromium 148+ 来尝试本文中的演示。如果你想查看实际运行效果,可以[获取 Polypane](https://dashboard.polypane.app/register/) 并免费试用。 ## 我制作了一些演示 我花了几个星期构思如何使用 `random()` 来创造有趣的设计、图案和背景。 ### 关于代码示例的说明 我们在下面的代码示例中直接使用了 `random()`,并没有为尚不支持该函数的浏览器提供降级方案。如果你想看到实际效果,可以[获取 Polypane](https://dashboard.polypane.app/register/) 并免费试用。 代码示例中的 CSS 是完全可编辑的,但只显示每个效果的相关 CSS(例如,下面的 bokeh 效果展示了定位,但没有展示 `border-radius`)。你可以编辑示例中的 CSS 来观察其工作原理。 在代码示例中,我们只展示了最相关的 CSS,但如果你复制代码,将会得到完整的 HTML 和 CSS。点击 "randomize" 按钮可以为每个属性生成新的随机值,并重新加载示例。 ### 关于浏览器支持的说明 浏览器的实现仍在进行中,目前该功能放在实验性 Web 特性标志后面是有原因的。部分演示在 Safari 中无法正常工作。我们相当肯定下面的一些示例无法经受未来实现的变更,并且为了同时支持 Polypane 29(基于 Chromium 148)和更高版本的 Chromium(因为实现从 148、149 到 150 版本有所演变),我们不得不使用一些技巧。我们会持续更新本文,但如果你在将来阅读时发现某些演示不再工作,请告诉我们,我们会及时更新文章! ## Bokeh 效果 当我看到 `random()` 在 [Polypane 29 中可用](https://polypane.app/experimental-web-platform-features/?search=random)时,我立刻就想尝试一下。我最喜欢的“随机设计”类型之一是 *bokeh*,这是一种摄影效果,能形成失焦的光斑。我觉得用 `random()` 来创建 bokeh 效果会很有趣。于是我查阅了 MDN 上关于 [random() 的页面](https://developer.mozilla.org/zh-CN/docs/Web/CSS/Reference/Values/random) 并开始动手。 如果你观察 bokeh 效果,它本质上是一堆圆形,这些圆形在以下几个方面有所不同: - 圆形的**位置** - 圆形的**大小** - 圆形的**颜色** - 圆形的**失焦程度** - 它们**变化的速度**(如果是动画 bokeh) ### 位置 圆形的定位最简单:将它们设置为 `position: absolute`,然后在 `left` 和 `top` 属性中使用 `random()`。这样就能将圆形放置在随机位置: #### Bokeh:随机位置 `random()` 函数最简单的形式是接受一个最小值(0%)和一个最大值(100%),并返回两者之间的随机值。 > **注意:** 这里的最小值是 0,但必须包含 %,以确保两个值属于同一类型。如果只写 `random(0, 100%)`,则无效,因为最小值是 ``,最大值是 ``(类型不匹配)。 ### 大小 bokeh 效果中的每个圆形大小不同,但它们仍然是圆形。因此,如果我们想用 `random()` 来设置大小,就需要确保宽度和高度是相同的值。我的想法是将随机值“存储”在一个自定义属性中(例如 `--size: random(50px, 20vmin)`),然后将该自定义属性同时用于宽度和高度。这样,宽度和高度就会始终相同。至少我是这么认为的。 #### Bokeh:随机椭圆 哎呀,宽度和高度不一样了!当你将自定义属性设置为随机值时,每次**使用**该自定义属性时都会生成一个新的随机值,而不是在声明时固定。为了解决这个问题,我们需要在 random 函数中添加一个自定义关键字 `element-scoped`。这会告诉浏览器为每个元素生成一个随机值。这样,每个元素会得到不同的随机值,但每个元素的宽度和高度是相同的: #### Bokeh:使用 element-scoped 修复大小 > 注意:`element-scoped` 并非此特性的最终名称,但目前 Polypane 和 Safari 支持的是这个名称。它将被重命名为 `per-element`。这两个名称均尚未收录到 MDN 文档中,不过[已经有人提交了 PR](https://github.com/mdn/content/pull/44544) 来添加该内容。 ### 重新审视位置 我最初想从位置开始讲,因为它最简单,但实际上位置存在一个问题:如果某个圆形从左侧 99% 开始,并且大小为 100px,那么它会溢出容器并导致滚动条。为了解决这个问题,我们可以使用 `calc()` 从位置中减去圆形的大小: #### Bokeh:使用 element-scoped 修复大小 我们并不确切知道圆形的大小,但由于 `--size` 在每个属性中对于同一个元素是相同的,因此我们可以用它来确保圆形始终完全位于容器内。 ### 圆形的颜色 对于圆形的颜色,我希望所有圆形的亮度和饱和度大致相同,但每个圆形具有不同的色相。因此,我在 `hsl()` 函数中对色相值使用了 `random()`。此外,当你观察 bokeh 图像时,有些圆形更明显,有些则不那么明显。所以我添加了一个随机的不透明度: #### Bokeh:颜色与不透明度 HSL 中的 `hue` 只是一个数字,因此不需要单位。不透明度也是如此。 > 注意:为了更清晰地展示效果,我们在本示例及接下来的几个示例中增加了圆形的数量。 ### 失焦程度 接下来,bokeh 图像中的一些圆形非常清晰,而另一些则比较模糊。在 CSS 中,我们可以使用 `filter: blur()` 函数来实现模糊效果。添加模糊后,某些颜色的鲜艳程度会有所损失,所以我添加了一个 `contrast()` 滤镜来使某些圆形更加鲜艳。最后,我添加了 `mix-blend-mode`,使用 "plus-lighter" 模式使圆形之间相互混合。这可以增加重叠区域的亮度,使其看起来更像真实的 bokeh: #### Bokeh:模糊、对比度、混合 模糊效果有助于使圆形看起来更像真实的 bokeh 光斑,而对比度则使其中一些圆形看起来更鲜艳,另一些更暗淡,从而增强了效果。对于对比度,我们特意选择了一个范围,使得大多数随机值会**增加**对比度(100% 到 200% 范围),只有少数圆形的对比度值会降低对比度(50% 到 100% 范围)。 ### 动画 最后,我想为 bokeh 圆形添加一些动画效果。当你通过相机观察 bokeh 并调整焦距时,一些圆形会变大且更模糊,而另一些则会变小且更清晰。最容易实现的方法就是使用简单的脉冲动画。我们只需要定义 50% 的关键帧。0% 和 100% 关键帧将是元素的默认状态(scale 为 1)。 ```css @keyframes pulse { 50% { scale: 1.2; } } ``` 我们可以对所有圆形重复使用同一个动画,因为我们可以为每个圆形设置随机的动画持续时间和动画延迟。这样,每个圆形会以不同的速率脉冲,并在不同的时间开始,从而使动画看起来更自然: ```css .bokeh { animation: pulse random(2s, 5s) ease-in-out infinite; animation-delay: random(-5s, 0s); } ``` 我们将动画设置为无限循环,使用 ease-in-out 缓动函数来平滑每个脉冲的开始和结束。通过设置随机的**负**延迟,一些圆形会从动画的中间开始,这样在页面刷新时看起来更自然。如果我们只使用无延迟或正延迟,所有圆形都会从放大开始动画。 ### 综合所有 因此,当我们把所有属性组合在一起时,就会得到: #### Bokeh:最终完整演示 > **注意:** 对于像上面这样包含动画的演示,我们会显示一个 "show demo" 按钮来激活预览,原因有二:1)动画可能会分散注意力或令人厌烦;2)动画可能对性能有影响。 ## 飘落的樱花花瓣 我家后院有一棵樱花树,春天风吹过时,花瓣会从树上飘落下来,缓缓落到地面。非常舒缓。我觉得用 `random()` 来重现这个效果会很有趣,我们先展示最终动画,让你了解我们要实现的目标: #### 飘落的花瓣 > **注意:** 在 Safari 中,有时你无法在演示中看到任何花瓣。如果发生这种情况,请多次点击 randomize。我不知道为什么会发生这种情况,但似乎是 Safari 的一个 bug。 让我们看看要实现这个效果需要随机化哪些部分。 - 所有花瓣都需要从屏幕外的不同位置开始 - 它们应该大小略有不同,并且外观略有差异 - 它们都需要大致朝着相同的方向移动,仿佛被风吹动,但每片花瓣的飘落方式应该略有不同 - 它们应该以不同的速度飘落 - 它们在飘落时应随机旋转 ### 起始位置 每片花瓣的起始位置应在当前视口上方,并随机分布在视口宽度方向,这样每片花瓣就会从不同的位置飘落。对于 `top` 值,我们可以使用固定值,使它们都从同一高度开始;对于水平起始值,我们将使用自定义属性,因为我们稍后在飘落动画中会再次用到它。我们将使用 `element-scoped`,这样每片花瓣都有不同的起始位置。我们不设置 `left`,而是设置 `translate`,因为我们希望动画让花瓣沿屏幕飘落,而动画 `translate` 比动画 `left` 性能更好: ```css .petal { position: absolute; top: -100px; --initial-position: random(element-scoped, -40vw, 100vw); translate: var(--initial-position) 0; } ``` 我们本可以展示一个演示,但所有花瓣都从屏幕外开始且没有动画,所以什么也看不到。起始位置已搞定,接下来看大小和形状。 ### 大小和花瓣样式 对于大小,这次我们使用 `aspect-ratio` 而不是显式的 `width`,这样可以保持简单: ```css .petal { width: random(30px, 50px); aspect-ratio: 1/1; } ``` 对于花瓣本身,我找到了 Pram Samnak 设计的四种不同的花瓣,我很喜欢,并想随机选择其中一种。理论上,你可以使用 `random-item()` 来随机挑选这四种花瓣之一,但该函数尚未在任何浏览器中实现。如果它有效,代码看起来会像这样: ```css .petal { background-image: random-item( url(petals/1.png), url(petals/2.png), url(petals/3.png), url(petals/4.png) ); } ``` 我思考了一番如何绕过这个问题,最后意识到既然每片花瓣从随机位置开始,我就可以直接使用 `nth-child`。`nth-child()` 选择器的重复模式不会很明显,因为每片花瓣的起始位置是随机的。所有这些仍然发生在屏幕外,所以没有演示。让我们快速添加飘落动画,看看效果! ### 飘落动画 花瓣飘落时也会被风吹动,所以它们不会直线下落。为了实现这一点,我们可以对 `translate` 进行动画,使花瓣向下并向右侧移动。由于每片花瓣受到的风力不同,我们希望它们以不同的速度和不同的角度飘落。对于速度,我们可以改变动画的持续时间。对于角度,我们可以设置 `translate` 的终点值,该值使用我们已经有的 `--initial-position`,再加上一个随机量。 #### 飘落的花瓣:飘落动画 与 bokeh 示例类似,每片花瓣有不同的动画持续时间,并且我们设置一个负的延迟,这样一些花瓣从动画中间开始,使页面加载时看起来更自然。我们只需将 `to` 关键帧设置为屏幕底部的终点位置。当花瓣离开屏幕时,它会跳回顶部并再次开始飘落,从而实现连续效果。 ### 旋转动画 为了实现花瓣在 3D 空间中旋转的效果,我们在它们飘落时随机缩放它们,仿佛它们正在靠近或远离摄像机,同时沿 X、Y 和 Z 轴旋转它们。我们使用两个独立的动画来实现这一点,这样两个动画可以以不同的随机持续时间和起始时间发生,为每片花瓣创造出独特的动画效果。对于旋转,我们使用带有 `perspective()` 的变换,以获得更好的 3D 视觉效果。我们还希望每片花瓣以不同的速度旋转,因此在动画持续时间中也使用了 `random()`。最后,我们将 transform-origin 设置为元素的 `top center`,这样花瓣会围绕该点旋转,而不是围绕花瓣的中心。 #### 飘落的花瓣:旋转 最后,我们添加了一张精美的背景图片作为背景。 ## 一叠可以扔开的宝丽来照片 在第三个示例中,我想创建一叠“不整齐”的宝丽来照片,它们略微旋转并相互偏移,形成自然堆叠的外观。此外,我希望点击它们时能随机方向扔开。让我们看看如何为随机性添加交互! ### 构建堆叠 创建元素堆叠的最简单方法是使用 CSS Grid,并将所有元素放置在同一个网格单元格中: ```css .container { position: absolute; margin: 0; inset: 0px; display: grid; grid-template-columns: 1fr; place-items: center; .polaroid { grid-area: 1/1/2/2; } } ``` 然后我们可以为每张宝丽来照片设置样式。这次它们都有相同的尺寸,但我们将在 `transform` 中使用随机值来增加随机性。每张宝丽来的 HTML 结构如下: ```html <div class="polaroid"> <img src="..."> <p>...</p> </div> ``` 由于网格布局,它们已经全部堆叠在相同的位置。我们可以在 `transform` 属性中使用 `random()` 来随机旋转和偏移每张卡片: #### 宝丽来:随机堆叠 这里的 transform 负责整个效果:在 -15 到 15 度之间随机旋转,然后在两个方向上随机平移最多 10 像素。这创造了一叠漂亮的“凌乱”宝丽来照片。 ### 添加交互 对于交互,我们需要在点击每张卡片时能够设置其状态,并且理想情况下还需要一种方法将卡片重置回原始位置。每张卡片都有一个复选框,我们将其叠加在卡片上方: ```html <div class="polaroid"> <input type="checkbox" id="card1"> <img src="..."> <p>...</p> </div> ``` CSS 确保复选框不可见且覆盖整张卡片: ```css .polaroid { input { position: absolute; inset: 0px; opacity: 0; cursor: pointer; } } ``` 这样我们就可以使用每张卡片的 `:checked` 状态,但要取消选中,需要再次单独点击每张卡片。如果我们希望一次重置所有卡片,就需要使用平台。通过将所有复选框包裹在一个 `` 中,我们可以利用表单的原生 `reset` 行为,在点击重置按钮时一次性取消所有复选框。将重置按钮*放在*相同网格堆叠中的卡片*之前*,它会在最后一张宝丽来被移除时出现。

相似文章

什么是随机生成?

Lobsters Hottest

本文探讨了计算机中的伪随机数生成,重点聚焦于线性同余生成器(LCG)及其质量可视化。文章还提及了 Cloudflare 的熔岩灯等熵源,并作为基于属性的测试的前导内容。

CSS:不可避免的坏部分

Lobsters Hottest

一位非Web开发者的个人博客文章讨论了CSS中不可避免的坏部分,包括布局难题、浏览器默认设置和过度使用包装器,同时强调了可处理简单任务的子集。

CSSQuake

Hacker News Top

CSSQuake 是一个基于 CSS 的工具或演示,能够在网页上模拟地震般的抖动效果。

Lobsters Hottest

一篇技术博文,探讨随机性、Linux熵以及构建一个名为morerandom的工具,该工具使用WASM插件来为系统熵池提供熵。

算法主题引擎

Hacker News Top

本文介绍了新的CSS `contrast-color()`函数,该函数允许开发人员自动选择黑色或白色文本,以实现与任何背景颜色的可访问对比度,解决网络上长期存在的低对比度问题,而无需依赖JavaScript。