search
HomeWeb Front-endCSS TutorialHow to achieve romantic meteor shower animation effect with CSS+JS? (code example)

The content of this article is to introduce how to realize the romantic meteor shower animation effect with CSS JS? (code example). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

First let’s take a look at the renderings:

How to achieve romantic meteor shower animation effect with CSS+JS? (code example)

Let’s do it next See how to do it:

HTML code:

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

CSS code:

/*  -  -  -  -  -  - 重启 -  -  -  -  -  -  */
 
 * {
     保证金: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 code:

//流星动画 
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>Encapsulation method: </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>Case analysis</strong></span></p>
<p><strong>HTML</strong></p>
<p>Since there are many nodes, and I wanted to make it as realistic and interesting as possible, I also added random positions to the nodes. Therefore, the output of nodes is controlled by JS. On the HTML side, only a few parent element boxes are written, plus the corresponding ID names and class names, and the structure is relatively simple. </p>
<p><strong>CSS</strong></p>
<p>The difficult part of the CSS part is the style of the meteor and drawing the clouds with circles, and then stacking the clouds to create a three-dimensional effect. </p>
<p>First let’s talk about the style of the meteor: </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);
 }

First extract the public style and add the positioning attribute;

Then add the meteor through the post pseudo-class after the star, using the boundary attribute Drawing:

1) Model drawing: The order of border-width is top, right, bottom, left. Similarly, the order of border-color is top, right, bottom, left. In this way, after one-to-one correspondence between border-width and border-color, you can see that 2px is the width of the meteor, 80px is the length of the meteor, and the 0-pixel meteor is the tail, thus forming a. Meteor model with head 2px wide, tail 0px, and length 80px;

2) Slightly realistic: by border radius? Add a rounded corner to the head of the meteor to make it look more realistic. Finally, rotate it at an angle through rotateta to make it look like it is falling;

3) Add sparkle: Add box shadow to the meteor. Add a little halo to make it look sparkling;

After the above 3 steps, a shooting star is ready.

Then there is drawing clouds:

Because the cloud code is relatively long, I won’t post it here. The method is nothing more than overlapping and covering each other one by one to complete the shape of a cloud.
After completing a cloud layer, copy one, and then use multiple cloud layers through rotate, opacity, left positioning, etc. to create a three-dimensional effect that fades and overlaps;

JS

The JS part uses meteor as an example

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>

I use two methods of my own encapsulation here, one is requestAnimation based on requestAnimationFrame, and addChild based on appendChild.

In order to achieve the effect of random star positions, meteors are continuously inserted and deleted through the setInterval of the timer:

First, add 2 meteors to the page each time, but the interval of the timer Less than the animation time of the meteor, this ensures that the number of meteors on the page is not a fixed value, but must be greater than 2. Otherwise, 2 meteors at a time will be a bit deserted;

Then, through the loop (it can also be used as an expression, it can be changed. For -, it is the simplest) to give each meteor newly added to the page a Random position (top, left), random size (scale), random animation execution time (timer);

Finally, in the loop, give each newly added to the page Meteor adds animation and deletes the node after executing the animation through the callback function. What should be noted here is that the animation is divided into two stages (appearance and disappearance, mainly opacity control). In addition, in my processing here, each meteor moves the same distance of 300px. I think this distance can also be controlled by random numbers, but I was lazy and didn't do it.

Small problems

Currently I have found two problems:

First, the problem with the DOM operation itself is that the page is not Adding and deleting nodes constantly, causing non-stop. Reflow and redrawing are very performance-intensive;

The second is the problem of requestAnimationFrame itself because the timer is constantly adding nodes, and the characteristics of requestAnimationFrame - when leaving the current page to browse other pages, the animation will be paused. This creates a problem. The nodes keep adding, but the animation is stopped and not executed. Then the next time you return to this page, the boom will happen!!! The animation will explode, and you will see the screen freeze. Many tadpoles set off collectively to find their mother.

Conclusion

Although this small case is very simple in terms of difficulty, it is highly scalable. For example, to express my love, Sending love, being romantic, etc. can also be achieved with pure CSS.

The above is the detailed content of How to achieve romantic meteor shower animation effect with CSS+JS? (code example). For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:segmentfault 思否. If there is any infringement, please contact admin@php.cn delete
How much specificity do @rules have, like @keyframes and @media?How much specificity do @rules have, like @keyframes and @media?Apr 18, 2025 am 11:34 AM

I got this question the other day. My first thought is: weird question! Specificity is about selectors, and at-rules are not selectors, so... irrelevant?

Can you nest @media and @support queries?Can you nest @media and @support queries?Apr 18, 2025 am 11:32 AM

Yes, you can, and it doesn't really matter in what order. A CSS preprocessor is not required. It works in regular CSS.

Quick Gulp Cache BustingQuick Gulp Cache BustingApr 18, 2025 am 11:23 AM

You should for sure be setting far-out cache headers on your assets like CSS and JavaScript (and images and fonts and whatever else). That tells the browser

In Search of a Stack That Monitors the Quality and Complexity of CSSIn Search of a Stack That Monitors the Quality and Complexity of CSSApr 18, 2025 am 11:22 AM

Many developers write about how to maintain a CSS codebase, yet not a lot of them write about how they measure the quality of that codebase. Sure, we have

Datalist is for suggesting values without enforcing valuesDatalist is for suggesting values without enforcing valuesApr 18, 2025 am 11:08 AM

Have you ever had a form that needed to accept a short, arbitrary bit of text? Like a name or whatever. That's exactly what is for. There are lots of

Front Conference in ZürichFront Conference in ZürichApr 18, 2025 am 11:03 AM

I'm so excited to be heading to Zürich, Switzerland for Front Conference (Love that name and URL!). I've never been to Switzerland before, so I'm excited

Building a Full-Stack Serverless Application with Cloudflare WorkersBuilding a Full-Stack Serverless Application with Cloudflare WorkersApr 18, 2025 am 10:58 AM

One of my favorite developments in software development has been the advent of serverless. As a developer who has a tendency to get bogged down in the details

Creating Dynamic Routes in a Nuxt ApplicationCreating Dynamic Routes in a Nuxt ApplicationApr 18, 2025 am 10:53 AM

In this post, we’ll be using an ecommerce store demo I built and deployed to Netlify to show how we can make dynamic routes for incoming data. It’s a fairly

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Tools

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.