likes
comments
collection
share

CSS+JS实现 | 简单的萤火虫效果

作者站长头像
站长
· 阅读数 10

前言

夏天到了,又快到了萤火虫出来的季节了,现在的城市很少能看到漫天的萤火虫飞舞了,既然看不到,我们就用代码创造,就当骗自己一下。

代码块

code.juejin.cn/pen/7086277…

代码实现

1.布局

布局很简单,就一个div,其他都靠js生成

<div id="app"></div>

2.闪烁效果

通过box-shadow给元素加阴影,然后使用动画改变阴影的大小和透明度来实现萤火虫的闪烁效果


    /* 萤火虫样式 */
    .round {
        width: 10px;
        height: 10px;
        background-image: radial-gradient(rgba(255, 255, 199, 1), rgba(203, 255, 138, 0.8), rgba(105, 193, 114, 0.8));
        border-radius: 50%;
        animation: shadow 2s infinite;
    }

    /* 闪烁动画 */
    @keyframes shadow {
        0% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0);
        }

        10% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.2);
        }

        20% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.4);
        }

        30% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.6);
        }

        40% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.8);
        }

        50% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 1);
        }

        60% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.8);
        }

        70% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.6);
        }

        80% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.4);
        }

        90% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.2);
        }

        100% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0);
        }
    }

效果如图:

CSS+JS实现 | 简单的萤火虫效果

因为萤火虫的光大小不一致,然后我们实现几个不同的大小的样式,最终CSS样式如下:


 html {
        background-color: black; overflow-x: hidden; overflow-y: hidden; }
#app {
        width: 100%;
        height: 100vh;
    }

    .round {
        width: 10px;
        height: 10px;
        background-image: radial-gradient(rgba(255, 255, 199, 1), rgba(203, 255, 138, 0.8), rgba(105, 193, 114, 0.8));
        border-radius: 50%;
        animation: shadow 2s infinite;
        transition-property: left, top;
        transition-duration: 1s, 1s;
        transition-timing-function: ease,ease;
    }

    .round2 {
        width: 8px;
        height: 8px;
        background-image: radial-gradient(rgba(255, 255, 199, 1), rgba(203, 255, 138, 0.8), rgba(105, 193, 114, 0.8));
        border-radius: 50%;
        animation: shadow2 2s infinite;
        transition-property: left, top;
        transition-duration: 1s, 1s;
        transition-timing-function: ease,ease;
    }

    .round3 {
        width: 5px;
        height: 5px;
        background-image: radial-gradient(rgba(255, 255, 199, 1), rgba(203, 255, 138, 0.8), rgba(105, 193, 114, 0.8));
        border-radius: 50%;
        animation: shadow2 2s infinite;
        transition-property: left, top;
        transition-duration: 1s, 1s;
        transition-timing-function: ease,ease;
    }

    @keyframes shadow {
        0% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0);
        }

        10% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.2);
        }

        20% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.4);
        }

        30% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.6);
        }

        40% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.8);
        }

        50% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 1);
        }

        60% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.8);
        }

        70% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.6);
        }

        80% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.4);
        }

        90% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.2);
        }

        100% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0);
        }
    }


    @keyframes shadow2 {
        0% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0);
        }

        10% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.2);
        }

        20% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.4);
        }

        30% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.6);
        }

        40% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.8);
        }

        50% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 1);
        }

        60% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.8);
        }

        70% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.6);
        }

        80% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.4);
        }

        90% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0.2);
        }

        100% {

            box-shadow: 0px 0px 5px 5px rgba(105, 193, 114, 0);
        }
    }

3.动态生成萤火虫

生成元素比较简单,直接只用js的document.createElement方法即可实现,随机分配不同大小的class给元素,然后随机指定坐标生成,给父元素添加子节点,并添加到一个数组中方便后面批量运动

    let arr = [];
    let app = document.getElementById("app")
    let clientW = app.offsetWidth;
    let clientH = app.offsetHeight;
    function addItem() {
        let div = document.createElement("div");
        const cName = (Math.floor(Math.random() * 3) + 1);
        div.setAttribute("class", "round" + (cName == 0 ? '' : cName));
        div.style.position = 'absolute';
        div.style.left = Math.floor(Math.random() * clientW) + "px";
        div.style.top = Math.floor(Math.random() * clientH) + "px";
        app.appendChild(div);
        arr.push(div);
    }

萤火虫肯定不是静止不动,会飞舞,所以我们要给元素添加移动的动画,实现思路是动态修改萤火虫元素lef top 属性的值,当然这个数值是随机,且不能为正数,要有正负数才行,不然只会往一个方向移动

    function move() {
        //防止页面卡顿,如果有1000个元素就停止生成
        if(arr.length > 1000) {
            clearInterval(window.addTask);
        }
        if (arr.length > 0) {
            arr.forEach(div => {
                let speed = Math.floor(Math.random() * clientW/20) + 10;//定义总体速度
                let left = div.offsetLeft;
                let top = div.offsetTop;
                //随机设置在x和y方向的速度
                let theta = Math.floor(Math.random() * speed) + 10 * Math.PI * Math.random();
                let speedX = Math.floor(speed * Math.cos(theta));
                let speedY = Math.floor(speed * Math.sin(theta));
                left += speedX;
                top += speedY;
                div.style.left = left + "px"
                div.style.top = top + "px"
            })
        }
    }

最后只要启动两个定时器即可运行

window.addTask = setInterval(addItem, 200)
setInterval(move, 500)

CSS+JS实现 | 简单的萤火虫效果

结语