我用 140 行代码,带你看一场流星雨⭐
? 大家好,我叫小丞同学,今天走个治愈风,来做一个治愈系的流星雨效果
前言
在一个夜深人静的晚上,程序员小丞坐在屋顶上,看着屏幕上满屏的error,心里拔凉拔凉的,泪水润湿了脸庞,无数个自己提桶跑路的身影充斥在脑海之中,猛然才发现自己还没有桶。此时星空中闪过了漫天的流星,小丞看到此景,心中的bug早已化去,留下的是还原此景的豪言壮举!(梦醒了,纯属瞎编)
小丞把脑海中的场景描绘成了动画,开始了他的 show time
分析动画
产品的需求已经明确下来了,很简单实现一个流星雨效果,那么接下来我们需要对动画进行分析,然后一步步的实现最终的效果,第一次看到这个效果的时候感觉很震撼,流星的效果非常的逼真,很炫酷。我们来分析一下过程,从一般的思路来看,我们可以通过 CSS3
动画来实现,绘制一个流星,让它从右上向左下移动
,流星滑动的起点和终点都在可视框之外,这样就能营造一种远端飞来的效果,同时实现动画的循环。
预处理器选择
那么这么多的流星个体,我们需要怎么实现呢,你能想到几种方式?
第一种:采用 JS
动态插入 html
第二种:采用 canvas
画布,通过实例化的方式创建粒子
第三种:纯HTML
我当然选择的是最简单的纯HTML
啦,通过编译器的element 语法
快速生成 50个 div
标签(.star*50
)这香,免去了考虑JS
操作的性能问题,以及采用canvas
画布带来的兼容性问题。
从小丞提供的动画来看,每个流星它的划动速度,它的间隔时间,起始的位置甚至是长度都是不一样的,那么对于这么多的元素,难道我们需要给他们一个个编写 CSS 代码吗,答案当然是是的
,当然我们不会采用 css
来开发,我们可以选择CSS预处理器
来开发,采用less
和sass
语法上存在的差异,同时sass
的功能比less
更加的强大。起初我准备采用less
进行产品的开发,但是遇到了这样的问题:
在设置流星长度等属性中,需要采用random
来生成随机数,但是在less
的官方文档中发现,并没有内置random
的 API
在查阅了资料后,发现了由于less
是由JS编写的,所以它天然的支持JS
语法,需要在前面加上~
符号,因此尝试用JS
内置对象Math
来调用生成随机数,结果出现了编译报错的情况,但是在网上的less
转化工具中能正确转化,有点不解…(诡异
)
但是我们可以清晰的在sass
的官方文档上看到random
的身影,这样就没有这么多怪事了,本次的产品确认采用sass
预处理器进行代码编写
产品制作
确定了使用的开发工具,我们就可以正式的来编写代码了
1. 确定流星移动方向
从动画来看,流星的移动方向是一定的,我们可以通过给流星添加一个动画,然后将整个装流星粒子的容器旋转一定的角度,这样流星的移动方向就会是一定方向上的
代码语言:javascript复制.container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 70%;
transform: rotate(-25deg);
}
蓝色方块的纵向方向就是流星移动的方向
确定了流星的移动方向,接下来我们来绘制流星样式
2. 绘制流星样式
流星的效果通过两部分来组成,一个是拖尾,一个是星星
首先拖尾的效果,可以通过渐变来实现
代码语言:javascript复制background: linear-gradient(45deg, currentColor, transparent);
filter: drop-shadow(0 0 6px currentColor);
这里采用了一个currentColor
表示的是当前字体的颜色,这是一个变量,可以直接使用,这样的好处是在改变color
值时拖尾的颜色和阴影的颜色
就会直接改变,不用去单独改变两个值
关于阴影的处理,大多数采用的都是box-shadow
,以致于drop-shadow
很少人知道,它和box-shadow
有着怎样的区别呢?
box-shadow
简单翻译一下“盒阴影”。是css3
中新增的属性,用于增加边框阴影
,让原有的元素变得更多样性,有四个参数,第一个控制水平方向偏移,第二个控制垂直方向偏移,第三个控制模糊度,第四个控制阴影颜色。
drop-shadow
也是用于投影,但是它不局限于矩形区域。
drop-shadow
符合真实世界的投影,非透明的颜色就有投影,透明的就没有投影,而box-shadow
只是盒子投影,即使盒子区域内有透明区域,也会投影
上图(来源网络,侵删)就展示了两者间显著的区别,在很多场景drop-shadow
很实用啊!!
流星头部星星的效果
用双伪元素,绘制两个两头细小的短线,定位到头部,旋转一定角度,实现闪亮星星效果
代码语言:javascript复制.star::before {
transform: rotate(45deg);
}
.star::after {
transform: rotate(-45deg);
}
3. 添加划动动画
对于单个流星的滑动动画非常简单,只需要改变一下位置就可以了,在开始的时候调整transformX
的值将流星移出可视区外
// 给单个流星添加animation以及transform属性
transform: translate3d(220vh, 0, 0);
animation: fall 10s linear infinite;
// 动画声明
@keyframes fall {
to {
transform: translate3d(-30em, 0, 0);
}
}
但是我们需要操作的是全部的粒子,每个粒子都要随机时间,远不止这么简单,继续向下看
4. 循环设定样式
由于每个流星的动画延时,动画时间等属性是在一定范围内的随机数,因此需要通过循环来设定样式
首先需要先在css
中编写一个能返回在一定范围内的随机数函数
@function random_range($min, $max) {
$rand: random();
$random_range: $min floor($rand * (($max - $min) 1));
@return $random_range;
}
这个方法接收两个参数,左边界和有边界,通过scss
中自带的random
方法获取一个随机数,然后乘以两个边界的差值,再加上左边界,这样就能实现需求
对于scss
中编写函数,需要特别注意它的语法
在调用函数的时候通过random_range(0vh, 10000vh)
来获取,在使用的时候可以这样:
--star-length:#{random_range(500em, 750em) / 100};
接下来给每个流星设置随机样式
代码语言:javascript复制@for $i from 1 through $star-count {
&:nth-child(#{$i}) {
--star-length:#{random_range(500em, 750em) / 100};
--top-offset: #{random_range(0vh, 10000vh) / 100};
--fall-duration: #{random_range(6000, 12000s) / 1000};
--fall-delay: #{random_range(0, 10000s) / 1000};
}
}
在.star
的样式代码内,编写一个循环,star-count
是在前面定义的一个长度变量为50
这样循环遍历i
会从0
递增到50
,这样就能通过nth-child(i)
来给50
流星粒子添加样式
scss
循环代码转化后
这样每个流星元素就能有独立的随机的
属于自己的样式,从而实现随机的效果
5. 绑定动画
代码语言:javascript复制animation: fall var(--fall-duration) var(--fall-delay) linear infinite;
将之前个流星粒子添加的animation
样式更改为自己的动画时间和延时时间
6. 添加背景
最后加上一个符合场景的绝美的背景,接下来让我陪你们看一场流星雨吧!
总结
通过这篇文章我们学到了什么呢?
scss
函数scss
循环设置样式box-shadow
和drop-shadow
的区别- 伪元素的妙用
- 拖尾效果的实现
完整 scss 代码
html
代码只需要在body
中输入.container>.star*50
回车即可
/* 设置背景 */
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: url(starBgc.jpg);/* 背景图 */
background-size: cover;
}
.container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 70%;
transform: rotate(-25deg);
}
// 生成范围内随机数函数
@function random_range($min, $max) {
$rand: random();
$random_range: $min floor($rand * (($max - $min) 1));
@return $random_range;
}
.star {
$star-count: 50;
--star-height: 2px;
--star-width: calc(var(--star-length) / 6);
position: absolute;
/* 后面给每个星星都添加一个 */
top: var(--top-offset);
left: 0;
/* 设定每个星星的长宽 */
width: var(--star-length);
height: var(--star-height);
color: #fff;
background: linear-gradient(45deg, currentColor, transparent);
border-radius: 50%;
/* drop-shadow和box-shadow的区别 */
filter: drop-shadow(0 0 6px currentColor);
/*简写xyz */
transform: translate3d(220vh, 0, 0);
animation: fall var(--fall-duration) var(--fall-delay) linear infinite;
// 循环
@for $i from 1 through $star-count {
&:nth-child(#{$i}) {
--star-length:#{random_range(500em, 750em)/100};
--top-offset: #{random_range(0vh, 10000vh) / 100};
--fall-duration: #{random_range(6000, 12000s) / 1000};
--fall-delay: #{random_range(0, 10000s) / 1000};
}
}
// 伪元素制作星星
&::before,
&::after {
position: absolute;
content: '';
top: 0;
left: calc(var(--star-width) / -2);
width: var(--star-width);
height: 100%;
background: linear-gradient(45deg, transparent, currentColor, transparent);
border-radius: inherit;
animation: blink 2s linear infinite;
}
&::before {
transform: rotate(45deg);
}
&::after {
transform: rotate(-45deg);
}
}
@keyframes fall {
to {
transform: translate3d(-30em, 0, 0);
}
}
@keyframes blink {
50% {
opacity: 0.6;
}
}
以上就是本文的全部内容了,希望你能喜欢?,有什么问题可以评论区留言噢~