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

2021-08-16 16:06:08 浏览数 (1)

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

? 大家好,我叫小丞同学,今天走个治愈风,来做一个治愈系的流星雨效果

前言

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

小丞把脑海中的场景描绘成了动画,开始了他的 show time

分析动画

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

预处理器选择

那么这么多的流星个体,我们需要怎么实现呢,你能想到几种方式?

第一种:采用 JS 动态插入 html

第二种:采用 canvas 画布,通过实例化的方式创建粒子

第三种:纯HTML

我当然选择的是最简单的纯HTML啦,通过编译器的element 语法快速生成 50个 div标签(.star*50)这香,免去了考虑JS操作的性能问题,以及采用canvas画布带来的兼容性问题。

从小丞提供的动画来看,每个流星它的划动速度它的间隔时间起始的位置甚至是长度都是不一样的,那么对于这么多的元素,难道我们需要给他们一个个编写 CSS 代码吗,答案当然是是的,当然我们不会采用 css 来开发,我们可以选择CSS预处理器来开发,采用lesssass语法上存在的差异,同时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的值将流星移出可视区外

代码语言:javascript复制
// 给单个流星添加animation以及transform属性
transform: translate3d(220vh, 0, 0);
animation: fall 10s linear infinite;
// 动画声明
@keyframes fall {
    to {
         transform: translate3d(-30em, 0, 0);
    }
}

但是我们需要操作的是全部的粒子,每个粒子都要随机时间,远不止这么简单,继续向下看

4. 循环设定样式

由于每个流星的动画延时,动画时间等属性是在一定范围内的随机数,因此需要通过循环来设定样式

首先需要先在css中编写一个能返回在一定范围内的随机数函数

代码语言:javascript复制
@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)来获取,在使用的时候可以这样:

代码语言:javascript复制
--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. 添加背景

最后加上一个符合场景的绝美的背景,接下来让我陪你们看一场流星雨吧!

总结

通过这篇文章我们学到了什么呢?

  1. scss函数
  2. scss循环设置样式
  3. box-shadowdrop-shadow的区别
  4. 伪元素的妙用
  5. 拖尾效果的实现

完整 scss 代码

html代码只需要在body中输入.container>.star*50回车即可

代码语言:javascript复制
/* 设置背景 */
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;
    }
}

以上就是本文的全部内容了,希望你能喜欢?,有什么问题可以评论区留言噢~

0 人点赞