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

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

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

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

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

借助 SASS 完成大致效果

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

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

假设我们有如下 HTML 结构:

<div class="g-wrap">
<div class="g-footer">
<div class="g-bubble"></div>
<div class="g-bubble"></div>
// ... 200 个 g-bubble
</div>
</div>

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

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

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

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

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

<ul>
<li></li>
<!--共 10 个...-->
<li></li>
</ul>
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-durationanimation-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 实现随机动画效果

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

<div class="g-wrap">
<div class="g-footer">
<div class="g-bubble"></div>
<div class="g-bubble"></div>
// ... 200 个 g-bubble
</div>
</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);
}
}

这里:

  1. 我们利用了 SASS 随机函数 $width: random(100) + px;,随机生成不同大小的 div 圆形
  2. 利用 SASS 随机函数 left: #{(random(100)) + '%'}top: #{(random(100))}px 基于父元素随机定位
  3. 最为核心的是 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 滤镜技巧与细节

简述下该技巧:

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

  1. filter: blur(): 给图像设置高斯模糊效果。
  2. 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 的异同

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

.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

最后

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

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

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

使用纯 CSS 实现超酷炫的粘性气泡效果的更多相关文章

  1. 超酷炫的转场动画?CSS 轻松拿下!

    在 WeGame 的 PC 端官网首页,有着非常多制作精良的基于滚动的动画效果. 这里我简单截取其中 2 个比较有意思的转场动画,大家感受感受.转场动画 1: 转场动画 2: 是不是挺有意思的,整个动 ...

  2. 纯CSS3写的10个不同的酷炫图片遮罩层效果【转】

    这个是纯CSS3实现的的10个不同的酷炫图片遮罩层效果,可以欣赏一下 在线预览 下载地址 实例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...

  3. 纯CSS3写的10个不同的酷炫图片遮罩层效果

    这个是纯CSS3实现的的10个不同的酷炫图片遮罩层效果,可以欣赏一下 在线预览 下载地址 实例代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 ...

  4. Amazing!巧用 CSS 视差实现酷炫交互动效

    本文将介绍利用 CSS 实现滚动视差效果的一个小技巧,并且,利用这个技巧来制作一些有意思的交互特效. 关于使用 CSS 实现滚动视差效果,在之前有一篇文章详细描述过具体方案 - CSS 实现视差效果, ...

  5. TensorSpace:超酷炫3D神经网络可视化框架

    TensorSpace:超酷炫3D神经网络可视化框架 TensorSpace - 一款 3D 模型可视化框架,支持多种模型,帮助你可视化层间输出,更直观地展示模型的输入输出,帮助理解模型结构和输出方法 ...

  6. 纯CSS实现帅气的SVG路径描边动画效果(转载)

    本文转载自: 纯CSS实现帅气的SVG路径描边动画效果

  7. 基于Kinetic框架实现超酷的风铃悬挂摆动效果

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/iefreer/article/details/37049987 在踏得网开发过程中,我们在引导页面中 ...

  8. 使用NestedScrollView+ViewPager+RecyclerView+SmartRefreshLayout打造酷炫下拉视差效果并解决各种滑动冲突

    使用NestedScrollView+ViewPager+RecyclerView+SmartRefreshLayout打造酷炫下拉视差效果并解决各种冲突 如果你还在为处理滑动冲突而发愁,那么你需要静 ...

  9. 用 CSS 实现酷炫的动画充电效果

    巧用 CSS 实现酷炫的充电动画 循序渐进,看看只使用 CSS ,可以鼓捣出什么样的充电动画效果. 画个电池 当然,电池充电,首先得用 CSS 画一个电池,这个不难,随便整一个: 欧了,勉强就是它了. ...

随机推荐

  1. AspNetCore配置多环境log4net配置文件

    前言 在之前的文章中有讲到AspNetCore多环境配置文件的应用,我们根据自己多种环境分别配置多个appsettings.$EnvironmentName.json文件. 在实际的开发中我们可能会遇 ...

  2. Python学习笔记: getpass module: 安全输入密码

    使用场景 使用input()函数接收用户输入的时候会将用户输入回显,对于密码肯定是不适用的.标准库里面有getpass module提供了安全输入不回显 getpass module有2个函数 get ...

  3. LintCode-1173 · 反转字符串 III-题解(istringstream简单使用)

    题目链接:https ://www.lintcode.com/problem/1173/?_from=collection&fromId=208描述:给定一个字符串句子,反转句子中每一个单词的 ...

  4. Neo4j数据和Cypher查询语法笔记

    Cypher数据结构 Cypher的数据结构: 属性类型, 复合类型和结构类型 属性类型 属性类型 Integer Float String: 'Hello', "World" B ...

  5. Java继承实例解析

    Java继承 前言 继承是面向对象语法的三大特征之一.继承可以降低代码编写的冗余度,提高编程的效率.通过继承,子类获得了父类的成员变量和方法.一个子类如何继承父类的字段和方法,如何修改从父类继承过来的 ...

  6. 【机器学习基础】无监督学习(3)——AutoEncoder

    前面主要回顾了无监督学习中的三种降维方法,本节主要学习另一种无监督学习AutoEncoder,这个方法在无监督学习领域应用比较广泛,尤其是其思想比较通用. AutoEncoder 0.AutoEnco ...

  7. SpringBoot接入两套kafka集群

    引入依赖 compile 'org.springframework.kafka:spring-kafka' 第一套kafka配置 package myapp.kafka; import lombok. ...

  8. K8S面试应知必回

    目录 面试不要不懂装懂,不会就是不会,不可能每个人都接触过所有的知识! 1. 基础问题 1.1 Service是怎么关联Pod的?(课程Service章节) 1.2 HPA V1 V2的区别 1.3 ...

  9. GIT速查手册

    一.GIT 1.1 简单配置 git是版本控制系统,与svn不同的是git是分布式,svn是集中式 配置文件位置 # 配置文件 .git/config 当前仓库的配置文件 ~/.gitconfig 全 ...

  10. 146_ACCESS之HR招聘信息管理_64位

    焦棚子的文章目录 点击下载附件 一.背景: 最近把之前做的一个HR招聘信息管理工具翻新了下,有需要的朋友可以自取,主要想解决的问题是多人在跟进人员招聘的时候信息的不对称,这样下来的就可以及时的看到整个 ...