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

举报
阿童木 发表于 2021/08/18 07:22:09 2021/08/18
【摘要】 📣 大家好,我叫小丞同学,今天走个治愈风,来做一个治愈系的流星雨效果 前言在一个夜深人静的晚上,程序员小丞坐在屋顶上,看着屏幕上满屏的 error ,心里拔凉拔凉的,泪水润湿了脸庞,无数个自己提桶跑路的身影充斥在脑海之中,猛然才发现自己还没有桶。此时星空中闪过了漫天的流星,小丞看到此景,心中的 bug 早已化去,留下的是还原此景的豪言壮举!(梦醒了,纯属瞎编)小丞把脑海中的场景描绘成了动画...

背景图

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

前言

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

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

shotshow1

分析动画

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

image-20210805171627707

预处理器选择

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

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

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

第三种:纯 HTML

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

从小丞提供的动画来看,每个流星它的划动速度它的间隔时间起始的位置甚至是长度都是不一样的,那么对于这么多的元素,难道我们需要给他们一个个编写 CSS 代码吗,答案当然是是的,当然我们不会采用 css 来开发,我们可以选择CSS预处理器来开发,采用 lesssass 语法上存在的差异,同时 sass 的功能比 less 更加的强大。起初我准备采用 less 进行产品的开发,但是遇到了这样的问题:

在设置流星长度等属性中,需要采用 random 来生成随机数,但是在 less 的官方文档中发现,并没有内置 random 的 API

image-20210805170012322

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

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

image-20210805170931749

产品制作

确定了使用的开发工具,我们就可以正式的来编写代码了

1. 确定流星移动方向

从动画来看,流星的移动方向是一定的,我们可以通过给流星添加一个动画,然后将整个装流星粒子的容器旋转一定的角度,这样流星的移动方向就会是一定方向上的

.container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 70%;
    transform: rotate(-25deg);
}

image-20210805172740460

蓝色方块的纵向方向就是流星移动的方向

确定了流星的移动方向,接下来我们来绘制流星样式

2. 绘制流星样式

流星的效果通过两部分来组成,一个是拖尾,一个是星星

首先拖尾的效果,可以通过渐变来实现

background: linear-gradient(45deg, currentColor, transparent);
filter: drop-shadow(0 0 6px currentColor);

这里采用了一个currentColor表示的是当前字体的颜色,这是一个变量,可以直接使用,这样的好处是在改变color值时拖尾的颜色和阴影的颜色就会直接改变,不用去单独改变两个值

image-20210805182856928

关于阴影的处理,大多数采用的都是box-shadow,以致于drop-shadow很少人知道,它和box-shadow有着怎样的区别呢?

box-shadow简单翻译一下“盒阴影”。是css3中新增的属性,用于增加边框阴影,让原有的元素变得更多样性,有四个参数,第一个控制水平方向偏移,第二个控制垂直方向偏移,第三个控制模糊度,第四个控制阴影颜色

drop-shadow也是用于投影,但是它不局限于矩形区域

drop-shadow符合真实世界的投影,非透明的颜色就有投影,透明的就没有投影,而box-shadow只是盒子投影,即使盒子区域内有透明区域,也会投影

image-20210805184307920

上图(来源网络,侵删)就展示了两者间显著的区别,在很多场景drop-shadow很实用啊!!

流星头部星星的效果

用双伪元素,绘制两个两头细小的短线,定位到头部,旋转一定角度,实现闪亮星星效果

.star::before {
  transform: rotate(45deg);
}
.star::after {
  transform: rotate(-45deg);
}

image-20210805185620941

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循环代码转化后

image-20210805192324262

这样每个流星元素就能有独立的随机的属于自己的样式,从而实现随机的效果

5. 绑定动画

animation: fall var(--fall-duration) var(--fall-delay) linear infinite;

将之前个流星粒子添加的animation样式更改为自己的动画时间和延时时间

shotshow4

6. 添加背景

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

shotshow8

总结

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

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

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

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

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。