CSS 实现 3D 书本动效

一、前言

本文将使用纯 CSS 实现一个简单的 3D 书本展开动效。

二、实现思路

实现这么一个书本动效 乍一看可能会感觉有些复杂,实际很并不难,遇到这种组合动效的需求时,我们只要将整体拆分成多个小步骤去做,就很简单了。

1. 拆分主体

在实现动效前,我们需要先将书本画出来,画一个本子,我们可以先简单分成三个元素:封皮、书脊、扉页

img

2. CSS 变量声明与使用

本不打算加入这段,但考虑到有些没有用过的读者,还是讲一下。

在现代 CSS 中,在不使用预处理器的情况下,我们也可以声明 CSS 变量,在当前场景下,我们可以直接将书本的主题色与大小设置为变量,这样我们可以轻松的修改整个书本的样式。

变量声明

CSS 变量也成为 CSS 自定义属性。

CSS 变量定义:带有前缀 -- 的属性名,比如 --example--name,表示的是带有值的自定义属性

:root 伪类匹配文档树的根元素。对于 HTML 来说,:root 表示 <html> 元素,除了优先级更高之外,与 html 选择器相同,我们可以在 :root 伪类中声明全局 CSS 变量。

1
2
3
:root {
--color: red;
}

变量使用

可以通过 var() 函数在使用声明的变量。

1
2
3
div {
color: var(--color)
}

3. 绘制书本主体

根据第一步的拆分,我们将三个主要部分绘制出来。

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
<style>
:root {
/* 书本的高度 */
--main-height: 150px;
/* 书本的颜色 */
--theme-bg-color: rgba(239, 112, 155, .9);
}

div {
box-sizing: border-box;
}

/* 书本主体 */
#book {
position: relative;
margin: 150px auto 80px auto;
width: 150px;
height: var(--main-height);
cursor: pointer;
}

/* 书脊 */
.book-side {
position: absolute;
left: -14px;
width: 15px;
height: var(--main-height);
border-radius: 5px 0 0 5px;

background-color: var(--theme-bg-color);
}

/* 封面 */
.book--cover {
position: absolute;
top: 0;
left: -1px;
padding: 10px;
width: 105px;
height: var(--main-height);
font-size: 18px;
font-weight: 400;
border-radius: 0 6px 6px 0;

background-color: var(--theme-bg-color);
}

/* 书本内容 Begin */
.book--content {
padding: 4px 5px 4px 2px;
width: 105px;
height: var(--main-height);
border-radius: 2px;

background-color: var(--theme-bg-color);
}

.book--inner {
padding: 10px 0;
width: 100%;
height: 100%;
color: #333;
border-radius: 1px;

box-shadow: 0px 2px 14px 0px rgba(0, 0, 0, 0.2);
background-color: rgba(250, 250, 250, 0.8);
}
</style>

<body>
<div id="book">
<div class="book-side"></div>
<div class="book--cover">封面</div>
<div class="book--content">
<div class="book--inner"></div>
</div>
</div>
</body>

实现效果

4. 书本张开效果

现在虽然有了雏形,但是完全闭合的书本并不好看,我们让他有一点微微打开的效果。

通过 rotate 函数,以 x 轴为逆时针旋转 8°, 以 y 轴为顺时针旋转 30°

1
2
3
4
.book--cover {
/** 省略... **/
transform: rotateX(-8deg) rotateY(30deg);
}

实现效果如下,可以看到有了一些样子,但是旋转是以中心进行旋转的,偏离了书脊,不符合我们的预期。

可以通过 transform-origin 改变元素变型的原点 来调整旋转的位置。

img

设置 x 轴以左侧为旋转点,y 轴以中心为旋转点进行旋转。

1
2
3
4
5
.book--cover {
/** 省略... **/
transform: rotateX(-8deg) rotateY(30deg);
transform-origin: left center;
}

实现效果

5. 实现动效

完成了书本的基本骨架绘制后,我们可以将动画效果加进来了

鼠标悬浮动效

通过 :hover 伪类设置鼠标悬浮后的效果, 和第四步其实一样,打开效果通过 rotateXrotateY 实现,为了模拟的更加真实,在掀开时加入阴影。

1
2
3
4
#book:hover .book--cover {
transform: rotateX(-10deg) rotateY(50deg);
box-shadow: 30px 0 10px 0 rgba(0, 0, 0, 0.2);
}

这样基本的打开效果就实现好了,但是太过直接,不够平滑,我们对元素加入过度效果。

1
2
3
4
5
.book--cover {
/** 省略... **/
transform: rotateX(-8deg) rotateY(30deg);
transform-origin: left center;
}

这样基本的鼠标效果就实现好了。

书本打开动效

通过 :active 伪类设置长按时的打开效果, 通过 scale 将书本整体适当放大, 并将 封皮 的打开效果尽量放大即可。

1
2
3
4
5
6
7
#book:active {
transform: scale(1.7);
}

#book:active .book--cover {
transform: rotateX(-10deg) rotateY(138deg);
}

添加上面的代码后,便实现了长按打开的效果,为了放大效果更加自然平滑,对 #book 元素添加过度效果

1
2
3
4
#book {
/* 省略... */
transition: all .7s linear;
}

如此整体功能就实现完成了。

6. 美化内容

功能玩成后,我们便可以进一步对书本进行美化,现在整个书本太空,加入一些文字回显的更加丰满充实。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="book">
<div class="book-side"></div>
<div class="book--content">
<div class="book--cover">
CSS 圣经
</div>
<div class="book--inner">
<div style="padding-left: 10px">
<div class="book-page--content boo-page--title">~~~</div>
<div class="book-page--content">~~~~~~~~</div>
<div class="book-page--content">~~~~~~~~</div>
<div class="book-page--content">~~~~~~~~</div>
<div class="book-page--content">~~~~~~~~</div>
</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
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
<!--
* @Author: zi.yang
* @Date: 2023-07-18 19:32:17
* @LastEditors: zi.yang
* @LastEditTime: 2023-07-19 00:59:10
* @Description: 3D 书本动效
* @FilePath: /demo/other/9.book.html
-->

<!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>

<style>
:root {
--main-height: 150px;
--theme-bg-color: rgba(239, 112, 155, .9);
}

div {
box-sizing: border-box;
}

/* 书本主体 */
#book {
position: relative;
margin: 150px auto 80px auto;
width: 150px;
height: var(--main-height);
transition: all .7s linear;
cursor: pointer;
}

/* 书脊 */
.book-side {
position: absolute;
left: -14px;
width: 15px;
height: var(--main-height);
border-radius: 5px 0 0 5px;

background-color: var(--theme-bg-color);
}

/* 封面 */
.book--cover {
position: absolute;
top: 0;
left: -1px;
padding: 10px;
width: 105px;
height: var(--main-height);
font-size: 18px;
font-weight: 400;
border-radius: 0 6px 6px 0;
transform-origin: left center;
transform: rotateX(-8deg) rotateY(30deg);
transition: all .7s linear;

background-color: var(--theme-bg-color);
}

#book:active {
transform: scale(1.7);
}

#book:hover .book--cover {
transform: rotateX(-10deg) rotateY(50deg);
box-shadow: 30px 0 10px 0 rgba(0, 0, 0, 0.2);
}

#book:active .book--cover {
transform: rotateX(-10deg) rotateY(138deg);
}

/* 书本内容 Begin */
.book--content {
padding: 4px 5px 4px 2px;
width: 105px;
height: var(--main-height);
border-radius: 2px;

background-color: var(--theme-bg-color);
}

.book--inner {
padding: 10px 0;
width: 100%;
height: 100%;
color: #333;
border-radius: 1px;

box-shadow: 0px 2px 14px 0px rgba(0, 0, 0, 0.2);
background-color: rgba(250, 250, 250, 0.8);
}
</style>
</head>

<body>
<div id="book">
<div class="book-side"></div>
<div class="book--cover">CSS 圣经</div>
<div class="book--content">
<div class="book--inner">
<div style="padding-left: 10px">
<div class="book-page--content boo-page--title">~~~</div>
<div class="book-page--content">~~~~~~~~</div>
<div class="book-page--content">~~~~~~~~</div>
<div class="book-page--content">~~~~~~~~</div>
<div class="book-page--content">~~~~~~~~</div>
</div>
</div>
</div>
</div>

<p style="text-align:center">长按书本,即可展开书本</p>
</body>

</html>

CSS 实现 3D 书本动效
https://blog.pangcy.cn/2023/07/18/前端编程相关/前端基础/CSS 实现 3D 书本动效/
作者
子洋
发布于
2023年7月18日
许可协议