Getting web front-end to combat: CSS, JS achieve romantic meteor shower animation

1, the effect of FIG.

Getting web front-end to combat: CSS, JS achieve romantic meteor shower animation

2, source

HTML

< body > 
    < div  class = “container” > 
        < div  id = “mask” > </ div > 
        < div  id = “sky” > </ div > 
        < div  id = “moon” > </ div > 
        < div  id = “stars” > </ div > 
        < div  class = “cloud cloud-1” ></ div > 
        <div  class = “cloud cloud-2” > </ div > 
        < div  class = “cloud cloud-3” > </ div > 
    </ div > 
</ body >
web前端开发学习Q-q-u-n: 731771211,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(详细的前端项目实战教学视频)

CSS

/*  -  -  -  -  -  - 重启 -  -  -  -  -  -  */

 * {
     保证金:0 ;
     填充:0 ;
 }

 html,
  body {
      width:100% ;
     最小宽度:1000px ;
     身高:100% ;
     最小高度:400px ;
     溢出:隐藏;
 }

 / * ------------画布------------ * / 
 .container {
      position:relative;
     身高:100% ;
 }
 / *遮罩层* /

 #mask {
      position:absolute;
     宽度:100% ;
     身高:100% ;
     background:rgba(0,0,0,.8);
     z-index:900 ;
 }
 / *天空背景* /

 #sky {
      width:100% ;
     身高:100% ;
     background:线性渐变(rgba(0,150,255,1),rgba(0,150,255,.8),rgba(0,150,255,.5));
 }
 / *月亮* /

 #moon {
      position:absolute;
     上:50px ;
     右:200px ;
     宽度:120px ;
     身高:120px ;
     背景:rgba(251,255,25,0.938);
     border-radius:50% ;
     box-shadow:0  0  20px  rgba(251,255,25,0.5);
     z-index:9999 ;
 }
 / *闪烁星星* /

 .blink {
      position:absolute;
     background:rgb(255,255,255);
     border-radius:50% ;
     box-shadow:0  0  5px  rgb(255,255,255);
     不透明度:0 ;
     z-index:10000 ;
 }
 / *流星* /

 .star {
      position:absolute;
     不透明度:0 ;
     z-index:10000 ;
 }

 .star :: after {
      content:“” ;
     显示:块;
     边界:坚固;
     border-width:2px  0  2px  80px ;
     / *流星随长度逐渐缩小* / 
     border-color:透明透明透明rgba(255,255,255,1);
     border-radius:2px  0  0  2px ;
     transform:rotate(-45deg);
     transform-origin:0  0  0 ;
     盒子阴影:0  0  20px  rgba(255,255,255,.3);
 }
 / *云* /

 .cloud {
      position:absolute;
     宽度:100% ;
     身高:100px ;
 }

 .cloud-1 {
      bottom: - 100px ;
     z-index:1000 ;
     不透明度:1 ;
     变换:规模(1.5);
     -webkit-transform:scale(1.5);
     -moz-transform:scale(1.5);
     -ms-transform:scale(1.5);
     -o-transform:scale(1.5);
 }

 .cloud-2 {
      left: - 100px ;
     底部: - 50px ;
     z-index:999 ;
     不透明度:。5 ;
     变换:旋转(7deg);
     -webkit-transform:rotate(7deg);
     -moz-transform:rotate(7deg);
     -ms-transform:rotate(7deg);
     -o-transform:rotate(7deg);
 }

 .cloud-3 {
      left:120px ;
     底部: - 50px ;
     z-index:999 ;
     不透明度:。1 ;
     transform:rotate(-10deg);
     -webkit-transform:rotate(-10deg);
     -moz-transform:rotate(-10deg);
     -ms-transform:rotate(-10deg);
     -o-transform:rotate(-10deg);
 }

 .circle {
      position:absolute;
     border-radius:50% ;
     背景:#fff ;
 }

 .circle-1 {
      width:100px ;
     身高:100px ;
     上: - 50px ;
     左:10px ;
 }

 .circle-2 {
      width:150px ;
     身高:150px ;
     上: - 50px ;
     左:30px ;
 }

 .circle-3 {
      width:300px ;
     身高:300px ;
     上: - 100px ;
     左:80px ;
 }

 .circle-4 {
      width:200px ;
     身高:200px ;
     上: - 60px ;
     左:300px ;
 }

 .circle-5 {
      width:80px ;
     身高:80px ;
     上: - 30px ;
     左:450px ;
 }

 .circle-6 {
      width:200px ;
     身高:200px ;
     上: - 50px ;
     左:500px ;
 }

 .circle-7 {
      width:100px ;
     身高:100px ;
     上: - 10px ;
     左:650px ;
 }

 .circle-8 {
      width:50px ;
     身高:50px ;
     上:30px ;
     左:730px ;
 }

 .circle-9 {
      width:100px ;
     身高:100px ;
     上:30px ;
     左:750px ;
 }

 .circle-10 {
      width:150px ;
     身高:150px ;
     上:10px ;
     左:800px ;
 }

 .circle-11 {
      width:150px ;
     身高:150px ;
     上: - 30px ;
     左:850px ;
 }

 .circle-12 {
      width:250px ;
     身高:250px ;
     上: - 50px ;
     左:900px ;
 }

 .circle-13 {
      width:200px ;
     身高:200px ;
     上: - 40px ;
     左:1000px ;
 }

 .circle-14 {
      width:300px ;
     身高:300px ;
     上: - 70px ;
     左:1100px ;
 }

JS

//流星动画 
setInterval(function() {
     const obj = addChild(“#sky”,“div”,2,“star”);

    for(let i = 0 ; i <obj.children.length; i ++){
         const top = -50 + Math .random()* 200 + “px”,
            left = 200 + Math .random()* 1200 + “px”,
            scale = 0.3 + Math .random()* 0.5 ;
        const timer = 1000 + Math .random()* 1000 ;

        obj.children [i] .style.top = top;
        obj.children [i] .style.left = left;
        obj.children [i] .style.transform = `scale($ {scale})` ;

        requestAnimation({
            ele:obj.children [i],
             attr:[ “top”,“left”,“opacity” ],
             值:[ 150,-150,.8 ],
             time:timer,
             flag:false,
             fn:function() {
                requestAnimation({
                    ELE:obj.children [I],
                     ATTR:“顶”,“左”,“不透明” ],
                     值:[ 150,-150,0 ],
                     时间:定时器,
                     标志:假,
                     FN:() => {
                        obj.parent.removeChild(obj.children [I]);
                    }
                })
            }
        });
    }

},1000);

//闪烁星星动画 
setInterval(function() {
     const obj = addChild(“#stars”,“div”,2,“blink”);

    for(let i = 0 ; i <obj.children.length; i ++){
         const top = -50 + Math .random()* 500 + “px”,
            left = 200 + Math .random()* 1200 + “px”,
            round = 1 + Math .random()* 2 + “px” ;
        const timer = 1000 + Math .random()* 4000 ;

        obj.children [i] .style.top = top;
        obj.children [i] .style.left = left;
        obj.children [i] .style.width = round;
        obj.children [i] .style.height = round;

        requestAnimation({
            ele:obj.children [i],
             attr:“opacity”,
             值:.5,
             time:timer,
             flag:false,
             fn:function() {
                requestAnimation({
                    ele:obj.children [i],
                     attr:“opacity”,
                     value:0,
                     time:timer,
                     flag:false,
                     fn:function() {
                        obj.parent.removeChild(obj.children [I]);
                    }
                });
            }
        });
    }

},1000);

//月亮移动
requestAnimation({
    ele:“#moon”,
     attr:“right”,
     值:1200,
     时间:10000000,
});

//添加云
const clouds = addChild(“。cloud”,“div”,14,“circle”,true);
for(let i = 0 ; i <clouds.children.length; i ++){
     for(let j = 0 ; j <clouds.children [i] .length;){
        clouds.children [i] [j] .classList.add(`circle- $ {++ j} `);
    }
}
//云动画

let flag = 1 ;
的setInterval(
    功能() {
         const clouds = document .querySelectorAll(“。cloud”);
        const left = Math .random()* 5 ;
        bottom = Math .random()* 5 ;

        let timer = 0 ;
        for(let i = 0 ; i <clouds.length; i ++){
            requestAnimation({
                ele:clouds [i],
                 attr:[ “left”,“bottom” ],
                 value:flag%2?[-left,-bottom]:[left,bottom],
                 time:timer + = 500,
                 flag:false,
                 fn:function() {
                    requestAnimation({
                        ele:clouds [i],
                         attr:[ “left”,“bottom” ],
                         value:flag%2?[left,bottom]:[ -  left,-bottom],
                         time:timer,
                         flag:false
                    })
                }
            });
        }

        标志++;
    },2000)

Packaging method

// -------------------------------------------动画---- ----------------------------------------------- 
//运动动画,调用Tween.js 
// ele:dom | 班级| id | 标签节点| 类名| id名| 标签名,只支持选择一个节点,类类名以及标签名只能选择页面中第一个
// attr:属性属性名
//值:目标值目标值
//时间:持续时间持续时间
//补间:定时function函数方程
// flag:Boolean判断是按值移动还是按位置移动,默认按位置移动
// fn:callback回调函数
//增加返回值:将内部参数对象返回,可以通过设置返回对象的属性stop为true打断动画
函数 requestAnimation(obj) {
     // -------------------------------------参数设置--------------------------------------------- 
    //默认属性
    const参数= {
         ele:null,
         attr:null,
         value:null,
         time:1000,
         tween:“linear”,
         flag:true,
         stop:false,
         fn:“”
    }

    //合并传入属性
    Object .assign(parameter,obj); //覆盖重名属性

    // -------------------------------------动画设置--------- ------------------------------------ 
    //创建运动方程初始参数,方便复用
    let start = 0 ; //用于保存初始时间戳
    let target =(typeof parameter.ele === “string”?document .querySelector(parameter.ele):parameter.ele),//目标节点 
        attr = parameter.attr,//目标属性 
        beginAttr = parseFloat(getComputedStyle(target)[attr]),// attr起始值 
        value = parameter.value,//运动目标值 
        count = value  -  beginAttr,//实际运动值 
        time = parameter.time,//运动持续时间,
        tween = parameter.tween,//运动函数
        flag = parameter.flag,
        callback = parameter.fn,//回调函数 
        curVal = 0 ; //运动当前值

    //判断传入函数是否为数组,多段运动 
    (function() {
         if(attr instanceof  Array){
            beginAttr = [];
            count = [];
            对于(让我的 ATTR){
                 常量 VAL = parseFloat(的getComputedStyle(目标)[I]);
                beginAttr.push(VAL);
                count.push(value  -  val);
            }
        }
        if(value instanceof  Array){
             for(let i in value){
                count [i] = value [i]  -  beginAttr [i];
            }
        }
    })();

    //运动函数
    功能 动画(时间戳) {
         如果(parameter.stop)返回 ; //打断
        //存储初始时间戳
        if(!start)start = timestamp;
        //已运动时间
        让 t =时间戳 - 开始;
        //判断多段运动
        if(beginAttr instanceof  Array){
             // const len = beginAttr.length //存数组长度,复用

            //多段运动第1类 - 多属性,同目标,同时间/不同时间
            if(typeof count === “number”){ //同目标
                //同时间
                if(typeof time === “number”){
                     if(t> time)t = time; //判断是否超出目标值

                    //循环attr,分别赋值
                    为(let i in beginAttr){
                         if(flag)curVal = Tween [tween](t,beginAttr [i],count,time); //调用Tween,返回当前属性值,此时计算方法为移动到
                        写入位置else curVal = Tween [tween](t,beginAttr [i],count + beginAttr [i],time); //调用Tween,返回当前属性值,此时计算方法为移动了
                        写入距离if(attr [i] === “opacity”)target.style [attr [i]] = curVal; //给属性赋值
                        else target.style [attr [i]] = curVal + “px” ; //给属性赋值

                        if(t <time)requestAnimationFrame(animate); //判断是否运动完
                        其他回调&& callback(); //调用回调函数
                    }
                    回归 ;
                }

                //不同时间
                if(time instanceof  Array){
                     //循环时间,attr,分别赋值
                    为(让我在 beginAttr中){
                         //错误判断
                        if(!time [i] && time [i]!== 0){
                             throw  new  Error(
                                 “输入时间的长度不等于属性的长度”);
                        }

                        //判断是否已经完成动画,完成则跳过此次循环
                        if(parseFloat(getComputedStyle(target)[attr [i]])===(typeof value === “number”?value:value [i]) )
                             继续 ;
                        // t =时间戳 - 开始; //每次循环初始化t 
                        if(t> time [i])t = time [i]; //判断是否超出目标值

                        if(flag || attr [i] === “opacity”)curVal = Tween [tween](t,beginAttr [i],count,i); //调用Tween,返回当前属性值,此时计算方法为移动到
                        写入位置else curVal = Tween [tween](t,beginAttr [i],count + beginAttr [i],i); //调用Tween,返回当前属性值,此时计算方法为移动了
                        写入距离if(attr [i] === “opacity”)target.style [attr [i]] = curVal; //给属性赋值
                        else target.style [attr [i]] = curVal + “px” ; //给属性赋值
                    }

                    if(t < Math .max(... time))requestAnimationFrame(animate); //判断函数是否运动完
                    其他回调&& callback(); //如果已经执行完时间最长的动画,则调查回调函数
                    return ;
                }
            }

            //多段运动第2类 - 多属性,不同目标,同时间/不同时间
            if(count instanceof  Array){
                 //同时间
                if(typeof time === “number”){

                    if(t> time)t = time; //判断是否超出目标值

                    for(let i in beginAttr){ //循环attr,count,分别赋值
                        //错误判断
                        if(!count [i] && count [i]!== 0){
                             throw  new  Error(
                                 “输入值的长度不是等于属性的长度“);
                        }

                        if(flag || attr [i] === “opacity”)curVal = Tween [tween](t,beginAttr [i],count [i],time); //调用Tween,返回当前属性值,此时计算方法为移动到
                        写入位置else curVal = Tween [tween](t,beginAttr [i],count [i] + beginAttr [i],time); //调用Tween,返回当前属性值,此时计算方法为移动了
                        写入距离if(attr [i] === “opacity”)target.style [attr [i]] = curVal; //给属性赋值
                        else target.style [attr [i]] = curVal + “px” ; //给属性赋值
                    }

                    if(t <time)requestAnimationFrame(animate); //判断函数是否运动完
                    其他回调&& callback(); //如果已经执行完时间最长的动画,则调查回调函数
                    return ;
                }

                //不同时间
                if(time instanceof  Array){
                     for(let i in beginAttr){
                         //错误判断
                        if(!time [i] && time [i]!== 0){
                             throw  new  Error(
                                 “输入时间的长度)不等于属性的长度“);
                        }

                        //判断是否已经完成动画,完成则跳过此次循环
                        if(parseFloat(getComputedStyle(target)[attr [i]])===(typeof value === “number”?value:value [i]) )
                             继续 ;

                        if(t> time [i])t = time [i]; //判断是否超出目标值

                        //错误判断
                        if(!count [i] && count [i]!== 0){
                             throw  new  Error(
                                 “输入值的长度不等于属性的长度”);
                        }

                        if(flag || attr [i] === “opacity”)curVal = Tween [tween](t,beginAttr [i],count [i],time [i]); //调用Tween,返回当前属性值,此时计算方法为移动到
                        写入位置其他 curVal = Tween [tween](t,beginAttr [i],count [i] + beginAttr [i],time [i]) ; //调用Tween,返回当前属性值,此时计算方法为移动了
                        写入距离if(attr [i] === “opacity”)target.style [attr [i]] = curVal;
                        否则 target.style [attr [i]] = curVal + “px” ;
                    }

                    if(t < Math .max(... time))requestAnimationFrame(animate);
                    else callback && callback();
                    回归 ;
                }
            }

        }

        //单运动模式
        if(t> time)t = time;
        if(flag || attr === “opacity”)curVal = Tween [tween](t,beginAttr,count,time); //调用Tween,返回当前属性值,此时计算方法为移动到
        写入位置else curVal = Tween [tween](t,beginAttr [i],count + beginAttr,time); //调用Tween,返回当前属性值,此时计算方法为移动了
        写入距离if(attr === “opacity”)target.style [attr] = curVal;
        否则 target.style [attr] = curVal + “px” ;

        if(t <time)requestAnimationFrame(animate);
        else callback && callback();

    }

    requestAnimationFrame(动画);
    返回参数; //返回对象,供打断或其他用途
}
//Tween.js 
/ *
 * t:时间已过时间
 * b:开始起始值
 * c:计算总的运动值
 * d:持续时间持续时间
 *
 *曲线方程
 *
 * http://www.cnblogs.com/bluedream2009/archive/2010/06/19/1760909.html
 * * /

让 Tween = {
     linear:function(t,b,c,d) { //匀速
        返回 c * t / d + b;
    },
    easeIn:function(t,b,c,d) { //加速曲线
        return c *(t / = d)* t + b;
    },
    easeOut:function(t,b,c,d) { //减速曲线
        return -c *(t / = d)*(t  - 2)+ b;
    },
    easeBoth:function(t,b,c,d) { //加速减速曲线
        if((t / = d / 2)< 1){
             return c / 2 * t * t + b;
        }
        return -c / 2 *(( -  t)*(t  - 2) - 1)+ b;
    },
    easeInStrong:function(t,b,c,d) { //加加速曲线
        return c *(t / = d)* t * t * t + b;
    },
    easeOutStrong:function(t,b,c,d) { //减减曲线
        返回 -c *((t = t / d  - 1)* t * t * t  - 1)+ b;
    },
    easeBothStrong:function(t,b,c,d) { //加速减减速线
        如果((t / = d / 2)< 1){
             return c / 2 * t * t * t * t + b;
        }
        return -c / 2 *((t  -  = 2)* t * t * t  - 2)+ b;
    },
    elasticIn:function(t,b,c,d,a,p) { //正弦衰减曲线(弹动渐入)
        if(t === 0){
             return b;
        }
        if((t / = d)== 1){
             return b + c;
        }
        if(!p){
            p = d * 0.3 ;
        }
        if(!a || a < Math .abs(c)){
            a = c;
            var s = p / 4 ;
        } else {
             var s = p /(2 * Math .PI)* Math .asin(c / a);
        }
        返回 - (A * 数学 .pow(2,10 *(T - = 1))* 数学 .sin((T * d - S)*(2 * 数学 .PI)/ P))+ B;
    },
    elasticOut:function(t,b,c,d,a,p) { //正弦增强曲线(弹动渐出)
        if(t === 0){
             return b;
        }
        if((t / = d)== 1){
             return b + c;
        }
        if(!p){
            p = d * 0.3 ;
        }
        if(!a || a < Math .abs(c)){
            a = c;
            var s = p / 4 ;
        } else {
             var s = p /(2 * Math .PI)* Math .asin(c / a);
        }
        返回 a * Math .pow(2,-10 * t)* Math .sin((t * d  -  s)*(2 * Math .PI)/ p)+ c + b;
    },
    elasticBoth:function(t,b,c,d,a,p) {
         if(t === 0){
             return b;
        }
        if((t / = d / 2)== 2){
             return b + c;
        }
        if(!p){
            p = d *(0.3 * 1.5);
        }
        if(!a || a < Math .abs(c)){
            a = c;
            var s = p / 4 ;
        } else {
             var s = p /(2 * Math .PI)* Math .asin(c / a);
        }
        如果(T < 1){
             返回 -0.5 *(A * 数学 .pow(2,10 *(T - = 1))*
                 数学 .sin((T * d - S)*(2 * 数学 .PI)/ p))+ b;
        }
        返回 a * Math .pow(2,-10 *(t  -  = 1))*
             Math .sin((t * d  -  s)*(2 * Math .PI)/ p)* 0.5 + c + b;
    },
    backIn:function(t,b,c,d,s) { //回退加速(回退渐入)
        if(typeof s == 'undefined'){
            s = 1.70158 ;
        }
        return c *(t / = d)* t *((s + 1)* t  -  s)+ b;
    },
    backOut:function(t,b,c,d,s) {
         if(typeof s == 'undefined'){
            s = 3.70158 ; //回缩的距离
        }
        return c *((t = t / d  - 1)* t *((s + 1)* t + s)+ 1)+ b;
    },
    backBoth:function(t,b,c,d,s) {
         if(typeof s == 'undefined'){
            s = 1.70158 ;
        }
        if((t / = d / 2)< 1){
             return c / 2 *(t * t *(((s * =(1.525))+ 1)* t  -  s))+ b;
        }
        return c / 2 *((t  -  = 2)* t *(((s * =(1.525))+ 1)* t + s)+ 2)+ b;
    },
    bounceIn:function(t,b,c,d) { //弹球渐出)
        返回 c  -  Tween [ 'bounceOut' ](d  -  t,0,c,d)+ b;
    },
    bounceOut:function(t,b,c,d) {
         if((t / = d)<(1 / 2.75)){
             return c *(7.5625 * t * t)+ b;
        } else  if(t <(2 / 2.75)){
             return c *(7.5625 *(t  -  =(1.5 / 2.75))* t + 0.75)+ b;
        } else  if(t <(2.5 / 2.75)){
             return c *(7.5625 *(t  -  =(2.25 / 2.75))* t + 0.9375)+ b;
        }
        return c *(7.5625 *(t  -  =(2.625 / 2.75))* t + 0.984375)+ b;
    },
    bounceBoth:函数(T,B,C,d) {
         如果(T <d / 2){
             返回吐温[ 'bounceIn' ](T * 2,0,C,d)* 0.5 + B;
        }
        return Tween [ 'bounceOut' ](t * 2 -  d,0,c,d)* 0.5 + c * 0.5 + b;
    }
}

// ------------------------------------------- DOM操作--- ------------------------------------------------ 
//添加节点
// ele:父节点,支持输入变量,id值,类值,标签值。除变量外,其余值必须为字符串
//节点:添加的标签名,值为字符串
// n:节点添加个数
// className:节点绑定的类名,值为字符串,多个类名用空格隔开
//布尔:是否选中所有目标父节点。可选参数,不输入则判定为false,则只匹配选中的第一个节点
函数 addChild(ele,node,n,className,boolean) {
     //获取节点
    let parent = null ;

    if(typeof ele!== “string”)parent = ele;
    else  if(ele [ 0 ] === “#”)parent = document .getElementById(ele.slice(1));
    else  if(ele [ 0 ] === “。”){
         if(boolean === false)parent = document .getElementsByClassName(ele.slice(1))[ 0 ];
        else parent = document .getElementsByClassName(ele.slice(1));
    } else {
         if(boolean === false)parent = docuemnt.getElementsByTagName(ele)[ 0 ];
        else parent = document .getElementsByTagNameNS(ele);
    }

    //声明用于存储父节点及子节点的对象
    const obj = {
         “parent”:parent,
         “children”:[]
    };

    //添加节点
    if(boolean){
         for(let i = 0 ; i <parent.length; i ++){
             //创建容器碎片
            const fragment = document .createDocumentFragment();
            //保存子节点,用于返回值
            obj.children [i] = [];

            for(let j = 0 ; j <n; j ++){
                 const target = document .createElement(node);
                target.className = className;
                fragment.appendChild(目标);
                //添加子节点到数组,用于返回值
                obj.children [i] [j] =目标;
            }

            父[I] .appendChild(片段)
        }
    } else {
         //创建碎片容器
        const fragment = document .createDocumentFragment();

        for(let i = 0 ; i <n; i ++){
             const target = document .createElement(node);
            target.className = className;
            fragment.appendChild(目标);
            //添加子节点,用于返回值
            obj.children [i] =目标;
        }
        //将碎片容器一次性添加到父节点
        parent.appendChild(片段);
    }

    //返回参数,供动画函数调用
    return obj;
}

3, case analysis

HTML

Since the node number, and I want to try to do a little realistic interesting, add a node back to a random location. Therefore, the output node is controlled by JS, HTML here write only a few elements of the parent box, with the corresponding ID and class name of the class, the structure is relatively simple.

CSS

Difficulties CSS style part is meteor with clouds and Videos circle, then the three-dimensional effect clouds stack.

First talk about the meteor style:

#sky  .star {
      position:absolute;
     不透明度:0 ;
     z-index:10000 ;
 }

 .star :: after {
      content:“” ;
     显示:块;
     边界:坚固;
     border-width:2px  0  2px  80px ;
     / *流星随长度逐渐缩小* / 
     border-color:透明透明透明rgba(255,255,255,1);
     border-radius:2px  0  0  2px ;
     transform:rotate(-45deg);
     transform-origin:0  0  0 ;
     盒子阴影:0  0  20px  rgba(255,255,255,.3);
 }
web前端开发学习Q-q-u-n: 784783012 ,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(详细的前端项目实战教学视频)

First extract the common style, add positioning attributes;

Then, after adding star meteor through the pseudo-classes, with the characteristic painted border:

1) Draw Model: border-width of the order of four sides of top, right, bottom, left, border-color order in the same way also for the four sides of top, right, bottom, left. After such correspondence, you can see the 2px border-width is the width of the border-color meteor, meteor 80px length, and the pixel 0 is the tail meteor thus forming a. 2px wide head, tail 0 pixels, the length of meteor model 80px;

2) somewhat realistic: by border-radius? Meteor increased to a rounded head, to make it look more realistic final angle of rotation by a roteta, it looks like fall down;

3) increasing the flash: add a bit to the meteor by halo shadow box, it appears to have the effect of flashing;

In three steps above, a meteor to draw better.

Then the painting goes:

Because the cloud long code, the method here is not posted by nothing more than a one round, are superimposed cover, a finish form clouds.
After completion of a cloud, a Copy, then through a plurality of clouds rotate, opacity, left positioning, to make a superimposed perspective fade effect;

JS

JS section to illustrate meteor

setInterval(function() {
     const obj = addChild(“#sky”,“div”,2,“star”); //插入流星

    for(let i = 0 ; i <obj.children.length; i ++){
         //随机位置
        const top = -50 + Math .random()* 200 + “px”,
            left = 200 + Math .random()* 1200 + “px”,
            scale = 0.3 + Math .random()* 0.5 ;
        const timer = 1000 + Math .random()* 1000 ;

        obj.children [i] .style.top = top;
        obj.children [i] .style.left = left;
        obj.children [i] .style.transform = `scale($ {scale})` ;

        //添加动画
        requestAnimation({
            ele:obj.children [i],
             attr:[ “top”,“left”,“opacity” ],
             值:[ 150,-150,.8 ],
             time:timer,
             flag:false,
             fn:function() {
                requestAnimation({
                    ELE:obj.children [I],
                     ATTR:“顶”,“左”,“不透明” ],
                     值:[ 150,-150,0 ],
                     时间:定时器,
                     标志:假,
                     FN:() => {
                        obj.parent.removeChild(obj.children [I]); //动画结束删除节点
                    }
                })
            }
        });
    }

},1000);
web前端开发学习Q-q-u-n: 731771211,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(详细的前端项目实战教学视频)

This side uses two methods of my own package, based on a requestAnimationFrame of requestAnimation, based on the appendChild addChild.

In order to achieve the position of the stars of the random effect, by continuing to insert and delete setInterval timer Meteor:

First of all, every time you add a page to two meteors, but less than the interval timer shooting star animation time, so we can guarantee the number of pages in the meteor is not a fixed value, but it is certainly greater than 2. Otherwise, a two meteors bit lonely;

Then, through the circulation (of formula can also be used, for the, for all rows - simplest) to each new page is added to a meteor random location (top, left), a random size (size ), random animation execution time (timer);

Finally, in a loop, to each new page added to the meteor add animation, and delete nodes after performing animation through the callback function. Here we must note that, to the animation divided into two phases (appear and disappear, mainly opacity control). Also I deal with here, every meteors are moving the same distance 300px, I think this distance can also be controlled by a random number, but I made a lazy, do not do.

4, small problems

Currently there are problems I found two:

One problem page DOM manipulation itself constantly add and remove nodes, resulting in constantly. And redraw reflux, a waste of performance;

Second, because the problem itself requestAnimationFrame timer constantly adding nodes, while requestAnimationFrame feature - when leaving the current page to browse other pages, the animation will be suspended. This creates a problem node has been added, but the animation in full-stop execution so that there is no return to this page the next time, it will explode boom !!! animation, you will see a picture card, many tadpoles collective action to find her mother.

5 Conclusion

Although this case is very simple little difficulty from the point of view, but it can develop very high - such as a table of white ah, send Acacia, playing a romantic ah, etc., can also be achieved using pure CSS.

Guess you like

Origin blog.51cto.com/14592820/2447317