📢前言

代码取自开源项目50projects50days,用作个人学习和巩固三件套的知识,增加了注释,可能会有小改动。

在线演示地址

📝实现思路及效果

20220901204155.jpg

20220901204206.jpg

💻代码

index.html

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
<!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>3d盒子背景</title>
<!-- 引入一个字体样式 并检验是否安全 -->

<!-- integrity 为了防止 CDN 篡改 javascript 而引入的XSS 风险。-->
<!-- 可以用在<script> 或者 <link>元素上,用来开启浏览器对获取的资源进行检查,它允许你为script或者link提供一个hash,用来进行验签,检验加载的JavaScript文件或者CSS问卷是否完整。如果检验 两者签名不同 则不会执行该资源 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog=="
crossorigin="anonymous">

<!-- crossorigin 该枚举属性指定在加载相关图片时是否必须使用CORS。可取的值包括以下两个:

anonymous:会发起一个跨域请求(即包含Origin: HTTP头)。但不会发送任何认证信息(即不发送cookie, X.509证书和HTTP基本认证信息)。如果服务器没有给出源站凭证(不设置Access-Control-Allow-Origin: HTTP头),这张图片就会被污染并限制使用。
use-credentials:会发起一个带有认证信息 (发送 cookie, X.509 证书和 HTTP 基本认证信息) 的跨域请求 (即>包含 Origin: HTTP 头). 如果服务器没有给出源站凭证 (不设置 Access-Control-Allow-Origin: HTTP 头), 这张图片就会被污染并限制使用.

当不设置该属性时, 资源将会不使用 CORS 加载 (即不发送 Origin: HTTP 头), 这将阻止其在 元素中进行使用. 若设置了非法的值, 则视为使用 anonymous.

-->
<link rel="stylesheet" href="style.css">
</head>
<body>
<button id="btn" class="change"> change style </button>
<!-- 默认状态下是一个 包括4*4格子 的大盒子 -->
<div id="boxes" class="boxes big"></div>
<script src="script.js"></script>
</body>
</html>

style.css

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/* @import 引入样式 注意加上分号 */
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');
* {
box-sizing: border-box;
}

body {
background-color: #fafafa;
/* sans-serif 无衬线字体 */
/* font-family最后加上sans-serif,也是为了保证能够调用这个字体族里面的字体,因为大多数计算机里都有这种字体。 */
font-family: 'Roboto', sans-serif;
display: flex;
/* 规定弹性项目的方向 */
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
}

.change {
background-color: #f9ca24;
color: #fff;
font-family: 'Poppins', sans-serif;
border: 0;
border-radius: 3px;
font-size: 16px;
padding: 12px 20px;
cursor: pointer;
position: fixed;
top: 20px;
/* 设置字与字之间的间距 */
letter-spacing: 2px;
/* box-shadow 给盒子添加阴影; */
box-shadow: 0 3px rgba(249, 202, 36, 0.5);
z-index: 100;
}

/* 按钮 焦点状态 */
.change:focus {
/* 盒子边框样式为空 */
outline: none;
}
/* 按钮 点击状态 */
.change:active {
box-shadow: none;
transform: translateY(2px);
}

.boxes {
display: flex;
/* 弹性盒子在需要的时候换行 常用于li标签弹性布局展示商品 */
flex-wrap: wrap;
justify-content: space-between;
height: 500px;
width: 850px;
position: relative;
top: 28px;
/* 动画0.4秒过程 快启动 慢停止 */
transition: 0.4s ease;
}

.boxes.big {
width: 950px;
height: 600px;
}

/* 大图切割成小盒子(小图)的样式设置 */
.box {
background-image: url('https://vip1.loli.io/2022/05/05/yaiAdPZeuYRXcL5.jpg');
background-repeat: no-repeat;
background-size: 850px 500px;
position: relative;
height: 125px;
width: 170px;
transition: 0.4s ease;
}
/* 小盒子的外侧面 合并后仍会显示在外层 */
.box::after {
content: '';
background-color: #eae5e6;
position: absolute;
top: 8px;
right: -15px;
height: 100%;
width: 15px;
/* 二维平面上 倾斜45度 显示出立体盒子其他面的背景色 给人立体感*/
transform: skewY(45deg);
}
/* 小盒子的内侧面 合并后看不到 */
.box::before {
content: '';
background-color: #eae5e6;
position: absolute;
bottom: -15px;
left: 8px;
width: 100%;
height: 15px;
transform: skewX(45deg);
}

script.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const boxesContainer = document.getElementById('boxes')
const btn = document.getElementById('btn')

btn.addEventListener('click', () => boxesContainer.classList.toggle('big'))

function createBoxes() {
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 5; j++) {
const box = document.createElement('div')
box.classList.add('box')
// 每个小盒子显示图片一个小角 图片移动盒子定长倍数 由下一个盒子显示
box.style.backgroundPosition = `${-j * 170}px ${-i * 125}px`
boxesContainer.appendChild(box)
}
}
}

createBoxes()