• 使用纯 CSS 实现超酷炫的粘性气泡效果


    🚀 优质资源分享 🚀

    学习路线指引(点击解锁)知识定位人群定位
    🧡 Python实战微信订餐小程序 🧡进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
    💛Python量化交易实战💛入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h9gfqLEW-1656996688611)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dfdaaa08049e4df49e047e973c5106ad~tplv-k3u1fbpfcp-watermark.image?)]

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

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

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

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

    借助 SASS 完成大致效果

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zewdRI8F-1656996688615)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bf1a317a414e405e8006d5cb9b39f8c9~tplv-k3u1fbpfcp-watermark.image?)]

    要制作这样一个效果还是比较简单的,只是代码会比较多,我们借助 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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

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

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

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

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

    <ul>
        <li>li>
         
        <li>li>
    ul>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-joUcWeVj-1656996688616)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/528ab7057f384feeb35c1f940e7f9615~tplv-k3u1fbpfcp-zoom-1.image)]

    要让小球的运动显得非常的随机,只需要让 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;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vokKlDcs-1656996688617)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/63a2d6ac45c04077a53c5e4dfc26ca28~tplv-k3u1fbpfcp-watermark.image?)]

    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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    核心的 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    这里:

    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)综合结果,会生成这样一种布局,均匀分散排布的圆形:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e9tq1Swj-1656996688619)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7567b9e04dfa4a6e88b9e7f78b52465d~tplv-k3u1fbpfcp-zoom-1.image)]

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

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y3QgAEyB-1656996688620)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5d673a16c5e5451b8fb0a015ca4dff2d~tplv-k3u1fbpfcp-zoom-1.image)]

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

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PI5zFGgJ-1656996688621)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b1c4c02c746843bdbe908900568a0262~tplv-k3u1fbpfcp-watermark.image?)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EG7X3pVE-1656996688621)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6f73321c0eda48e0b8f7981da71482b2~tplv-k3u1fbpfcp-watermark.image?)]

    添加融合效果

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

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

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

    简述下该技巧:

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

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

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CL84mOMH-1656996688622)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f2973c4eafd84078b5febce205984dd0~tplv-k3u1fbpfcp-zoom-1.image)]

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

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

    .g-wrap {
        background: #fff;
        filter: contrast(8);
    }
    .g-footer {
        // ... 其他保持一致
        filter: blur(5px);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-33XVup9p-1656996688623)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cbc1e364a4034c798707f1e407b590d3~tplv-k3u1fbpfcp-watermark.image?)]

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

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

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Ce1XYLX-1656996688624)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e4057e3783824949b0cf07383507075e~tplv-k3u1fbpfcp-zoom-1.image)]

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

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

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

    .g-footer {
        // ... 
        filter: blur(5px);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    改造后的代码:

    
    .g-footer {
        // ... 去掉 filter: blur(5px)
        &:before {
            content: "";
            position: absolute;
            top: -300px;
            left: 0;
            right: 0;
            bottom: 0;
            z-index: 1;
            backdrop-filter: blur(5px);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

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

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3TjMkR1K-1656996688625)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/15f0e0cd7766409aa12b1bedfc77b58e~tplv-k3u1fbpfcp-watermark.image?)]

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

    最后

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

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

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

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

    想 Get 到最有意思的 CSS 资讯,千万不要错过我的 iCSS 公众号 😄 :

    image

    如果觉得文章对您有用,请随意打赏。您的支持将鼓励我继续创作!打赏支持+## (_)打个赏喝个咖啡(_)

    微信支付支付宝支付

  • 相关阅读:
    飞腾CPU FT-2000/4 uboot下PHY调试记录
    WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展
    立即执行函数在前端国际化方案中的应用
    Redis lua_client 伪客户端生命周期
    EMANE中olsrd的调试
    eslint与prettier
    93. 复原 IP 地址
    MariaDB Tutorial
    【Java】Jxls--轻松生成 Excel
    博客园众包平台:游戏开发者找人长期合作建设自己的网站
  • 原文地址:https://blog.csdn.net/xuhss_com/article/details/125617464