放飞孔明灯
我们都知道在很多地方都有元宵节放孔明灯的习惯,但是近年来,一些地方因为环境和安全考虑,开始限制或禁止放孔明灯,以避免火灾和环境污染等问题。于是我就是手写了一个孔明灯放飞的动画,来弥补大家的遗憾。
动画
jcode
HTML源码
<div class="container">
<section class="z-100">
<div class="blur">
<img class="lantern l9" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cd0ea77244db4b4f81d1342ecb7da38d~tplv-k3u1fbpfcp-image.image#?w=109&h=121&s=7562&e=svg&a=1&b=cc793a" alt="孔明灯" />
</div>
<img class="lantern l10" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cd0ea77244db4b4f81d1342ecb7da38d~tplv-k3u1fbpfcp-image.image#?w=109&h=121&s=7562&e=svg&a=1&b=cc793a" alt="孔明灯" />
</section>
<section class="cloud-wrap">
<img class="cloud c4" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5251241ced334d3db28f54a47e71389d~tplv-k3u1fbpfcp-image.image#?w=103&h=45&s=1482&e=svg&a=1&b=14243a" alt="云" />
</section>
<aside class="land"><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7353a091fac64b5aa0650e3068fd95c8~tplv-k3u1fbpfcp-image.image#?w=521&h=69&s=85120&e=svg&a=1&b=13263d" alt="地面" />
</aside>
</div>
源码设计分析
我们先编写一个html页面来为我们的孔明灯升起设施背景框架
-
首先我们先定义一个
<div class="container">
容器,用来存放我们所有的元素和内容,通过container来控制网页的布局和样式。 -
然后我们定义一个
<section>
元素,用来放置我们的孔明灯。-
内部包含了一个带有
<div>
元素,可能用于添加模糊效果。 -
<div>
元素里面包含我们的孔明灯图片,这里我们放置多张
-
-
云的部分我们使用
<section class="cloud-wrap">
元素来存载。我们在里面存放我们的云的图片,这里放置多张。 -
地面部分我们使用
<aside class="land">
元素来存载,我们在里面存放我们的地面的图片 。
scss源码
$bg-light: #243C54
$bg-dark: #091726
html, body, .container, section
width: 100%
height: 100vh
overflow: hidden
.container
position: relative
background: $bg-dark
background: linear-gradient(180deg, $bg-dark 0%, $bg-light 100%)
section
position: absolute
top: 0
right: 0
bottom: 0
left: 0
&.z-100
z-index: 100
.land
position: absolute
right: 0
bottom: -.5rem
left: 0
z-index: 999
img
width: 101vw
.copyright
position: absolute
right: 1rem
left: 1rem
bottom: 1rem
display: flex
justify-content: space-between
font-size: 12px
@media screen and (max-width: 640px)
flex-wrap: wrap
a
text-decoration: none
color: rgba(#FFF, .8)
// 孔明灯
$bg-light: #243C54
$bg-dark: #091726
html, body, .container, section
width: 100%
height: 100vh
overflow: hidden
.container
position: relative
background: $bg-dark
background: linear-gradient(180deg, $bg-dark 0%, $bg-light 100%)
section
position: absolute
top: 0
right: 0
bottom: 0
left: 0
&.z-100
z-index: 100
.land
position: absolute
right: 0
bottom: -.5rem
left: 0
z-index: 999
img
width: 101vw
.copyright
position: absolute
right: 1rem
left: 1rem
bottom: 1rem
display: flex
justify-content: space-between
font-size: 12px
@media screen and (max-width: 640px)
flex-wrap: wrap
a
text-decoration: none
color: rgba(#FFF, .8)
// 孔明灯
@keyframes lantern-rise
0%
transform: translate(0, 0) rotate(0deg)
30%
transform: translate(20%, -40vh) rotate(10deg)
50%
transform: translate(-30%, -90vh) rotate(-10deg)
70%
opacity: 1
transform: translate(20%, -115vh) rotate(10deg)
90%
opacity: 1
transform: translate(10%, -130vh) rotate(5deg)
100%
opacity: 0
transform: translate(0, -140vh) rotate(-10deg)
.lantern
position: absolute
animation: lantern-rise infinite linear
@for $i from 1 through 300
$posX: random() * 90%
$posY: random() * 100% + 90%
$random: random(100) + 16
$second: abs(($random / 1.2) - 150) + s
$delay: $i * -.1s
$size: $random + px
$sizeM: $random / 2 + px
$abs: $random / 100
$g: abs($random / 100 * 100% - 100%)
.l#{$i}
top: $posY
left: $posX
z-index: $random
max-width: $size
filter: grayscale($g)
animation-duration: $second
animation-delay: $delay
.blur .l#{$i}
@if $random % 2 == 0 & $random > 40
filter: blur(7px)
@media screen and (max-width: 640px)
.l#{$i}
max-width: $sizeM
// 云
@keyframes cloud-move-left
5%
opacity: 1
100%
transform: translateX(100vw)
@keyframes cloud-move-right
5%
opacity: 1
100%
transform: translateX(-100vw) rotateY(180deg)
.cloud-wrap
.cloud
position: absolute
opacity: 0
.cloud:nth-of-type(odd)
animation: cloud-move-left linear infinite
.cloud:nth-of-type(even)
transform: translateX(100vw) rotateY(180deg)
animation: cloud-move-right ease-in-out
@for $x from 1 through 20
$posY: random() * 20% + 40%
$z: random(30)
$random: random(100)
$size: ($random + 50) + px
$sizeM: $random / 2 + px
$second: ($z + 100) + s
$delay: ($x * random(10)) + s
.cloud-wrap .cloud.c#{$x}
top: $posY
z-index: $z
max-width: $size
animation-duration: $second
animation-delay: $delay
@media screen and (max-width: 640px)
.cloud-wrap .cloud.c#{$x}
max-width: $sizeM
源码设计分析
- 首先,我们先定义了两个颜色变量
$bg-light
和$bg-dark
,分别用于定义我们的浅色背景和深色背景
-
然后我们要修改我们浏览器的默认样式,
html, body, .container, section
修改成,width
和height
设置为100%
,使它们占据整个可视窗口的宽度和高度。overflow: hidden
隐藏了元素的溢出内容。
-
我们定义
.container
采用相对定位,背景色采用了一个深色到浅色的线性渐变 -
我们定义
section
采用绝对定位,占满父容器。- 并且
.z-100
类设置z-index
为 100
- 并且
-
设置
.land
地面,采用绝对定位。使用元素固定在底部
接下来是我们最核心的动画,也就是孔明灯放飞的部分。
核心动画
首先我们要定义一个控制了孔明灯升起的关键帧动画 lantern-rise
,来控制了孔明灯升起的动画效果。
@keyframes lantern-rise
0%
transform: translate(0, 0) rotate(0deg)
30%
transform: translate(20%, -40vh) rotate(10deg)
50%
transform: translate(-30%, -90vh) rotate(-10deg)
70%
opacity: 1
transform: translate(20%, -115vh) rotate(10deg)
90%
opacity: 1
transform: translate(10%, -130vh) rotate(5deg)
100%
opacity: 0
transform: translate(0, -140vh) rotate(-10deg)
0%
:初始状态,孔明灯保持最初位置。30%
:在 30% 的时候,向右平移20%的宽度,向上平移40vh(视窗高度的百分比),并顺时针旋转了10度。50%
:在 50% 的时候,左平移30%的宽度,向上平移90vh,同时逆时针旋转了10度。70%
:在 70% 的时候,孔明灯的透明度变为1,将孔明灯向右平移20%的宽度,向上平移115vh,并以10度的角度顺时针旋转。90%
:在 90% 的时候,孔明灯继续向上移动,透明度保持为1,将孔明灯向右平移10%的宽度,向上平移130vh,并以5度的角度顺时针旋转。100%
:最终状态,透明度变为0,孔明灯回到初始位置下方,向上平移140vh,并以-10度的角度逆时针旋转。
position: absolute
animation: lantern-rise infinite linear
给的孔明灯添加.lantern
类,并且设置为无限循环播放,线性过渡。
循环孔明灯
我们可以使用 Sass 的控制流语法,在一个循环中生成了一系列的孔明灯(lantern)元素,并且随机属性让得孔明灯看起来分布随机,大小和动画速度各异。
-
@for $i from 1 through 300
:,我们循环生成300个孔明灯元素。 -
在每次循环迭代中,都进行随机设置了值
$posX
:随机的水平位置,位于页面宽度的90%内。$posY
:随机的垂直位置,位于页面高度的90%以上。这会使孔明灯从屏幕底部开始升起。$random
:随机数,取值范围从16到115(100+16),用于确定其他随机属性。$second
:根据随机数计算的动画持续时间,单位为秒。$delay
:动画延迟时间,通过每次循环迭代的$i
值生成,每个孔明灯的延迟递减0.1秒。$size
:随机的孔明灯大小,以像素为单位。$sizeM
:随机的孔明灯大小,用于小屏幕设备,大小是正常大小的一半。$abs
:随机的透明度,介于0到1之间。$g
:随机的灰度滤镜强度,用于使孔明灯变得灰色。
-
定义一个
.l#{$i}
:选择器,因为我们生成的孔明灯元素会具有类名 从.l1
到.l300
,类名中的数字根据我们当前循环的$i
值而变化。这样我们可以为每个孔明灯元素定义不同的样式。 -
然后我们孔明灯元素的样式定义中,会根据以下样式属性随机变量进行设置:
top
和left
:分别设置孔明灯的随机垂直和水平位置。z-index
:设置孔明灯的随机堆叠顺序。max-width
:设置孔明灯的随机最大宽度。filter
:设置孔明灯的随机灰度滤镜强度。animation-duration
:设置孔明灯的动画持续时间。animation-delay
:设置孔明灯的动画延迟。
然后我们要给符合条件的孔明灯添加模糊效果
.blur .l#{$i}
@if $random % 2 == 0 & $random > 40
filter: blur(7px)
@media screen and (max-width: 640px)
.l#{$i}
max-width: $sizeM
这里我们定义一个模糊样式.blur .l#{$i}
,当$random
是偶数且大于40,就会为孔明灯应用模糊效果。
- 在这里,如果
$random
是偶数且大于40,就会为孔明灯应用模糊效果,filter: blur(7px)
。
在这里我们要进行一个屏幕适配,进行一个媒体查询,用于针对小屏幕设备设置特定的样式。
如果是小于640px的屏幕.l#{$i}
孔明灯元素的 max-width
会根据 $sizeM
改变,
云的动画
我们定义两个云的动画 cloud-move-left
和 cloud-move-right
,分别用于云向左和向右移动。
cloud-move-left(向左)
@keyframes cloud-move-left
5%
opacity: 1
100%
transform: translateX(100vw)
5%
:初始状态,透明度为1,云的位置不发生变化。100%
:最终状态,云通过transform
属性在水平方向上向右移动了整个视窗的宽度,即translateX(100vw)
。
cloud-move-right
向右
@keyframes cloud-move-right
5%
opacity: 1
100%
transform: translateX(-100vw) rotateY(180deg)
5%
:初始状态,透明度为1,云的位置不发生变化。100%
:最终状态,云通过transform
属性在水平方向上向左移动了整个视窗的宽度,同时发生了180度的Y轴旋转,即translateX(-100vw) rotateY(180deg)
。
分两部控住云
.cloud-wrap
.cloud
position: absolute
opacity: 0
.cloud:nth-of-type(odd)
animation: cloud-move-left linear infinite
.cloud:nth-of-type(even)
transform: translateX(100vw) rotateY(180deg)
animation: cloud-move-right ease-in-out
-
.cloud-wrap
类:position: absolute
:设置云元素的定位方式为绝对定位,这样它们可以自由定位在父元素内。opacity: 0
:设置初始时云元素的不透明度为0,即完全透明。
-
.cloud:nth-of-type(odd)
和.cloud:nth-of-type(even)
:- 这些选择器选择了云元素中的奇数和偶数项。这是为了使奇数项的云元素应用
cloud-move-left
动画,而偶数项的云元素应用cloud-move-right
动画。
- 这些选择器选择了云元素中的奇数和偶数项。这是为了使奇数项的云元素应用
-
.cloud:nth-of-type(odd)
:animation: cloud-move-left linear infinite
:为奇数项的云元素应用cloud-move-left
动画效果,使用线性时间函数(linear
)并设置为无限循环(infinite
)。
-
.cloud:nth-of-type(even)
:transform: translateX(100vw) rotateY(180deg)
:将偶数项的云元素初始时移动到页面的右侧,同时进行180度的Y轴旋转,以实现出现在页面的右侧并以不同的方向移动。animation: cloud-move-right ease-in-out
:为偶数项的云元素应用cloud-move-right
动画效果,使用 ease-in-out 时间函数,也设置为无限循环。
循环云动画
@for $x from 1 through 20
$posY: random() * 20% + 40%
$z: random(30)
$random: random(100)
$size: ($random + 50) + px
$sizeM: $random / 2 + px
$second: ($z + 100) + s
$delay: ($x * random(10)) + s
.cloud-wrap .cloud.c#{$x}
top: $posY
z-index: $z
max-width: $size
animation-duration: $second
animation-delay: $delay
-
@for $x from 1 through 20
:我们要循环将生成20个云元素。 -
在每次循环迭代中,都进行随机设置了值
$posY
:随机的垂直位置,位于页面高度的40%以上,最多不超过60%。$z
:随机的 z-index 值,最大为30。$random
:随机数,取值范围从0到99(100-1),用于确定其他随机属性。$size
:随机的云元素大小,通过将随机数加上50,然后加上 px 单位。$sizeM
:用于小屏幕设备的随机云元素大小,是正常大小的一半。$second
:根据随机数 $z 计算的动画持续时间,单位为秒,范围为100秒到130秒。$delay
:动画延迟时间,通过每次循环迭代的 $x 值和随机数生成,每个云元素的延迟时间不同。
-
定义一个
.cloud-wrap .cloud.c#{$x}
:选择器,因为我们生成的云元素会具有类名 从.c1
到.c20
,类名中的数字根据我们当前循环的$x
值而变化。这样我们可以为每个云元素定义不同的样式。 -
然后我们云元素的样式定义中,会根据以下样式属性随机变量进行设置:
- top:设置云元素的垂直位置为随机的 $posY。
- z-index:设置云元素的 z-index 值为随机的 $z,决定了它们的堆叠顺序。
- max-width:设置云元素的最大宽度为随机的 $size,使它们具有不同的大小。
- animation-duration:设置云元素的动画持续时间为随机的 $second,使它们有不同的速度。
- animation-delay:设置云元素的动画延迟时间为随机的 $delay,使它们的动画开始时间不同。
- @media screen and (max-width: 640px):这是一个媒体查询,用于针对小屏幕设备设置特定的样式。
@media screen and (max-width: 640px)
.cloud-wrap .cloud.c#{$x}
max-width: $sizeM
在这里我们要进行一个屏幕适配,进行一个媒体查询,用于针对小屏幕设备设置特定的样式。
如果是小于640px的屏幕.cloud-wrap .cloud.c#{$x}
云元素的 max-width
会根据 $sizeM
改变,