HTML5 满天繁星+流星划过动画效果

377 阅读4分钟

Untitled11.gif

image.png

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
      background-color: #000;
    }
    /* 天空 */
    #the-sky {
      position: relative;
      left: 0px;
      top: 0px;
      width: 100%;
      height: 100%;
      background-color: #000;
      overflow: hidden;
    }
    /* 星星 - 容器 */
    .star-container {
      position: absolute;
      /* 可以在 js 中随机生成星星大小,造成远近感 */
      /* transform: scale(0.5); */
    }
    /* 星星 - 横 */
    .star-hor {
      position: absolute;
      width: 30px;
      height: 2px;
      border-radius: 100%;
      background: linear-gradient(
        -45deg,
        rgba(0, 0, 255, 0),
        /* 星星颜色 */
        #5f91ff,
        rgba(0, 0, 255, 0)
      );
      transform: scale(0);
      animation-name: shining;
      animation-timing-function: ease-in-out;
      animation-iteration-count: infinite;
      /* 动画时间,拆出来就是为了方便生成随机时间 */
      animation-duration: 3.0s;
    }
    /* 星星 - 竖 */
    .star-ver {
      position: absolute;
      top: -14px;
      left: 14px;
      width: 2px;
      height: 30px;
      border-radius: 100%;
      background: linear-gradient(
        -45deg,
        rgba(0, 0, 255, 0),
        /* 星星颜色 */
        #5f91ff,
        rgba(0, 0, 255, 0)
      );
      transform: scale(0);
      animation-name: shining;
      animation-timing-function: ease-in-out;
      animation-iteration-count: infinite;
      /* 动画时间,拆出来就是为了方便生成随机时间 */
      animation-duration: 3.0s;
    }
    /* 星星发光动画 */
    @keyframes shining {
      0% {
        transform: scale(0);
      }
      50% {
        transform: scale(1);
      }
      100% {
        transform: scale(0);
      }
    }
    /* 流星 - 容器 */
    .meteor-container {
      position: absolute;
    }
    /* 流星 - 主体 */
    .meteor {
      position: absolute;
      width: 4px;
      height: 4px;
      border-radius: 50%;
      background: #fff;
      box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.1),
      0 0 0 8px rgba(255, 255, 255, 0.1),
      0 0 20px rgba(255, 255, 255, 0.1);
      /* 重复动画,现在按照每个流星每次不同位置的方式出现,这种重复位置出现的则先注释 */
      /* animation-name: streaking;
      animation-timing-function: ease-in-out;
      animation-iteration-count: infinite;
      animation-duration: 3.0s; */
    }
    /* 流星 - 尾巴 */
    .meteor-tail {
      position: absolute;
      top: 50%;
      width: 200px;
      height: 1px;
      background: linear-gradient(90deg, #fff, transparent);
      transform: translateY(-50%);
    }
    /* 流星划过天空动画 */
    /* @keyframes streaking {
      0% {
        opacity: 1;
        transform: rotate(315deg) translateX(0);
      }
      70% {
        opacity: 1;
      }
      100% {
        opacity: 0;
        transform: rotate(315deg) translateX(-1500px);
      }
    } */
  </style>
</head>
<body>
  <!-- 天空 -->
  <div id="the-sky">
    <!-- 星星(由 js 去创建)-->
    <!-- 星星有个容器,方便控制每个星星大小,内部装有横竖条组装成十字形状的星星进行闪烁,不使用伪类是为了更好的给每个条添加动画,达到闪烁效果 -->
    <!-- <div class="star-container" style="left: 100px; top: 100px;">
      <div class="star-hor">
        <div class="star-ver"></div>
      </div>
    </div> -->
    <!-- 流星(由 js 去创建 -->
    <!-- 流星有个容器,方便控制每个流星大小,内部装有流星与尾巴元素,不使用伪类是为了更好的给每个尾巴自由控制角度、长度、速度 -->
    <!-- <div class="meteor-container" style="left: 50%; top: 50%;">
      <div class="meteor">
        <div class="meteor-tail"></div>
      </div>
    </div> -->
    <!-- 背景音乐,触摸播放,可以删除 -->
    <audio
      id="music"
      src="https://freetyst.nf.migu.cn/public/product9th/product46/2023/12/2514/2023%E5%B9%B412%E6%9C%8822%E6%97%A516%E7%82%B951%E5%88%86%E5%86%85%E5%AE%B9%E5%87%86%E5%85%A5%E5%8D%8E%E5%BC%BA%E8%87%B4%E8%BF%9C1%E9%A6%96115803/%E6%A0%87%E6%B8%85%E9%AB%98%E6%B8%85/MP3_128_16_Stero/63278105706140959.mp3?channelid=02&msisdn=6f8432c3-03ec-4c12-817b-163a1fda6104&Tim=1703570982946&Key=9bf5ce0f48e0c0f1"
      loop
      autoplay
    ></audio>
  </div>
  <script>
    // 初始化指定星星数量
    function initStars (num) {
      // 获取当前天空元素
      let thesky = document.getElementById('the-sky')
      // 获取天空宽高
      let w = thesky.clientWidth
      let h = thesky.clientHeight
      // 星星列表,方便更新位置
      let stars = []
      // 星星颜色
      let colors = ['#fff', '#5f91ff']
      // 循环创建
      for (let i = 0; i < num; i++) {
        // 星星坐标
        let x = createRandomInteger(0, w)
        // 顶部的星星不会被挡住,也可以设置为 0 ,但是有些星星会被挡掉半边
        let y = createRandomInteger(15, h)
        // 延迟闪烁,保证所有星星不是同时执行动画,产生交替闪烁的感觉
        let delay = createRandomDecimal(0, 10) // i * 0.1
        // 随机闪烁时间
        let duration = createRandomDecimal(1.5, 6.0)
        // 星星大小
        let scale = Math.min(createRandomDecimal(0.1, 0.7), 1.0) // 1
        // 星星颜色
        let color = colors[createRandomInteger(0, colors.length)]
        // 星星容器
        const starContainer = document.createElement('div')
        starContainer.setAttribute('class', 'star-container')
        starContainer.setAttribute('style', `
          left: ${x}px;
          top: ${y}px;
          transform: scale(${scale});
        `)
        // 星星横条
        const starHor = document.createElement('div')
        starHor.setAttribute('class', 'star-hor')
        starHor.setAttribute('style', `
          animation-delay: ${delay}s;
          animation-duration: ${duration}s;
          background: linear-gradient(
            -45deg,
            rgba(0, 0, 255, 0),
            ${color},
            rgba(0, 0, 255, 0)
          );
        `)
        // 星星竖条
        const starVer = document.createElement('div')
        starVer.setAttribute('class', 'star-ver')
        starVer.setAttribute('style', `
          animation-delay: ${delay}s;
          animation-duration: ${duration}s;
          background: linear-gradient(
            -45deg,
            rgba(0, 0, 255, 0),
            ${color},
            rgba(0, 0, 255, 0)
          )
        `)
        // 组装星星
        starHor.appendChild(starVer)
        starContainer.appendChild(starHor)
        // 星星添加到天空
        stars.push(starContainer)
        thesky.append(starContainer)
      }
      // 监听窗口变化,更新星星位置
      window.addEventListener('resize', () => {
        // 获取天空宽高
        let w = thesky.clientWidth
        let h = thesky.clientHeight
          // 循环创建
        for (let i = 0; i < stars.length; i++) {
          // 星星坐标
          let x = createRandomInteger(0, w)
          // 顶部的星星不会被挡住,也可以设置为 0 ,但是有些星星会被挡掉半边
          let y = createRandomInteger(15, h)
          // 修改位置
          stars[i].style.top = `${y}px`
          stars[i].style.left = `${x}px`
        }
      })
    }
    // 随机出现指定区间数量内的流星划过,间隔指定时间再次随机出现
    function initMeteors (min, max) {
      // 获取当前天空元素
      let thesky = document.getElementById('the-sky')
      // 流星颜色
      let colors = ['#fff', '#5f91ff']
      // 随机出现几条流星
      let count = createRandomInteger(min, max)
      // 开始随机出现
      for (let i = 0; i < count; i++) {
        // 获取天空宽高
        let w = thesky.clientWidth
        let h = thesky.clientHeight
        // 流星坐标
        let x = createRandomInteger(w * 0.1, w)
        let y = createRandomInteger(-15, -10)
        // 延迟出现时间
        let delay = createRandomDecimal(0, 8)
        // 划过天空时间
        let duration = createRandomDecimal(10.0, 20.0)
        // 流星大小
        let scale = Math.min(createRandomDecimal(0.5, 1.0), 1.0)
        // 流星颜色
        let color = colors[createRandomInteger(0, colors.length)]
        // 流星容器
        const meteorContainer = document.createElement('div')
        meteorContainer.setAttribute('class', 'meteor-container')
        meteorContainer.setAttribute('style', `
          left: ${x}px;
          top: ${y}px;
          transform: scale(${scale});
        `)
        // 流星主体
        const meteor = document.createElement('div')
        meteor.setAttribute('class', 'meteor')
        meteor.setAttribute('style', `
          background: ${color};
          box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.1),
          0 0 0 8px rgba(255, 255, 255, 0.1),
          0 0 20px rgba(255, 255, 255, 0.1);
          opacity: 1;
          transition: all ${duration}s;
          transition-delay: ${delay}s;
          transform: rotate(315deg) translateX(0);
        `)
        // 流星尾巴
        const meteorTail = document.createElement('div')
        meteorTail.setAttribute('class', 'meteor-tail')
        meteorTail.setAttribute('style', `
          background: linear-gradient(90deg, ${color}, transparent);
        `)
        // 组装流星
        meteor.appendChild(meteorTail)
        meteorContainer.appendChild(meteor)
        // 流星添加到天空
        thesky.append(meteorContainer)
        // 流星动画,动画完成后移除
        setTimeout(() => {
          meteor.style.opacity = 0
          meteor.style.transform = `rotate(315deg) translateX(-${Math.max(w, h)}px)`
          // 移除当前流星
          setTimeout(() => {
            meteor.removeChild(meteorTail)
            meteorContainer.removeChild(meteor)
            thesky.removeChild(meteorContainer)
          }, duration * 1000 + delay * 1000)
        }, 0)
      }
      // 重复出现流星
      setTimeout(() => {
        initMeteors(min, max)
      }, 2000)
    }
    // 在指定区间生成随机整数
    function createRandomInteger (min, max) {
      return Math.round(Math.random() * (max - min) + min)
    }
    // 在指定区间生成随机小数,保留两位小数,float 为浮动值,默认 0
    function createRandomDecimal (min, max) {
      return (Math.random() * (max - min) + min).toFixed(2)
    }
    // 调用(如果卡顿可以降低渲染数量)
    initStars(1000)
    initMeteors(3, 10)
    // 触摸开始播放音乐
    document.getElementById('the-sky').onclick = () => {
      document.getElementById('music').play()
    }
  </script>
</body>
</html>

源码地址,最新调整会更新到这:DZMStarrySky