前言
看到以上的翻书动画相信大家早已急不可耐,我们废话少说直接开敲
构思
如何实现一个3D翻书动画? 首先解构我们今天的需求 这本书实质上由什么组成呢?显而易见的是这本书由正反两面构成,能翻开的左边和右边,每两边都有两个封面,那么套到HTML的思维中就是:这本书由四个盒子组成,其中前两页盒子可以翻开。相信说到这很多大佬们就已经开始狂敲代码了,哈哈让我们一起写下这本书的HTML部分吧。
一.HTML:构建框架
我们创建一个div元素,其类名为book p3d。代表这本书的整体结构。
-
book-cover: 我们用它代表情书右半部分,包含前后两页。
- page back flip: 这是书的背面页,我们给他加上“flip”类,用于翻书效果。
- page front p3d: 这是书的前面页,加上“p3d”类,用于照片弹起的3D效果。它包含
shadow和pic两个div,分别用于显示阴影和照片。
-
front-cover: 是书内部的左半部分。
- page front flip p3d: 这是书内部的正面页,具有“flip”和“p3d”类,用于3D翻页效果。它包含一个
p元素,我们在这里写下对小美的表白。 - page back: 这是整本情书的封面,是这封信的第一外观
- page front flip p3d: 这是书内部的正面页,具有“flip”和“p3d”类,用于3D翻页效果。它包含一个
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="book p3d">
<div class="book-cover p3d">
<div class="page back flip"></div>
<div class="page front p3d">
<div class="shadow"></div>
<div class="pic"></div>
</div>
</div>
<div class="front-cover p3d">
<div class="page front flip p3d">
<p>
</p>
</div>
<div class="page back"></div>
</div>
</div>
</body>
</html>
好,大功告成,这封信的外观设计已经被我们码码码下,想让这封信变得更加好看就得交給我们的CSS部分
二.CSS:设计情书的布局和外观
1.布局你的整体页面
布局网页时通常会设置了一套“默认服装”,让页面看起来更整洁、统一,并为之后的样式和效果设置做好了准备。它移除了一些默认的、可能不需要的样式,并设置基础的字体、颜色和背景,使得你之后可以更容易地在这个基础上添加更多的样式和交互效果。通常通过通配符选择器* 和类型选择器body HTML来控制,提高用户的体验。
在这里我们也加上这三种选择器来达到美观的效果。
* {
margin: 0;
padding: 0;
border: 0;
box-sizing: border-box;
}
html {
height: 100%;
}
body {
height: 100%;
font: 100%/1.25 Helvetica, arial, helvetica;
color: #030202;
perspective: 1000px;
background: linear-gradient(to bottom, #444, #999);
}
-
*选择器:margin: 0;: 移除所有元素的外边距(margin)。这通常用于避免元素之间的默认间隔。padding: 0;: 移除所有元素的内边距(padding)。border: 0;: 移除所有元素的边框(border)。box-sizing: border-box;: 设置所有元素的盒模型为border-box。这意味着元素的宽度和高度包括了内容、内边距和边框,但不包括外边距。这有助于更精确地控制元素的尺寸。
-
html选择器:height: 100%;: 设置html元素的高度为其父元素(通常是浏览器窗口)的100%。
-
-
body选择器: -
height: 100%;: 设置body元素高度为其父元素(这里是html元素)的100%。这通常用于确保页面内容填充整个浏览器窗口。 -
font: 100%/1.25 Helvetica, arial, helvetica;: 设置字体为Helvetica,arial,或helvetica(如果前两个不可用)。字体大小是浏览器默认字体大小的100%,行高是字体大小的1.25倍。 -
color: #030202;: 设置文本颜色为深灰色。 -
perspective: 1000px;: 为3D转换元素设置观察者和Z=0平面的距离,即“视距”。这常用于创建3D效果,如翻转、旋转等。 -
background: linear-gradient(to bottom, #444, #999);: 为body设置背景色渐变效果。从上到下,颜色从深灰色(#444)渐变到中灰色(#999)。
-
2.仔细分析,建造你的主体
接下来是CSS的重头戏,在开始之前让我们整理一下我们需要做的事情
- 设置这本书的长宽高,确定这本书的位置,让这本书倾斜
- 确定书页的位置,设置字体大小
- 给这本书包个书皮,填上你喜欢的背景颜色或图片
- 设置翻书的角度,实现3D效果
- 确定照片和阴影的位置,为其选择合适的大小 最后CSS就被我们完成啦~代码如下:
.book {
width: 300px;
height: 300px;
position: absolute;
left: 50%;
margin-left: -150px;
top: 50%;
margin-top: -150px;
cursor: pointer;
user-select: none;
transform: rotateX(30deg);
}
.page {
width: 300px;
height: 300px;
padding: 1em;
position: absolute;
left: 0;
top: 0;
text-indent: 2em;
}
.front {
background-color: rgba(255, 192, 203, 0.8);
}
.back {
background-color: #fff;
}
.front-cover {
transform-origin: 0 50%;
transform: rotateY(-120deg);
}
.p3d {
transform-style: preserve-3d;
}
.front-cover .back {
background-image: url(https://bpic.588ku.com/element_origin_min_pic/19/03/07/559240eabf65606beca294556a46533b.jpg);
background-size: cover;
transform: translateZ(3px);
}
.flip {
transform: rotateY(180deg);
}
.shadow,
.pic {
width: 196px;
height: 132px;
position: absolute;
left: 60px;
top: 60px;
transform-origin: 0 100%;
}
.pic {
width: 200px;
height: 150px;
background: url(https://th.bing.com/th/id/OIP.G4dqo6KprE77GL5J7tGeGwHaKv?w=192&h=279&c=7&r=0&o=5&dpr=2&pid=1.7);
background-size: cover;
}
.shadow {
background-color: rgba(0, 0, 0, 0.5);
}
这里面有些代码是值得我们注意的,他们在其中有着重要的作用~
控制元素的位置:
left: 50%和margin-left: -150px将这本书居中于屏幕水平方向,因为元素的平移是基于左边框的,其中没有考虑到元素原本的宽度,而margin-left: -150px能起到让元素远离边框的效果使其居中;同样地,top: 50%和margin-top: -150px将其居中于屏幕垂直方向。- 绝对定位
position: absolute;:使得元素以父容器position:absolute或者position:relative为基准定位自身
- transform的rotate,scale,skew,translate四种方式
- 3D 旋转 (rotateX, rotateY, rotateZ)
- 3D 缩放 (scaleX, scaleY, scaleZ)
- 3D 倾斜 (skewX, skewY)
- 3D 移动 (translateX, translateY, translateZ)
这四种方式对元素的控制十分灵活,我们要烂熟于心
transform-origin: 0 50%;这个值意味着变形原点被设置在元素的左侧(X轴上的起始位置,即0%的位置)和垂直中心(Y轴上的50%位置)元素会围绕其左侧和垂直中心这个点进行旋转。cursor: pointer;是一个CSS样式属性,用于改变鼠标指针在悬停在元素上时的外观。当这个样式被应用到一个元素上时,鼠标指针通常会变成一个表示可以点击的手形图标以此向用户暗示这个元素是可以交互的user-select: none;不允许文本被复制text-indent: 2em;用于设置文本内容的第一行的缩进。em是一个相对单位,通常等于当前元素的字体尺寸。transform-style: preserve-3d;他的作用是能保持3D空间正确的3D变换层次,与perspective和perspective-origin属性一起使用时,preserve-3d可以确保元素在3D空间中具有正确的透视效果。
三.JS:让你的书动起来
JS部分往往是最重要的部分,只有它能赋予我们动画灵魂
要打开这本书,需要我们监听两个事件1.用户的鼠标是否按住2.用户的鼠标是否移动。用户按住鼠标时,向左拖拽书才能打开,这里首先就要用到onmousemove来监听鼠标的动向,onmousedown来监听鼠标是否按下。我们可以设置:当用户鼠标没有按住onmouseup时事件为false,按住时为true(利用开关变量开监听鼠标的状态);当用户按下鼠标向左移动(x坐标减小)时,书被打开。ok,让我们开始
- 首先设置鼠标事件hold为false
- 可以用标签选择器
querySelector获取你的书本 - 构造一个函数来监听鼠标是否按下
- 构造一个函数来监听鼠标是否在窗口移动
- 满足‘按下’和‘x轴坐标减小’时,书才被打开
// 鼠标摁住事件
// 鼠标移动事件
var hold = false
var page = document.querySelector('.front-cover')
var clamp = function(val, min, max) {
return Math.max(min, Math.min(val, max))
}
page.onmousedown = function () {
hold = true
}
window.onmouseup = function () {
hold = false
}
window.onmousemove = function(e) { // 摁住才能执行
if (hold == true) {
console.log(e.pageX);
var angle = clamp((window.innerWidth / 2 - e.pageX + 300) / 300 * -90, -180, 0)
page.style.transform = `rotateY(${angle}deg)`
}
}
我们注意这个函数:
var clamp = function(val, min, max) {
return Math.max(min, Math.min(val, max))
}
clamp 函数的工作方式是:
- 使用
Math.min(val, max)来找出val和max之间的较小值。这一步确保val不会大于max。 - 使用
Math.max(min, ...)来找出上一步得到的结果和min之间的较大值。这一步确保最终的结果不会小于min。
这样,clamp 函数就确保了返回的值总是在 [min, max] 范围内。
clamp 函数被用于计算旋转的角度,确保角度值在 -180 到 0 度之间。这是通过 (window.innerWidth / 2 - e.pageX + 300) / 300 * -90 计算出初始角度后,再应用 clamp 函数来实现的。这样做有助于避免因为鼠标位置过于极端而导致的旋转角度过大,从而保持动画或视觉效果在可控的范围内。
以此类推,我们可以让书里面的照片立起来,让书里面的照片立起来时影子随之歪斜。
首先拿到照片和影子的类名
var pic = document.querySelector('.pic')
var shadow = document.querySelector('.shadow')
计算出合适的角度后放进函数中的if语句中行使功能,要注意他们是绕什么轴旋转或者偏移的,同时也要明白这里的${}是一个嵌入在模板字符串中的表达式。大括号{}用来包裹这个表达式,这样JavaScript引擎才会知道需要对这部分代码进行求值
pic.style.transform = `rotateX(${angle / 3}deg)`
shadow.style.transform = `skewX(${angle/8})`
结尾
大功告成!快去表白你的男神女神吧!