Maison  >  Article  >  interface Web  >  Comment obtenir un effet d'animation romantique de pluie de météores avec CSS+JS ? (exemple de code)

Comment obtenir un effet d'animation romantique de pluie de météores avec CSS+JS ? (exemple de code)

青灯夜游
青灯夜游avant
2018-11-10 17:16:582877parcourir

Le contenu de cet article est de présenter comment réaliser l'effet d'animation romantique d'une pluie de météores avec CSS+JS ? (exemple de code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.

Jetons d'abord un coup d'œil aux rendus :

Comment obtenir un effet danimation romantique de pluie de météores avec CSS+JS ? (exemple de code)

Faisons ensuite Voyez comment ça marche :

Code HTML :

 
     
          p > 
          p > 
          p > 
          p > 
         p > 
        <p>  p > 
          p > 
     p > 
 body ></p>

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

Code JS :

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

    for(let i = 0 ; i <obj.children.length> {
                        obj.parent.removeChild(obj.children [I]);
                    }
                })
            }
        });
    }

},1000);

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

    for(let i = 0 ; i <obj.children.length requestanimation const for let><p><strong>Méthode d'encapsulation : </strong></p>
<pre class="brush:php;toolbar:false">// -------------------------------------------动画---- ----------------------------------------------- 
//运动动画,调用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> 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  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> 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  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><p><span style="font-size: 20px;"><strong>Analyse de cas</strong> </span></p>
<p><strong>HTML</strong></p>
<p>Comme il y a de nombreux nœuds et que je voulais le rendre aussi réaliste et intéressant que possible, j'ai également ajouté des positions aléatoires au nœuds. Par conséquent, la sortie des nœuds est contrôlée par JS. Du côté HTML, seules quelques zones d'éléments parents sont écrites, ainsi que les noms d'ID et de classe correspondants, et la structure est relativement simple. </p>
<p><strong>CSS</strong></p>
<p>La partie difficile de la partie CSS est le style du météore et le dessin des nuages ​​avec des cercles, puis l'empilage des nuages ​​pour créer un effet tridimensionnel. effet. </p>
<p>Parlons d'abord du style du météore : </p>
<pre class="brush:php;toolbar:false">#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);
 }

Extrayez d'abord le style public et ajoutez l'attribut de positionnement ;

Ajoutez ensuite le météore via le pseudo post -class après l'étoile, utilisez le dessin des caractéristiques de la bordure :

1) Dessin du modèle : l'ordre de la largeur de la bordure est en haut, à droite, en bas, à gauche. De même, l'ordre de la couleur de la bordure est en haut, à droite, en haut. en bas, à gauche. De cette façon, après une correspondance biunivoque entre la largeur de la bordure et la couleur de la bordure, vous pouvez voir que 2px est la largeur du météore, 80px est la longueur du météore et le météore de 0 pixel est la queue, formant ainsi un. Modèle météore avec une tête de 2px de large, une queue de 0px et une longueur de 80px

2) Légèrement réaliste : par rayon de bordure ? Ajoutez un coin arrondi à la tête du météore pour lui donner un aspect plus réaliste. Enfin, faites-le pivoter selon un angle pour donner l'impression qu'il tombe

3) Ajoutez de l'éclat : ajoutez une ombre de boîte à ; le météore Ajoutez un petit halo pour le rendre étincelant ;

Après les 3 étapes ci-dessus, une étoile filante est prête.

Ensuite, dessinez des nuages :

Le code du nuage étant relativement long, je ne le publierai pas ici. La méthode consiste simplement à superposer et à couvrir les cercles un par un pour compléter la forme de. un nuage.
Après avoir terminé un calque de nuage, copiez-en un, puis plusieurs calques de nuage utilisent la rotation, l'opacité, le positionnement à gauche, etc. pour créer un effet tridimensionnel de fondu et de chevauchement

JS

La partie JS utilise Meteor comme exemple

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

    for(let i = 0 ; i <obj.children.length> {
                        obj.parent.removeChild(obj.children [I]); //动画结束删除节点
                    }
                })
            }
        });
    }

},1000);</obj.children.length>
J'utilise deux méthodes encapsulées par moi-même ici, l'une est requestAnimation basée sur requestAnimationFrame et addChild basée sur appendChild.

Afin d'obtenir l'effet de positions aléatoires des étoiles, les météores sont continuellement insérés et supprimés via l'intervalle défini de la minuterie :

Tout d'abord, ajoutez 2 météores à la page à chaque fois, mais l'intervalle du timer Inférieur au temps d'animation du météore, cela garantit que le nombre de météores sur la page n'est pas une valeur fixe, mais doit être supérieur à 2. Sinon, 2 météores à la fois seront un peu déserts ;

Ensuite, donnez à chaque météore nouvellement ajouté à la page une position aléatoire (en haut, à gauche), une taille aléatoire (échelle), un temps d'exécution d'animation aléatoire (minuterie );

Enfin, dans la boucle, donnez à chaque nouvel ajout à la page Meteor ajoute une animation et supprime le nœud après avoir exécuté l'animation via la fonction de rappel. Ce qu'il faut noter ici, c'est que l'animation est divisée en deux étapes (apparition et disparition, principalement contrôle de l'opacité). De plus, dans mon traitement ici, chaque météore se déplace sur la même distance de 300 pixels. Je pense que cette distance peut également être contrôlée par des nombres aléatoires, mais j'étais paresseux et je ne l'ai pas fait.

Petits problèmes

Actuellement, j'ai trouvé deux problèmes :

Premièrement, le problème avec le fonctionnement du DOM lui-même est que la page n'ajoute et ne supprime pas de nœuds en permanence, ce qui provoque un non-stop. La redistribution et le redessinage sont très gourmands en performances ;

Le deuxième problème est requestAnimationFrame lui-même car le minuteur ajoute constamment des nœuds, et les caractéristiques de requestAnimationFrame - lorsque vous quittez la page actuelle pour parcourir d'autres pages, l'animation sera mise en pause. . Cela crée un problème. Les nœuds continuent d'être ajoutés, mais l'animation s'arrête et n'est pas exécutée. Ensuite, la prochaine fois que vous reviendrez sur cette page, le boom explosera !!! L'animation explosera et vous verrez l'écran se figer. partent collectivement à la recherche de leur mère.

Conclusion

Bien que ce petit cas soit très simple en termes de difficulté, il est très évolutif. Par exemple, pour exprimer mon amour, Envoyer de l’amour, être romantique, etc. peut également être réalisé en utilisant du CSS pur.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer