使用 HTML 和 CSS 创建降雪效果

2025-06-08

使用 HTML 和 CSS 创建降雪效果

最近德克萨斯州一直在下雪,天气也很寒冷(现在仍然如此)......这就是我用 HTML 和 CSS在不到 10 分钟的时间内制作出这个雪花飘落的快速动画的灵感(视频位于页面底部)。

注意:我们分别使用了PugSass/SCSS来简化 HTML 和 CSS 的重复部分,但它们并非必需。您可以推断代码仅包含 HTML 和 CSS(为简单起见,我们将在文章中同时展示这两种代码)。

这就是我们的动画最终呈现的样子(通过 CodePen 演示):

设置背景

我们先来设置背景。此步骤是可选的,可以通过多种方式完成。出于演示目的,我们仅使用 CSS 制作一个深色背景:

html, body {
  padding: 0;
  margin: 0;
  width: 100vw;
  height: 100vh;
  position: relative;
  overflow: hidden;
  background: linear-gradient(#123, #111);
}
Enter fullscreen mode Exit fullscreen mode

添加雪花

然后,我们将为<div>屏幕上想要显示的每个雪花创建一个。我们可以这样做:

<div class="snowflake"></div>
...
...
...
<div class="snowflake"></div>
<div class="snowflake"></div> <!-- 50 times! -->
Enter fullscreen mode Exit fullscreen mode

但为了简单起见,我们使用了 PugJS,它允许我们使用循环来执行这些重复性任务:

- for (i = 0; i < 50; i++)
  div(class="snowflake")
Enter fullscreen mode Exit fullscreen mode

雪花造型

现在<div>页面上已经有了所有的雪花,我们需要给它们添加样式。它们将是小巧、圆润、白色的:

.snowflake {
  --size: 1vw;
  width: var(--size);
  height: var(--size);
  background: white;
  border-radius: 50%;
  position: absolute;
  top: -5vh;
}
Enter fullscreen mode Exit fullscreen mode

我们对宽度和高度使用了自定义属性(--size),因为当我们以后想要不同大小的雪花时会很方便。

另外,我们将雪花放置在视图框架之外(从顶部)。我们将使它们落到视图框架之外(从底部)。

添加动画

为了实现这个秋天的动画效果,我们需要使用 CSS 动画@keyframes。我们将从一些基本的东西开始,然后让它逐渐发展。

首先,我们将使用translate3d来使雪花垂直移动。因为它是一个 3D 变换,所以它会触发硬件加速,看起来比我们用其他属性来制作动画效果要好看得多,例如top

@keyframes snowfall {
  0% {
    transform: translate3d(0, 0, 0);
  }
  100% {
    transform: translate3d(0, 110vh, 0);
  }
}
Enter fullscreen mode Exit fullscreen mode

我们可以通过添加以下属性将此动画应用于雪花类:

animation: snowfall 5s linear infinite;
Enter fullscreen mode Exit fullscreen mode

但这只会让雪花从上到下垂直移动,看起来不真实。而且,由于绝对定位,所有雪花都重叠了,看起来不太好看。我们需要解决这个问题。

我们可以创建 50 条不同的规则,每个雪花一条,为每个雪花分配不同的左侧位置、角度、速度……虽然这在纯 CSS 中是可能的,但却非常繁琐:

.snowflake:nth-child(1) {
  --size: 0.6vw;
  left: 55vw;
  animation: snowfall 8s linear infinite;
}

...

.snowflake:nth-child(49) {
  --size: 1vw;
  left: 78vw;
  animation: snowfall 7s linear infinite;
}

.snowflake:nth-child(50) {
  --size: 1.5vw;
  left: 20vw;
  animation: snowfall 10s linear infinite;
}
Enter fullscreen mode Exit fullscreen mode

使用 SCSS 及其函数编写代码并使用生成的 CSS 代码会更加容易。因此,我们不必编写数百行代码,而是可以使用循环来大大简化开发过程:

@for $i from 1 through 50 {
  .snowflake:nth-child(#{$i}) {
    --size: #{random(5) * 0.2}vw; /* randomize size! */
    left: #{random(100)}vw;
    animation: snowfall #{5 + random(10)}s linear infinite;
  }
}
Enter fullscreen mode Exit fullscreen mode

轰!这 7 行代码稍后会被编译成 250 行!而且我们不必担心随机数的生成,因为 SCSS 提供了这方面的random()功能

最后的润色

雪花的大小和移动速度各不相同,但它们仍然只是垂直移动,这不太现实。我们可以将 CSS 变量与 SCSS 函数结合起来,添加一些随机的横向移动效果:

/* uses CSS variables to determine initial and final position */
@keyframes snowfall {
  0% {
    transform: translate3d(var(--left-ini), 0, 0);
  }
  100% {
    transform: translate3d(var(--left-end), 110vh, 0);
  }
}

@for $i from 1 through 50 {
  .snowflake:nth-child(#{$i}) {
    --size: #{random(5) * 0.2}vw;
    --left-ini: #{random(20) - 10}vw; /* random initial translation */
    --left-end: #{random(20) - 10}vw; /* random final translation */
    left: #{random(100)}vw;
    animation: snowfall #{5 + random(10)}s linear infinite;
    animation-delay: -#{random(10)}s;
  }
}
Enter fullscreen mode Exit fullscreen mode

最后,我们添加了一个负片animation-delay,这样所有雪花的动画开始位置就不会相同。否则,它们会同时开始飘落,看起来会有点奇怪。

更新:将变量移动到 HTML

上面的代码没问题,但它生成了很多重复的 CSS 规则,而且每次只会改变一个小的值。可以将其简化为类中的一个(或两个)属性.snowflake,并为每个元素使用 CSS 变量。

这个想法是将 CSS 变量的声明从 CSS 移到 HTML:

<!-- 1 -->
<div class="snowflake" style="--left: 69vw; --left-ini: -4vw; --left-end: 0vw; --speed: 8s; --size: 0.4vw; --delay: -10s;"></div>
...
...
...
<!-- 50 -->
<div class="snowflake" style="--left: 83vw; --left-ini: 5vw; --left-end: 1vw; --speed: 10s; --size: 0.2vw; --delay: -6s;"></div>
Enter fullscreen mode Exit fullscreen mode

在 PugJS 中,我们需要定义一个random函数,然后使用它来设置 CSS 变量的值:

- function random(num) { return Math.floor(Math.random() * num) }
- for (i = 0; i < 50; i++)
  div(class="snowflake", style=`--left: ${random(100)}vw; --left-ini: ${random(20) - 10}vw; --left-end: ${random(20) - 10}vw; --speed: ${5 + random(15)}s; --size: ${random(5) * 0.2}vw; --delay: -${random(15)}s;`)
Enter fullscreen mode Exit fullscreen mode

现在我们在 HTML 中有了所有的值,我们可以删除所有的 CSS 选择器,而只在.snowflake定义中直接保留动画属性:

.snowflake {
  width: var(--size);
  height: var(--size);
  background: white;
  border-radius: 50%;
  position: absolute;
  top: -5vh;
  left: var(--left);
  animation: snowfall var(--speed) linear infinite;
  animation-delay: var(--delay);
}
Enter fullscreen mode Exit fullscreen mode

这个解决方案显著简化了 CSS 代码(从 500 行减少到 34 行!),同时稍微增加了 HTML 的复杂度。您可以在这里查看它的运行情况。(感谢@afif的启发)。

结论

这是一个简单的动画,虽然很吸引人……但如果添加太多雪花,也会占用大量 CPU。请谨慎使用。

您可以在 Youtube 上观看动画开发的视频:

同时,您还可以订阅:)
鏂囩珷鏉ユ簮锛�https://dev.to/alvaromontoro/creating-a-snowfall-effect-with-html-and-css-1pp1
PREV
CSS 恐龙游戏 GenAI LIVE!| 2025 年 6 月 4 日
NEXT
构建交互式表单