您现在的位置是:亿华云 > 应用开发

妙啊!超酷炫的气泡效果

亿华云2025-10-02 09:05:48【应用开发】9人已围观

简介最近,在 CodePen 上看到这样一个非常有意思的效果:这个效果的核心难点在于气泡的一种特殊融合效果。其源代码在:CodePen Demo -- Goey footer[1],作者主要使用的是SVG

最近,妙超在 CodePen 上看到这样一个非常有意思的酷炫效果:

这个效果的核心难点在于气泡的一种特殊融合效果。

其源代码在:CodePen Demo -- Goey footer[1],泡效作者主要使用的妙超是 SVG 滤镜完成的该效果,感兴趣的酷炫可以戳源码看看。

其中,泡效要想灵活运用 SVG 中的妙超 feGaussianBlur 滤镜还是需要有非常强大的 SVG 知识储备的。那么,酷炫仅仅使用 CSS 能否实现该效果呢?泡效

嘿嘿,强大的妙超 CSS 当然是可以的。本文,酷炫就将带领大家一步步使用纯 CSS,泡效完成上述效果。妙超

借助 SASS 完成大致效果

首先,酷炫如果上述效果没有气泡的泡效融合效果,可能就仅仅是这样:

要制作这样一个效果还是比较简单的,香港云服务器只是代码会比较多,我们借助 SASS 预处理器即可。

假设我们有如下 HTML 结构:

// ... 200 个 g-bubble

</div>

核心要做的,仅仅是让 200 个 .g-bubble 从底部无规律的进行向上升起的动画。

这里,就需要运用我们在 深入浅出 CSS 动画[2] 这篇文章中所介绍的一种技巧 -- 利用 animation-duration 和 animation-delay 构建随机效果。

利用 animation-duration 和 animation-delay 构建随机效果

同一个动画,我们利用一定范围内随机的 animation-duration 和一定范围内随机的 animation-delay,可以有效的构建更为随机的动画效果,让动画更加的自然。

我们来模拟一下,如果是使用 10 个 animation-duration 和 animation-delay 都一致的圆的话,核心伪代码:

ul {

display: flex;

flex-wrap: nowrap;

gap: 5px;

}

li {

background: #000;

animation: move 3s infinite 1s linear;

}

@keyframes move {

0% {

transform: translate(0, 0);

}

100% {

transform: translate(0, -100px);

}

}

这样,小球的运动会是这样的整齐划一:

要让小球的运动显得非常的随机,云服务器提供商只需要让 animation-duration 和 animation-delay 都在一定范围内浮动即可,改造下 CSS:

@for $i from 1 to 11 {

li:nth-child(#{ $i}) {

animation-duration: #{ random(2000)/1000 + 2}s;

animation-delay: #{ random(1000)/1000 + 1}s;

}

}

我们利用 SASS 的循环和 random() 函数,让 animation-duration 在 2-4 秒范围内随机,让 animation-delay 在 1-2 秒范围内随机,这样,我们就可以得到非常自然且不同的上升动画效果,基本不会出现重复的画面,很好的模拟了随机效果:

CodePen Demo -- 利用范围随机 animation-duration 和 animation-delay 实现随机动画效果[3]。

好,我们把上述介绍的技巧,套用到我们本文要实现的效果中去,HTML 结构再看一眼:

// ... 200 个 g-bubble

</div>

核心的 CSS 代码:

.g-footer {

position: absolute;

bottom: 0;

left: 0;

height: 86px;

width: 100%;

background: #26b4f5;

}

@for $i from 0 through 200 {

.g-bubble:nth-child(#{ $i}) {

position: absolute;

background: #26b4f5;

$width: random(100) + px;

left: #{ (random(100)) + %};

top: #{ (random(100))}px;

width: $width;

height: $width;

animation: moveToTop #{ (random(2500) + 1500) / 1000}s ease-in-out -#{ random(5000)/1000}s infinite;

}

}

@keyframes moveToTop {

90% {

opacity: 1;

}

100% {

opacity: .08;

transform: translate(-50%, -180px) scale(.3);

}

}

这里:

我们利用了 SASS 随机函数$width: random(100) + px;,随机生成不同大小的 div 圆形。利用 SASS 随机函数left: #{ (random(100)) + %},top: #{ (random(100))}px 基于父元素随机定位。最为核心的是animation: moveToTop #{ (random(2500) + 1500) / 1000}s ease-in-out -#{ random(5000)/1000}s infinite,让所有 div 圆的运动都是随机的。

上述(1)、(2)综合结果,会生成这样一种布局,站群服务器均匀分散排布的圆形:

注:这里为了方便理解,我隐藏了最外层 g-footer 的颜色,并且给 g-bubble 添加了黑色边框。

接着,如果我们替换一下 animation 语句,使用统一的动画时长,去掉负的延迟,变成 animation: moveToTop 4s ease-in-out infinite,动画就会是这样:

整体是整齐划一,没有杂乱无章的感觉的。

运用上随机效果,animation: moveToTop #{ (random(2500) + 1500) / 1000}s ease-in-out -#{ random(5000)/1000}s infinite,就能得到上述的,不同气泡随机上升的感觉:

添加融合效果

接下来,也是最重要的一步,如何让气泡与气泡之间,以及气泡和底部 .g-footer 之间产生融合效果呢?

这个技巧在此前非常多篇文章中,也频繁提及过,就是利用 filter: contrast() 滤镜与 filter: blur() 滤镜。

如果你还不了解这个技巧,可以戳我的这篇文章看看:你所不知道的 CSS 滤镜技巧与细节[4]。​

简述下该技巧:

单独将两个滤镜拿出来,它们的作用分别是:

filter: blur():给图像设置高斯模糊效果。filter: contrast():调整图像的对比度。

但是,当他们“合体”的时候,产生了奇妙的融合现象。

仔细看两圆相交的过程,在边与边接触的时候,会产生一种边界融合的效果,通过对比度滤镜把高斯模糊的模糊边缘给干掉,利用高斯模糊实现融合效果。

基于此,我们再简单改造下我们的 CSS 代码,所需要加的代码量非常少:

.g-wrap {

background: #fff;

filter: contrast(8);

}

.g-footer {

// ... 其他保持一致

filter: blur(5px);

}

就这么简单,父容器添加白色底色以及对比度滤镜 filter: contrast(8),子容器添加 filter: blur(5px) 即可,这样,我们就能得气泡的融合效果,基本得到我们想要的效果:

利用 backdrop-filter 替代 filter 消除边缘

但是!利用 filter: blur() 会有一个小问题。

运用了 filter: blur() 的元素,元素边缘的模糊度不够,会导致效果在边缘失真,我们仔细看看动画的边缘:

如何解决呢?也好办,在这里,我们尝试利用 backdrop-filter 去替换 filter。

两者之间的差异在于,filter 是作用于元素本身,而 backdrop-filter 是作用于元素背后的区域所覆盖的所有元素,如果你想了解更多关于 backdrop-filter 的信息,可以戳我的这篇文章:深入探讨 filter 与 backdrop-filter 的异同[5]。

简单改造下代码,原代码:

.g-footer {

// ...

filter: blur(5px);

}

改造后的代码:

.g-footer {

// ... 去掉 filter: blur(5px)

&:before {

content: "";

position: absolute;

top: -300px;

left: 0;

right: 0;

bottom: 0;

z-index: 1;

backdrop-filter: blur(5px);

}

}

我们通过去到原来添加在 .g-footer 上的 filter: blur(5px),通过他的伪元素,叠加一层新的元素在它本身之上,并且添加了替代的 backdrop-filter: blur(5px)。

当然,因为这里的 blur(5px) 还需要为气泡与气泡之间的融合服务,所以为了覆盖动画全区域,我们还设置了 top: -300px,扩大了它的作用范围。

最终,我们就能完美的复刻文章一开头,使用 SVG 滤镜实现的效果:

在文章中,我省去了大部分基础的 CSS 代码,完整的代码,你可以戳这里:CodePen Demo -- Bubble Rises[6]。

最后

本文与之前的 巧用 CSS 实现酷炫的充电动画[7] 内使用的技巧非常类似,但本文也有一些新的知识点,大家可以结合着一起看看。

好了,本文到此结束,希望对你有帮助 :)

参考资料

[1]CodePen Demo -- Goey footer: https://codepen.io/z-/pen/zYxdRQy。

[2]深入浅出 CSS 动画: https://github.com/chokcoco/iCSS/issues/141。

[3]CodePen Demo -- 利用范围随机 animation-duration 和 animation-delay 实现随机动画效果: https://codepen.io/Chokcoco/pen/JjyRYyR。

[4]你所不知道的 CSS 滤镜技巧与细节: https://github.com/chokcoco/iCSS/issues/30。

[5]深入探讨 filter 与 backdrop-filter 的异同: https://github.com/chokcoco/iCSS/issues/147。

[6]CodePen Demo -- Bubble Rises: https://codepen.io/Chokcoco/pen/QWQRjrX。

[7]巧用 CSS 实现酷炫的充电动画: https://github.com/chokcoco/iCSS/issues/75。

很赞哦!(71)