制作一个有趣的404页面

最近决定给博客更换一个有趣的 404 页面,效果可以点击这个链接看看效果,接下来记录一下完成过程。

首先分析页面结构,黑色背景上飘过一排星星,上方中部一个晃动的灯,下方两行文字只有灯光扫过,或者鼠标覆盖时才能看到。

404页面◎ 一个有趣的404页面

下面复盘一下完成过程:

首先是页面背景:黑色背景上漂浮着一堆星星,星星的位置随机出现,然后向上漂浮。背景没什么好说的,设置全屏宽高后,给个背景色就好了。

大量的星星颜色随机,位置随机,所以不可能自己手敲。我们很容易想到通过 CSS 的多重投影配合自定义属性,随机生成以上背景。

为了背景上的星星效果不显得那么突兀,需要使得点开网页时整屏就有星星,且星星持续从下至上运动,所以盒子下方还会有轮换交替的一屏幕大小的星星,所以我们总共需要生成 3 个星星。第一个星星盒子播放一次动画后停留在最后一帧(即全部消失)。后两组星星盒子重新生成星星后,交替无限播放星星从下向上得运动。

1
2
3
4
5
6
7
<!--- html -->
<div class="bg">
  <div class="star star1"></div>
  <div class="star star2"></div>
  <div class="star star3"></div>
  <div></div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/* css */
.bg {
  width: 100vw;
  height: 100vh;
  background-color: #222;
  position: relative;
  overflow: hidden;
}

/* 星星的运动动画 */
@keyframes animStar {
  0% {
    transform: translateY(0px);
  }

  100% {
    transform: translateY(-100vh);
  }
}

@keyframes animStar1 {
  0% {
    transform: translateY(0px);
  }

  100% {
    transform: translateY(-200vh);
  }
}

.star {
  width: 3px;
  height: 3px;
  position: absolute;
  font-size: 0.75rem;
}

/* var(--xxx)是css自定义属性 */
.star1 {
  left: -9px;
  top: -9px;
  text-shadow: var(--randomStar1);
  animation: animStar 10s linear forwards;
}

.star2 {
  left: -9px;
  bottom: -9px;
  text-shadow: var(--randomStar2);
  animation: animStar1 20s linear infinite;
}

.star3 {
  left: -9px;
  bottom: -9px;
  text-shadow: var(--randomStar3);
  animation: animStar1 20s 10s linear infinite;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// javascript
// 利用闭包生成星星的随机颜色
const getRandomColor = function () {
  return (
    '#' +
    (function addCharacters(color) {
      return (color += '0123456789abcdef'[Math.floor(Math.random() * 16)]) &&
        color.length == 6
        ? color
        : addCharacters(color)
    })('')
  )
}

// 生成星星的随机位置
const getRandomPosition = function () {
  const posX = Math.random() * 100
  const posY = Math.random() * 100
  return posX + 'vw ' + posY + 'vh'
}

// 利用多重投影,将星星随机铺满屏幕
const getRandomStar = function () {
  let randomStar = ''
  for (let i = 0; i < 100; i++) {
    randomStar += getRandomPosition() + ' ' + getRandomColor() + ','
  }
  randomStar = randomStar.replace(/,([^,]*)$/, '' + '$1')
  return randomStar
}

// javascript修改阴影属性
;(function () {
  document.documentElement.style.setProperty('--randomStar1', getRandomStar())
  document.documentElement.style.setProperty('--randomStar2', getRandomStar())
  document.documentElement.style.setProperty('--randomStar3', getRandomStar())
})()

// 每次播放动画完成后,重新生成星星位置
setInterval(function () {
  document.documentElement.style.setProperty('--randomStar2', getRandomStar())
}, 20000)

// 在上述规则,添加延时半次播放规则
let i = 1
setInterval(function () {
  i++
  if (i == 2) {
    document.documentElement.style.setProperty('--randomStar3', getRandomStar())
    i = 0
  }
}, 10000)

背景◎ 背景

接着就是灯的效果,基本可以分为灯杆、灯罩、灯泡、追光四部分。

灯杆绕着屏幕上方中心旋转,为了模拟灯杆发热效果,还增加了一个由冷色到暖色渐变的效果。

1
2
3
4
<!--- html -->
<div class="line">
  <div class="pointer"></div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* css */
@keyframes move {
  0% {
    transform: rotate(20deg);
  }

  100% {
    transform: rotate(-20deg);
  }
}

.line {
  position: relative;
  width: 8px;
  height: 100px;
  background-image: linear-gradient(#2094da, #c14119);
  border-radius: 4px;
  margin: 2px auto;
  transform-origin: center 4px;
  animation: move 2.5s cubic-bezier(0.7, 0, 0.3, 1) infinite alternate;
}

.pointer {
  position: absolute;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background-color: #eee;
  top: 2px;
  left: 2px;
}

然后是灯罩,根据灯杆绝对定位即可。

1
2
<!--- html -->
<div class="cover"></div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
/* css */
.cover {
  position: absolute;
  width: 200px;
  height: 80px;
  background: #0bd5e8;
  border-top-left-radius: 50%;
  border-top-right-radius: 50%;
  top: 98px;
  left: -100px;
}

灯罩里加上一个灯泡,且灯泡周围以及灯罩内部需要有一个高亮效果。

1
2
3
4
<!--- html -->
<div class="in-cover">
  <div class="bulb"></div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* css */
.in-cover {
  position: absolute;
  width: 200px;
  height: 20px;
  border-radius: 100%;
  background: #08ffff;
  bottom: -9px;
}

.bulb {
  position: absolute;
  z-index: -1;
  width: 50px;
  height: 50px;
  background-color: #08fffa;
  border-radius: 50%;
  left: 75px;
  bottom: -20px;
  margin: 0px auto;
  box-shadow: 0 0 25px 7px #7fffff, 0 0 64px 47px #00ffff80,
    0px 0 30px 15px #00ffff33;
}

最后利用边框的分割效果做出一个梯形的散射追光效果。

1
2
<!--- html -->
<div class="light"></div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* css */
.light {
  position: absolute;
  width: 200px;
  left: -175px;
  top: 20px;
  border-bottom: 70vh solid #2cffff3d;
  border-left: 100px solid transparent;
  border-right: 100px solid transparent;
}

灯光完成效果◎ 灯光完成效果

文字颜色跟背景颜色一样,即可将文字隐藏起来。当追光扫过时,就能显示出文字,就不多做赘述了。以上,一个有趣的404 页面就全部完成了。