我用 140 行代码,带你看一场流星雨?

宝剑锋从磨砺出,梅花香自苦寒来。这篇文章主要讲述我用 140 行代码,带你看一场流星雨?相关的知识,希望能为你提供帮助。

我用 140 行代码,带你看一场流星雨?

文章图片

前言在一个夜深人静的晚上,程序员小丞坐在屋顶上,看着屏幕上满屏的 error ,心里拔凉拔凉的,泪水润湿了脸庞,无数个自己提桶跑路的身影充斥在脑海之中,猛然才发现自己还没有桶。此时星空中闪过了漫天的流星,小丞看到此景,心中的 bug 早已化去,留下的是还原此景的豪言壮举!(梦醒了,纯属瞎编)
小丞把脑海中的场景描绘成了动画,开始了他的 show time
我用 140 行代码,带你看一场流星雨?

文章图片

分析动画产品的需求已经明确下来了,很简单实现一个流星雨效果,那么接下来我们需要对动画进行分析,然后一步步的实现最终的效果,第一次看到这个效果的时候感觉很震撼,流星的效果非常的逼真,很炫酷。我们来分析一下过程,从一般的思路来看,我们可以通过 CSS3 动画来实现,绘制一个流星,让它从右上向左下移动,流星滑动的起点和终点都在可视框之外,这样就能营造一种远端飞来的效果,同时实现动画的循环。
我用 140 行代码,带你看一场流星雨?

文章图片

预处理器选择那么这么多的流星个体,我们需要怎么实现呢,你能想到几种方式?
第一种:采用 JS 动态插入 html
第二种:采用 canvas 画布,通过实例化的方式创建粒子
第三种:纯 HTML
我当然选择的是最简单的纯 HTML啦,通过编译器的element 语法快速生成 50 个 div标签(.star*50)这香,免去了考虑JS操作的性能问题,以及采用canvas画布带来的兼容性问题。
从小丞提供的动画来看,每个流星它的划动速度,它的间隔时间,起始的位置甚至是长度都是不一样的,那么对于这么多的元素,难道我们需要给他们一个个编写 CSS 代码吗,答案当然是是的,当然我们不会采用 css 来开发,我们可以选择CSS预处理器来开发,采用 lesssass 语法上存在的差异,同时 sass 的功能比 less 更加的强大。起初我准备采用 less 进行产品的开发,但是遇到了这样的问题:
在设置流星长度等属性中,需要采用 random 来生成随机数,但是在 less 的官方文档中发现,并没有内置 random 的 API
我用 140 行代码,带你看一场流星雨?

文章图片

在查阅了资料后,发现了由于less是由JS编写的,所以它天然的支持JS语法,需要在前面加上~符号,因此尝试用JS内置对象Math来调用生成随机数,结果出现了编译报错的情况,但是在网上的less转化工具中能正确转化,有点不解...(诡异
我用 140 行代码,带你看一场流星雨?

文章图片

但是我们可以清晰的在 sass 的官方文档上看到 random 的身影,这样就没有这么多怪事了,本次的产品确认采用 sass 预处理器进行代码编写
我用 140 行代码,带你看一场流星雨?

文章图片

产品制作确定了使用的开发工具,我们就可以正式的来编写代码了
1. 确定流星移动方向
从动画来看,流星的移动方向是一定的,我们可以通过给流星添加一个动画,然后将整个装流星粒子的容器旋转一定的角度,这样流星的移动方向就会是一定方向上的
.container { position: fixed; top: 0; left: 0; width: 100%; height: 70%; transform: rotate(-25deg); }

我用 140 行代码,带你看一场流星雨?

文章图片

蓝色方块的纵向方向就是流星移动的方向
【我用 140 行代码,带你看一场流星雨?】确定了流星的移动方向,接下来我们来绘制流星样式
2. 绘制流星样式
流星的效果通过两部分来组成,一个是拖尾,一个是星星
首先拖尾的效果,可以通过渐变来实现
background: linear-gradient(45deg, currentColor, transparent); filter: drop-shadow(0 0 6px currentColor);

这里采用了一个currentColor表示的是当前字体的颜色,这是一个变量,可以直接使用,这样的好处是在改变color值时拖尾的颜色和阴影的颜色就会直接改变,不用去单独改变两个值
我用 140 行代码,带你看一场流星雨?

文章图片

关于阴影的处理,大多数采用的都是box-shadow,以致于drop-shadow很少人知道,它和box-shadow有着怎样的区别呢?
box-shadow简单翻译一下“盒阴影”。是css3中新增的属性,用于增加边框阴影,让原有的元素变得更多样性,有四个参数,第一个控制水平方向偏移,第二个控制垂直方向偏移,第三个控制模糊度,第四个控制阴影颜色。
drop-shadow也是用于投影,但是它不局限于矩形区域。
我用 140 行代码,带你看一场流星雨?

文章图片

上图(来源网络,侵删)就展示了两者间显著的区别,在很多场景drop-shadow很实用啊!!
流星头部星星的效果
用双伪元素,绘制两个两头细小的短线,定位到头部,旋转一定角度,实现闪亮星星效果
.star::before { transform: rotate(45deg); } .star::after { transform: rotate(-45deg); }

我用 140 行代码,带你看一场流星雨?

文章图片

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};

接下来给每个流星设置随机样式
@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循环代码转化后
我用 140 行代码,带你看一场流星雨?

文章图片

这样每个流星元素就能有独立的随机的属于自己的样式,从而实现随机的效果
5. 绑定动画
animation: fall var(--fall-duration) var(--fall-delay) linear infinite;

将之前个流星粒子添加的animation样式更改为自己的动画时间和延时时间
我用 140 行代码,带你看一场流星雨?

文章图片

6. 添加背景
最后加上一个符合场景的绝美的背景,接下来让我陪你们看一场流星雨吧!
我用 140 行代码,带你看一场流星雨?

文章图片

总结通过这篇文章我们学到了什么呢?
  1. scss函数
  2. scss循环设置样式
  3. box-shadowdrop-shadow的区别
  4. 伪元素的妙用
  5. 拖尾效果的实现
完整 scss 代码html代码只需要在body中输入.container& gt; .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-length: 6em; --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; } }


    推荐阅读