CSS动效合集之实现气泡发散动画

前言

👏「CSS 动效合集之实现气泡发散动画,速速来 Get 吧~」

🥇「文末分享源代码。记得点赞+关注+收藏!」

1.实现效果

图片

2.实现步骤

  • 定义一个数组 bubbles,用来存储气泡列表的基本新,w 表示宽高,x 表示绝对定位中 left 的百分比
  • 注:以下代码基于 vue
const bubbles = ref([
{
w: 8,
x: 10,
},
{
w: 9,
x: 50,
},
{
w: 4,
x: 30,
},
{
w: 5,
x: 80,
},
{
w: 4,
x: 30,
},
{
w: 4,
x: 70,
},
{
w: 6,
x: 20,
},
{
w: 8,
x: 50,
},
{
w: 4,
x: 60,
},
{
w: 6,
x: 65,
},
]);
  • 绘制父元素 section,设置宽高为 300px,相对定位
图片
section {
height: 300px;
width: 300px;
margin: 50px auto;
position: relative;
z-index: 1;
border-radius: 20px;
box-shadow: 0px 9px 17px 4px rgba(0, 0, 0, 0.5);
}
  • section 内添加子元素 bubbles 标签,设置宽高与父元素一致,绝对定位
  • 在 bubbles 用 span 标签循环展示气泡列表
<div class="bubbles">
<span
class="bubble"
v-for="(item, index) in bubbles"
:key="index"
}"
></span>
</div>
  • 为 span 标签添加 css 变量,设置–w 表示元素的宽高,–x 表示绝对定位中 left 的百分比
<span
class="bubble"
v-for="(item, index) in bubbles"
:key="index"
:style="{
'--w': item.w,
'--x': item.x,
}"
  • 气泡设置绝对定位,初始位置居于父元素的底部 10%,水平居中,并设置宽高为–w,默认设置背景色为粉色
图片
.bubble {
position: absolute;
width: calc(1px * var(--w));
height: calc(1px * var(--w)); border-radius: 50%;
left: calc(50% - calc(1px * calc(var(--w) / 2)));
bottom: 10%;
background: pink;
}
  • 为气泡添加发散动画
.bubble {
+ animation: rise 3s infinite linear;
}
  • 实现气泡 left 由水平居中到对应列表中–x 的变化,bottom 位置由 10%到 100%的改变,opacity 透明度由刚开始的 0 到中间 0.8,最后 0 的变化
图片


@keyframes rise {
  0% {
    left: calc(50% - calc(1px * calc(var(--w) / 2)));
    opacity: 0;
    bottom: 10%;
  }
  50% {
    opacity: 0.8;
  }
  100% {
    left: calc(1% * var(--x));
    bottom: 90%;
    opacity: 0;
  }
}
  • 给每个气泡设置不同的动画延迟,实现错落的效果,在 span 标签上添加–d,表示当前标签动画延迟时间
图片
<span
class="bubble"
v-for="(item, index) in bubbles"
:key="index"
:style="{
'--w': item.w,
'--x': item.x,
'--d':
parseInt(bubbles.length / 2) +
1 -
Math.abs(index - parseInt(bubbles.length / 2)),
}"
></span>
.bubble {
+ animation-delay: calc(600ms * var(--d));
}
  • 可以发现,设置了动画延迟,在初始阶段,会出现固定的气泡展示在中心位置,这不是我们想要的效果,修改 span 标签样式,设置其默认的透明度为 0
图片
.bubble {
+ opacity: 0;
}
  • 当前动画时长是 3s,动画延迟为间隔 600ms * 延长单位,气泡列表长度为 10 个,我们尝试将动画延迟为间隔设置 100ms,会发生什么呢?
图片
  • 可以发现,气泡发散效果变的不连贯,延迟的时间间隔不够大,如果想要气泡发散是比较连贯的效果,就需要去平衡动画总时长和延迟间隔
  • 为每个气泡设置不同的颜色,定义一个颜色数组 colors
 colors: {
type: Array,
default: () => ["#00BABC", "#009FA4", "#00FFC0"],
},
  • 每个气泡的颜色根据当前数据的索引从 colors 中获取
bubbles.value.forEach((i, index) => {
i.c = props.colors[index]
});
  • 那么随之而来一个问题,当 bubbles 数据过多,colors 不够用怎么解决?
  • 当 colors 不够用时候,就从 colors 的第一项继续赋值
  • 定义一个循环取值的方法
/**
* 根据索引循环取数值的值,取模运算符(%)来实现循环取数组的值
* @param {*} array
* @param {*} sort
* @returns
*/
export const forArrayValue = (array, sort) => {
return array[sort % array.length];
};
  • bubbles 重新赋值
bubbles.value.forEach((i, index) => {
i.c = forArrayValue(props.colors, index);
});
  • 为每个气泡 span 标签添加–c 变量,表示当前背景颜色
图片
<span
class="bubble"
v-for="(item, index) in bubbles"
:key="index"
:style="{
'--w': item.w,
'--c': item.c,
'--x': item.x,
'--d':
parseInt(bubbles.length / 2) +
1 -
Math.abs(index - parseInt(bubbles.length / 2)),
}"
></span>
.bubble {
+ background: var(--c);
}
  • 为其父元素 bubbles 设置溢出隐藏,以防 left 位置变化超出当前容器,设置 z-index 为-1,以防遮挡到父元素其他内容
.bubbles {
+ z-index: -1;
+ overflow: hidden;
}
  • 这样就完整的实现啦~
图片
  • 当然,你可以可以通过代码,动态的去生成气泡列表,使用 Math.random 生成其位置和大小,实现原理与上述一致~,这里就不在赘述了

3.实现代码

<template>
<section>
<div class="bubbles">
<span
class="bubble"
v-for="(item, index) in bubbles"
:key="index"
:style="{
'--w': item.w,
'--c': item.c,
'--x': item.x,
'--d':
parseInt(bubbles.length / 2) +
1 -
Math.abs(index - parseInt(bubbles.length / 2)),
}"
></span>
</div>
</section>
</template>
<script setup>
import { ref } from "vue";
import { forArrayValue } from "@/utils/tools";
const props = defineProps({
colors: {
type: Array,
default: () => ["#00BABC", "#009FA4", "#00FFC0"],
},
});
const bubbles = ref([
{
w: 8,
x: 10,
},
{
w: 9,
x: 50,
},
{
w: 4,
x: 30,
},
{
w: 5,
x: 80,
},
{
w: 4,
x: 30,
},
{
w: 4,
x: 70,
},
{
w: 6,
x: 20,
},
{
w: 8,
x: 50,
},
{
w: 4,
x: 60,
},
{
w: 6,
x: 65,
},
]);
bubbles.value.forEach((i, index) => {
i.c = forArrayValue(props.colors, index);
});
</script>
<style lang="less" scoped>
section {
height: 300px;
width: 300px;
margin: 50px auto;
position: relative;
z-index: 1;
border-radius: 20px;
box-shadow: 0px 9px 17px 4px rgba(0, 0, 0, 0.5);
}
.bubbles {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: -1;
overflow: hidden;
}
.bubble {
position: absolute;
width: calc(1px * var(--w));
height: calc(1px * var(--w));
background: var(--c);
border-radius: 50%;
left: calc(50% - calc(1px * calc(var(--w) / 2)));
opacity: 0;
bottom: 10%;
animation: rise 3s infinite linear;
animation-delay: calc(600ms * var(--d));
}
@keyframes rise {
0% {
left: calc(50% - calc(1px * calc(var(--w) / 2)));
opacity: 0;
bottom: 10%;
}
50% {
opacity: 0.8;
}
100% {
left: calc(1% * var(--x));
bottom: 90%;
opacity: 0;
}
}
</style>

4.写在最后 🍒

看完本文如果觉得对你有一丢丢帮助,记得点赞+关注+收藏鸭 🍕
更多相关内容,关注 🍥**苏苏的 bug**,🍡苏苏的 github[1],🍪苏苏的码云[2]~

Reference

[1]

苏苏的github:https://github.com/susu-hu[2]

苏苏的码云:https://gitee.com/susuhhhhhh

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/317331.html

联系我们
联系我们
分享本页
返回顶部