快过年了,我写了一个放鞭炮动画🔥
PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛
效果展示
首先放上效果图:
线上预览地址:鞭炮动画
ps:动画是一次性的,每次刷新才能看到效果,毕竟鞭炮燃放后就没了(偷懒了-_-)
实现
参考图片
本文鞭炮静态展示页面是参考上面图片实现的,技术上用的vue + scss,动画效果就是css动画,没有用到js。
实现单个鞭炮
单个鞭炮其实就是一个圆柱体,所以我们先画个圆柱体再完善细节。
- 先画一个圆柱体的外表面,用
linear-gradient
属性设置为渐变背景色
.item{
margin: 10px;
position: relative;
width: 40px;
height: 100px;
background: linear-gradient(90deg,#6e0009,#e64743,#6e0009);
}
- 利用伪元素画底和顶,为了底部有点层次感,给
border
设置为一层深色,再用outline
设置为浅色:
.item{
// ...
&::before,&::after{
content: '';
position: absolute;
display: inline-block;
width: 38px;
height: 20px;
border-radius: 50%;
}
&::before{
width: 40px;
top: -10px;
background: linear-gradient(90deg,#6e0009,#e64743,#6e0009);
}
&::after{
left: 1px;
bottom: -9px;
background: #9f6f2d;
border: 1px solid #58301b;
outline: 1px solid #9f6f2d;
}
}
- 最后画上下的黄色线条
黄色的线条其实是两个椭圆叠起来的效果,然后利用定位放在圆柱体上,因为和背景色是一样的所以才有这样的效果:
.cicle{
position: absolute;
top: -6px;
width: 100%;
height: 20px;
background: linear-gradient(90deg,#9f6f2d,#dfa351,#9f6f2d);
border-radius: 50%;
&::before{
content: '';
position: absolute;
display: inline-block;
top: 3px;
width: 100%;
height: 20px;
border-radius: 50%;
background: linear-gradient(90deg,#6e0009,#e64743,#6e0009);
}
&.cicle1{
top: 82px;
}
}
- 细节调整 颜色我是吸的图片上的颜色,但是效果看起来有点黯淡,于是加了一层滤镜:
.container{
filter: contrast(120%);
}
画单个的时候为了方便调整效果画的有点大,组合成一串鞭炮的时候适当缩小就行了。
单个鞭炮代码的完整代码:one.vue
组合成一串鞭炮
- 编写容器和线
这应该很好理解,所有的鞭炮排放位置是相对于线的位置排放的,所以线设置属性
position: relative
<div class="bianpao">
<div class="main">
</div>
</div>
对应css:
.bianpao {
position: relative;
width: 400px;
height: 380px;
margin: 0 auto;
transform-origin: top;
padding: 20px;
}
.main {
width: 2px;
height: 52.6%;
background: black;
margin: 40px auto;
position: relative;
box-shadow: 0 0 1px black;
}
- 引入鞭炮组件
<template>
<div class="bianpao">
<div class="main">
<One v-for="item in 40" :key="item" />
<One class="last-one" />
</div>
</div>
</template>
<script>
import One from './one.vue'
export default {
components: {
One
}
}
</script>
- 排放鞭炮 单数排一边,双数排一边,类似这样:
- 旋转鞭炮 从图片上可以看出,鞭炮的旋转角度0-90度的样子,我们也让鞭炮随机旋转一个角度即可。单数旋转正角度,双数旋转负角度:
第3,4步用到了scss的遍历和随机函数,相关scss代码如下:
.container:nth-child(2n) {
left: -28px;
}
.container:nth-child(2n + 1) {
right: -28px;
}
.last-one {
transform: scale(0.4) rotate(10deg);
bottom: -120px;
}
@for $i from 1 through 20 {
$angle: #{random(70) + 20}deg;
@if ($i % 2 == 0) {
$angle: -#{random(70) + 20}deg;
}
.container:nth-child(#{$i}) {
top: 14px + $i * 8px;
transform: scale(0.4) rotate($angle);
}
}
@for $i from 20 through 40 {
$angle: #{random(70) + 7}deg;
@if ($i % 2 == 0) {
$angle: -#{random(70) + 7}deg;
}
.container:nth-child(#{$i}) {
top: 14px + ($i - 20) * 8px;
transform: scale(0.4) rotate($angle);
}
}
可以注意到我把40个鞭炮分成了两组去写,因为我发现这样做随机出来的效果更好看一点。
- 最后一个鞭炮 由于每次改动代码,随机函数生成的值都不一样,每次生成的鞭炮旋转角度也不一样,形状也就不一样,我们有可能会出现这样的效果:
下面分开太大不太好看,于是加上最后一个鞭炮来协调一下,位置看着调就行了
实现光斑
光斑是燃放鞭炮的时候产生的一个效果,单个光斑是用渐变背景和box-shadow来实现的。
$yellow: #fdf410;
background: radial-gradient(rgba($yellow, 0.6), rgba($yellow, 0.1));
box-shadow: 0 0 20px rgba($yellow, 0.6);
光斑的有以下特点:大小随机,位置随机。又可以用到上面提到过的random()函数了,完整代码如下:
<div class="spot-wrap">
<div v-for="item in 50" :key="item" class="spot" />
</div>
$yellow: #fdf410;
.spot-wrap {
position: absolute;
bottom: -160px;
left: 50%;
transform: translateX(-50%);
width: 200px;
height: 200px;
.spot {
position: absolute;
background: radial-gradient(rgba($yellow, 0.6), rgba($yellow, 0.1));
box-shadow: 0 0 20px rgba($yellow, 0.6);
border-radius: 50%;
animation: twikle 1.2s infinite alternate;
}
@for $i from 1 through 50 {
.spot:nth-child(#{$i}) {
width: #{random($limit: 20) + 20}px;
height: #{random($limit: 20) + 16}px;
top: #{random($limit: 150) + 10}px;
left: #{random($limit: 160) + 10}px;
animation-delay: -#{random($limit: 4)}s;
}
}
@keyframes twikle {
0% {
opacity: 1;
}
100% {
opacity: 0.2;
}
}
}
给每个光斑加了闪烁的动画,看起来更生动一点。
效果是这样的
实现爆炸后的碎片
和光斑类似,但不一样的地方在于,每个碎片除了大小位置不一样外,颜色和形状也不一样。大小随机和位置随机前面我们已经说过怎么实现了,下面主要将其他不一样的地方
- 不同颜色的碎片 颜色我们用rgba函数来取随机数,但是要限制每个值的范围,因为我们只想用红色系的颜色:
background: rgba(random(100) + 155, random(100), random(100), 1);
- 不同形状 形状是用clip-path属性实现的,polygon()函数让我们可以实现各种形状。
我们给每个div分组,分为3n,4n,10n和其他,每组设置成不一样的形状,这样保证了碎片形状的随机性,相关scss代码如下:
@for $i from 1 through 50 {
.suipian:nth-child(#{$i}) {
width: #{random($limit: 6) + 8}px;
height: #{random($limit: 6) + 8}px;
top: #{random($limit: 120) + 6}px;
left: #{random($limit: 120) + 6}px;
/* animation-delay: -#{random($limit: 4)}s; */
background: rgba(random(100) + 155, random(100), random(100), 1);
@if ($i % 3 == 0) {
clip-path: polygon(#{random($limit: 100)}% 0%, #{random($limit: 100)}% 10%, #{random($limit: 100)}% 80%, 0% 60%);
} @else if($i % 4 == 0) {
clip-path: polygon(#{random($limit: 100)}% 0%, #{random($limit: 100)}% 10%, #{random($limit: 100)}% 40%, 0% 20%);
} @else if($i % 10 == 0) {
clip-path: circle(24%);
} @else {
clip-path: polygon(#{random($limit: 40)}% 0%, #{random($limit: 100)}% 10%, #{random($limit: 100)}% 80%, #{random($limit: 80)}% 60%, 0% 20%);
}
}
}
- 碎片的动画 碎片的动画是加在每个碎片上的,运动轨迹类似下图这样:
单数的先向左上运动再向下运动,双数的先向右上运动再向下运动,每个动画的延迟时间随机,移动的距离也是随机的。
@for $i from 1 through 50 {
.suipian:nth-child(#{$i}) {
// ...
animation: move#{$i} .8s infinite;
animation-delay: -#{random($limit: 4)}s;
$der: #{random($limit: 100)}px;
@if ($i % 2 == 0) {
$der: -#{random($limit: 100)}px;
}
@keyframes move#{$i} {
30%{
transform: translate($der,-#{random($limit: 100)}px);
opacity: 0.8;
}
100%{
transform: translate($der,#{random($limit: 200) + 10}px);
opacity: 0;
}
}
}
}
效果是这样的
实现动画
至此静态的效果可以完成了:
整体的动画包括两个方面,一个是鞭炮的掉落,一个是线的燃烧
- 鞭炮的掉落
.container {
// ...
animation: drop 1s forwards;
}
@keyframes drop{
80%,100%{
transform: scale(0.3) rotate(0deg) translateY(1600px);
opacity: 0;
}
}
设置每个鞭炮的动画延时不一样,注意下面的鞭炮应该先掉落,所以应该是这样的:
@for $i from 1 through 20 {
animation-delay: #{(20 - $i)*0.1}s;
}
@for $i from 20 through 40 {
animation-delay: #{(40 - $i)*0.1}s;
}
- 线的燃烧 只需要减小线的高度就行了,因为光斑和碎片都是相对线的bottom定位的,所以就自动往上移动。
.main {
// ...
animation: ranshao 2s forwards;
@keyframes ranshao {
84%{
opacity: 1;
height: 80px;
}
100%{
opacity: 0;
height: 80px;
}
}
}
以上完整代码:bianpao.vue
结语
第一版的效果就这样吧,从有这个想法开发到实现已经比较满意了~~
其他动画: css 实现伪3D魔方动态效果
转载自:https://juejin.cn/post/7052587733553774622