用css画一幅明月高挂,星星会闪的星空

1,482 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情

我正在参加 码上掘金体验活动,详情:show出你的创意代码块

前言

前面的文章我用css画了五角星⭐️(用css画一个五角星), 以及用box-shadow实现了画月亮🌛(css3的box-shadow属性

那么今天,结合五角星和月亮,在码上掘金画一幅明月高挂,星星会闪的星空。

效果展示

code.juejin.cn/pen/7087956…

代码介绍

首先我们实现星空的背景,这里我们用黑色来代替

html,
body {
  position: relative;
  background-color: black;
  height: 100%;
}

然后我们画一个月亮,具体可以在我的这篇文章css3的box-shadow属性可以看到,主要是使用box-shadow实现。

<style>
.moon {
  position: relative;
  left: 100px;
  top: 100px;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  box-shadow: 35px 0px 5px yellow inset;
}
</style>
<body>
  <div class="moon"></div>
</body>

image.png

然后我们接着把星星加上,具体怎么画星星可以通过我这篇文章用css画一个五角星,之前画的是红色的大五角星,我要把星星变小点,然后换成白色的颜色。

.star {
  position: absolute;
  width: 0px;
  height: 0px;
  border-color: white transparent transparent transparent;
  border-width: 4.49px 6.18px;
  border-style: solid;
}
.star::before {
  content: '';
  display: block;
  position: absolute;
  left: -6.18px;
  top: -4.49px;
  border-color: white transparent transparent transparent;
  border-width: 4.49px 6.18px;
  border-style: solid;
  transform: rotate(72deg);
  transform-origin: 50% 22.5%;
}
.star::after {
  content: '';
  display: block;
  position: absolute;
  left: -6.18px;
  top: -4.49px;
  border-color: white transparent transparent transparent;
  border-width: 4.49px 6.18px;
  border-style: solid;
  transform: rotate(-72deg);
  transform-origin: 50% 22.5%;
}

image.png

但是天上的星星是满天的,这里我们可以用js遍历生成100个星星。

这里我使用createDocumentFragment,这个是生成文档碎片节点,它并不存在dom中,所以创建的div append到它里面,并不会引起页面的重新渲染(回流,重绘)。最后才把它append到body中,这样 只需要重绘一次。

const frag = document.createDocumentFragment()
for (let i = 0; i < 100; i++) {
  const star = document.createElement('div')
  star.classList.add('star')
  frag.appendChild(star)
}
body.appendChild(frag)

image.png

然后星星的位置应该是随机的,所以我们也动态给他们加上随机位置。

获取body的宽度和高度,利用Math.random()来生成随机位置。

const body = document.querySelector('body')
const bodyWidth = body.clientWidth
const bodyHeight = body.clientHeight
const frag = document.createDocumentFragment()
for (let i = 0; i < 100; i++) {
  const star = document.createElement('div')
  star.classList.add('star')
  star.style.left = `${Math.random() * bodyWidth}px`
  star.style.top = `${Math.random() * bodyHeight}px`
  frag.appendChild(star)
}
body.appendChild(frag)

注意⚠️:star的position要改成absolute(绝对定位);

image.png

可以看到星空的轮廓已经出来了。

现实中星星是有大有小的,我们这里都是一样大小的星星,可以使用transform: scaleMath.random()来设置随机的大小。

star.style.transform = `scale(${Math.random() * 1.2})`

image.png

这个星空目前来看是静态的,要加点动画才行。

因为星星会闪的嘛,下面再把星星会闪的动画加上。

这里我使用的是css3动画animation/keyframes。 用opacity来模拟星星的显示或隐藏。

我之前也有篇文章讲过元素隐藏的几种方式,有兴趣可以看看

.star {
 animation: twinkle 2s infinite;
}
@keyframes twinkle {
  0%, 100% {
    opacity: 1;
  }

  50% {
    opacity: 0;
  }
}

QQ20220419-004031-HD.gif

但是这样实现的星星都是同时闪烁的,闪烁的时机应该加上随机的效果。我们继续用Math.random()函数,去设置星星动画延迟的随机时间。

在动态生成star元素的时候都加上。

star.style.animationDelay = `${Math.random()}s`

最终的效果是

QQ20220419-000240-HD.gif

总结

以上就是实现明月高挂,星星会闪的星空的整体效果。整体还是比较简单的。大家可以动手试试吧~

附上整体的代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>star-sky</title>
  <style>
    html,
    body {
      position: relative;
      background-color: black;
      height: 100%;
    }

    .moon {
      position: relative;
      left: 100px;
      top: 100px;
      z-index: 1;
      width: 200px;
      height: 200px;
      border-radius: 50%;
      box-shadow: 35px 0px 5px yellow inset;
    }

    .star {
      position: absolute;
      width: 0px;
      height: 0px;
      border-color: white transparent transparent transparent;
      border-width: 4.49px 6.18px;
      border-style: solid;
      animation: twinkle 2s infinite;
    }

    @keyframes twinkle {

      0%,
      100% {
        opacity: 1;
      }

      50% {
        opacity: 0;
      }
    }

    .star::before {
      content: '';
      display: block;
      position: absolute;
      left: -6.18px;
      top: -4.49px;
      border-color: white transparent transparent transparent;
      border-width: 4.49px 6.18px;
      border-style: solid;
      transform: rotate(72deg);
      transform-origin: 50% 22.5%;
    }

    .star::after {
      content: '';
      display: block;
      position: absolute;
      left: -6.18px;
      top: -4.49px;
      border-color: white transparent transparent transparent;
      border-width: 4.49px 6.18px;
      border-style: solid;
      transform: rotate(-72deg);
      transform-origin: 50% 22.5%;
    }
  </style>
</head>

<body>
  <div class="moon"></div>
</body>
<script>
  const body = document.querySelector('body')
  const bodyWidth = body.clientWidth
  const bodyHeight = body.clientHeight
  const frag = document.createDocumentFragment()
  for (let i = 0; i < 100; i++) {
    const star = document.createElement('div')
    star.classList.add('star')
    star.style.left = `${Math.random() * bodyWidth}px`
    star.style.top = `${Math.random() * bodyHeight}px`
    star.style.transform = `scale(${Math.random() * 1.2})`
    star.style.animationDelay = `${Math.random()}s`
    frag.appendChild(star)
  }
  body.appendChild(frag)
</script>

</html>