Đây là hiệu ứng nền sử dụng thuộc tính CSS box-shadow để vẽ và tạo hiệu ứng cho nhiều hạt (ngôi sao). Không gian hạt lặp vô hạn được thể hiện bằng CSS thuần túy mà không sử dụng JavaScript.

Xem trước

<div class="particle-field">
  <div class="stars small"></div>
  <div class="stars medium"></div>
  <div class="stars large"></div>
</div>
.particle-field {
  position: relative;
  width: 100%;
  height: 400px;
  background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
  overflow: hidden;
  border-radius: 8px;
}

/* 星のコンテナ設定 */
.stars {
  background: transparent;
  position: absolute;
  top: 0;
  left: 0;
}

/* アニメーションループのため、同じ星の配置をY軸下に配置 */
.stars::after {
  content: "";
  position: absolute;
  top: 1000px; /* 親要素の高さ以上の値 */
  background: transparent;
}

/* --- 小さい星 --- */
.small {
  width: 1px;
  height: 1px;
  box-shadow: 
    120px 80px #fff, 250px 150px #fff, 380px 220px #fff, 410px 50px #fff, 
    550px 300px #fff, 680px 120px #fff, 720px 350px #fff, 850px 80px #fff, 
    920px 250px #fff, 150px 400px #fff, 300px 500px #fff, 450px 450px #fff,
    580px 600px #fff, 710px 550px #fff, 840px 700px #fff, 970px 650px #fff,
    180px 800px #fff, 310px 750px #fff, 440px 900px #fff, 570px 850px #fff,
    700px 950px #fff, 830px 800px #fff, 960px 900px #fff, 100px 900px #fff,
    200px 200px #fff, 400px 800px #fff, 600px 100px #fff, 800px 400px #fff,
    900px 100px #fff, 350px 70px #fff;
  animation: animStar 50s linear infinite;
}
.small::after {
  width: 1px;
  height: 1px;
  box-shadow: 
    120px 80px #fff, 250px 150px #fff, 380px 220px #fff, 410px 50px #fff, 
    550px 300px #fff, 680px 120px #fff, 720px 350px #fff, 850px 80px #fff, 
    920px 250px #fff, 150px 400px #fff, 300px 500px #fff, 450px 450px #fff,
    580px 600px #fff, 710px 550px #fff, 840px 700px #fff, 970px 650px #fff,
    180px 800px #fff, 310px 750px #fff, 440px 900px #fff, 570px 850px #fff,
    700px 950px #fff, 830px 800px #fff, 960px 900px #fff, 100px 900px #fff,
    200px 200px #fff, 400px 800px #fff, 600px 100px #fff, 800px 400px #fff,
    900px 100px #fff, 350px 70px #fff;
}

/* --- 中くらいの星 --- */
.medium {
  width: 2px;
  height: 2px;
  box-shadow: 
    80px 120px #fff, 200px 250px #fff, 320px 380px #fff, 450px 100px #fff,
    510px 450px #fff, 650px 200px #fff, 780px 50px #fff, 820px 300px #fff,
    950px 150px #fff, 100px 550px #fff, 220px 700px #fff, 350px 650px #fff,
    480px 800px #fff, 610px 750px #fff, 740px 900px #fff, 870px 850px #fff,
    150px 950px #fff, 280px 800px #fff, 410px 900px #fff, 540px 1000px #fff,
    250px 50px #fff, 500px 300px #fff, 750px 600px #fff, 900px 900px #fff;
  animation: animStar 100s linear infinite;
}
.medium::after {
  width: 2px;
  height: 2px;
  box-shadow: 
    80px 120px #fff, 200px 250px #fff, 320px 380px #fff, 450px 100px #fff,
    510px 450px #fff, 650px 200px #fff, 780px 50px #fff, 820px 300px #fff,
    950px 150px #fff, 100px 550px #fff, 220px 700px #fff, 350px 650px #fff,
    480px 800px #fff, 610px 750px #fff, 740px 900px #fff, 870px 850px #fff,
    150px 950px #fff, 280px 800px #fff, 410px 900px #fff, 540px 1000px #fff,
    250px 50px #fff, 500px 300px #fff, 750px 600px #fff, 900px 900px #fff;
}

/* --- 大きい星 --- */
.large {
  width: 3px;
  height: 3px;
  box-shadow: 
    50px 200px #fff, 180px 50px #fff, 300px 300px #fff, 420px 150px #fff,
    550px 400px #fff, 680px 50px #fff, 800px 250px #fff, 920px 450px #fff,
    100px 600px #fff, 250px 800px #fff, 380px 700px #fff, 500px 950px #fff,
    620px 850px #fff, 750px 1000px #fff, 880px 750px #fff, 120px 900px #fff;
  animation: animStar 150s linear infinite;
}
.large::after {
  width: 3px;
  height: 3px;
  box-shadow: 
    50px 200px #fff, 180px 50px #fff, 300px 300px #fff, 420px 150px #fff,
    550px 400px #fff, 680px 50px #fff, 800px 250px #fff, 920px 450px #fff,
    100px 600px #fff, 250px 800px #fff, 380px 700px #fff, 500px 950px #fff,
    620px 850px #fff, 750px 1000px #fff, 880px 750px #fff, 120px 900px #fff;
}

@keyframes animStar {
  from {
    transform: translateY(0px);
  }
  to {
    transform: translateY(-1000px);
  }
}