前言
小白实战🔥--实现3D-OpenBook
今天我们来学习如何实现这样的一个效果!
正文
我们要实现这样的一个效果!!
我们需要在我们的文件夹中新建三个文件:html
文件,css
文件,js
文件
编写html
文件
html
<!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="front-cover p3d">
<div class="inside page p3d flip">
<p>我是JSsolder the most beautiful being in my life. Whenever I see your smile, my heart will melt into tenderness. Your eyes are as bright as the starry sky, and every time you look at me, you seem to inject love into me. Your tenderness and thoughtfulness make me feel endless happiness, and your company makes me feel that the world is full of infinite possibilities. Whether it is wind, rain or sunshine, I am willing to hold your hand and walk through every beautiful moment with you.</p>
</div>
<div class="outside page"></div>
</div>
<div class="back-cover p3d">
<div class="outside page"></div>
<div class="inside page p3d">
<div class="shadow"></div>
<div class="card"></div>
</div>
</div>
</div>
<script src="./index.js"></script>
</body>
</html>
我们的html
文件实现这样一个布局,首先导入我们的css
文件和js
文件
定义一个book p3d
的容器将我们要实现的页面装进去!
里面放了front-cover p3d
实现字体的容器和outside page
实现书的外部的容器和inside page
书的内部的容器
我们还添加shadow
阴影和card
书里面的卡片。
编写css
文件
我们先上代码!再为大家逐步分析:
css
*{
margin: 0;
padding: 0;
border: 0;
/* 对齐方式 baseline基准线对齐 */
vertical-align: baseline;
/* 修改浏览器的渲染规则 */
/* 将容器声明成IE模型 */
box-sizing: border-box;
}
html{
height: 100%;
}
body{
/* vh可视窗口的高度 */
height: 100%;
/* Helvetica是个字体黑体 */
font:100%/1.25 Helvetica,arial,sans-serif;
/* 透视图 仿3D */
perspective: 1000px;
background-color: #75d8f1;
/* 线性渐变 */
background-image: linear-gradient(to bottom, #62f3f0, #fa01e9);
}
.p3d{
/* 设置3d效果,以3d的视锥查看 */
transform-style: preserve-3d;
}
.book{
width: 300px;
height: 300px;
position: absolute;
left: 50%;
top: 50%;
/* transform: translateY(-150px); */
margin-top: -150px;
color: #fff;
/* 文字相关的css属性都是可以继承的 */
/* 对着x轴进行旋转*/
transform: rotateX(60deg);
/* -webkit前缀,谷歌内核,防止老版本的浏览器读不懂 */
/* -webkit-transform: rotateX(45deg); */
/* -moz前缀,火狐内核,防止老版本的浏览器读不懂 */
/* -moz-transform: rotateX(45deg); */
/* -o-欧朋浏览器 */
/* -o-transform: rotateX(45deg); */
/* 用户选择none,不准复制*/
user-select: none;
}
.front-cover{
/* 控制鼠标状态,move当鼠标挪上去的是一个十字架, */
cursor: move;
/* 旋转基点 x轴0,y轴50%*/
transform-origin:0 50%;
transform: rotateY(0deg);
}
.page{
width: 300px;
height: 300px;
/* em是相对单位,相对父容器的大小倍数的意思 */
padding: 1em;
/* 定位脱离文档流 */
position: absolute;
left: 0;
top: 0;
/* 2个字节,1em相当于父容器的一个字节 */
text-indent: 2em;
}
.inside{
background-color: #d93e2b;
}
.outside{
background-color: #efe9e9;
}
.front-cover .outside{
background-image:url(./da.png);
background-repeat: no-repeat;
background-size: cover;
transform: translateZ(3px);
}
.flip{
transform: rotateY(180deg);
}
.back-cover .outside{
transform: translateZ(-3px);
}
.back-cover .inside{
background-color: #d93e2b;
}
.card,
.shadow{
width: 196px;
height: 132px;
position: absolute;
left: 60px;
top: 60px;
transform-origin: 0 100%;
}
.shadow{
/* 黑色且是半透明状态 */
background-color: rgba(0,0,0,0.5);
}
.card{
transform-origin: 0 100%;
transform: rotateX(0deg);
background-image: url(./ada.png);
background-repeat: no-repeat;
background-size: cover;
}
在我们的css文件中:
-
我们首先定义全局
*{}
在全局中margin: 0;
:设置元素的边距为0,让元素的外边距与其包含块的外边距相接触。padding: 0;
:设置元素的内部填充为0,让元素的内容和边框之间没有空间。border: 0;
:设置元素的边框为0,让元素没有边框。vertical-align: baseline;
:设置元素的垂直对齐方式为基线对齐。元素按照其基线对齐,基线是文本的底部线。box-sizing: border-box;
:将容器的 box-sizing 属性设置为 border-box。元素的内边距和边框不会增加元素本身的宽度。在某些情况下,这可以简化布局和计算尺寸。修改浏览器的渲染规则 , 将容器声明成IE模型
-
定义我们
html
和body
首先,在
html
我们设置高度为100%,让页面充满整个屏幕在
body
中,我们也将高度设为100%,font:100%/1.25 Helvetica,arial,sans-serif;
其中100%
表示使用父元素的字体大小,而1.25
是行高与字体大小的百分比,Helvetica,arial,sans-serif
是备选字体列表perspective: 1000px;
:这设置了 CSS 3D 变换的视角距离,影响 3D 效果的距离感。在这里,视角距离被设置为 1000px。background-color: #75d8f1;
和background-image: linear-gradient(to bottom, #62f3f0, #fa01e9);
:这两行代码分别设置了背景颜色和背景图片。背景颜色是一个单一的颜色,而背景图片则是一个从顶部到底部的线性渐变,由两个颜色值(#62f3f0 和 #fa01e9)定义。 -
p3d
在这里 我们 设置3d效果,以3d的视锥查看transform-style: preserve-3d;
-
book
中width: 300px;
:设置元素的宽度为 300 像素。height: 300px;
:设置元素的高度为 300 像素。position: absolute;
:将元素的位置设置为绝对定位,元素的位置将相对于最近的已定位祖先元素(而不是正常流),如果元素没有已定位的祖先元素,那么它的位置将相对于初始包含块。left: 50%;
:将元素的左边位置设置为父元素的50%,元素将位于父元素的垂直中心。top: 50%;
:将元素的顶部位置设置为父元素的50%,元素将位于父元素的水平中心。margin-top: -150px;
:这将元素的顶部外边距设置为负的150像素,使得元素"悬挂"在父元素的垂直中心,看起来像是被旋转了。color: #fff;
:设置元素的所有文本颜色为白色。transform: rotateX(60deg);
:这将元素沿着X轴旋转60度。这是一种3D转换,元素会在三维空间中进行旋转。user-select: none;
:这行代码防止用户选择或复制元素的内容。 -
.front-cover
:cursor: move;
:当鼠标悬停在该元素上时,鼠标的形状将变成一个十字架,表示该元素可拖动。transform-origin:0 50%;
:这定义了元素旋转的基点。在这里,基点被设置为在元素的中心(x轴为0,y轴为50%)。transform: rotateY(0deg);
:这会将元素沿Y轴旋转0度。由于默认值已经是0度,所以这行代码在这里并没有实际效果。
-
.page
width: 300px;
和height: 300px;
:这设置了 "page" 类元素的宽度和高度都为300像素。padding: 1em;
:这设置了元素的内边距为1em。em是一个相对单位,相对于其父元素的字体大小。position: absolute;
:这使得元素的位置脱离了文档流,可以相对于最近的已定位祖先元素(而不是正常的文档流)进行定位。在这里,元素的左和顶部都设置为0,它会停在父元素的左边或顶部。left: 0;
和top: 0;
:这设置了元素的左和顶部的位置都为0,它会停在父元素的左边或顶部。text-indent: 2em;
:这设置了元素的首行文本缩进2em。em是一个相对单位,相对于其父元素的字体大小。在这里,首行文本会比其他行文本偏移2倍的字体大小。
-
inside
和outside
我们为他们设置不同的背景色! -
front-cover .outside
background-image:url(./da.png);
:这里,我们导入自己的图片background-repeat: no-repeat;
:告诉浏览器不要重复元素的背景图像。background-size: cover;
:将背景图像的大小设置为覆盖整个元素。如果背景图像比元素大,它将被裁剪并填充元素。transform: translateZ(3px);
:应用一个2D转换效果,将元素沿着Z轴移动3像素。这种效果可以创建一种3D空间的效果,但不会影响元素的实际布局。
-
.flip
和.back-cover .outside
和.back-cover .inside
.flip{ transform: rotateY(180deg); }
:当应用于一个元素时,它将使该元素沿 Y 轴旋转 180 度。这种变换通常用于实现元素的翻转或旋转效果。.back-cover .outside{ transform: translateZ(-3px); }
:将元素沿 Z 轴向原点移动 -3px,这种变换可以创建一种深度偏移的效果,使元素看起来更加立体。.back-cover .inside{ background-color: #d93e2b; }
:将背景颜色设置为十六进制颜色代码 #d93e2b
-
shadow
我们在影子中width: 196px;
设置元素的宽度为196像素。height: 132px;
设置元素的高度为132像素。position: absolute;
设置元素的定位方式为绝对定位。left: 60px;
设置元素距离包含块的左边界为60像素。top: 60px;
设置元素距离包含块的顶边界为60像素。transform-origin: 0 100%;
设置元素的转换原点为元素的顶部(0%),并且其宽度延伸到整个元素background-color: rgba(0,0,0,0.5);
给我们的影子设置为黑色半透明
-
.card
transform-origin: 0 100%;
- 这个属性定义了元素进行变换(例如旋转、缩放等)时的原点。在这里,原点被设置为在元素的顶部(0%),也就是说,当你旋转这个元素时,它会围绕其顶部进行。transform: rotateX(0deg);
- 这个属性应用了一个2D旋转效果,但是在这里,它被设置为旋转X轴0度。。background-image: url(./ada.png);
- 在这里插入你自己的图像文件。background-repeat: no-repeat;
- 这个属性防止背景图像在水平和垂直方向上重复。background-size: cover;
- 这个属性确保背景图像完全覆盖整个元素。如果背景图像比元素大,它会被缩小以适应元素;如果背景图像比元素小,它会被复制(平铺)以填充元素的整个宽度或高度。
编写JS文件
首先,我们首先展示整个代码:
js
var front = document.getElementsByClassName('front-cover')[0]//byClassName默认以数组返回
var book = document.getElementsByClassName('book')[0]
var card = document.getElementsByClassName('card')[0]
var shadow = document.getElementsByClassName('shadow')[0]
var hold= false
var clamp = function(val,min,max){
return Math.max(min,Math.min(val,max))
}
//onmousedown监听鼠标是否点击,是否按下
front.onmousedown = function(){
hold = true
}
window.onmouseup=function(){
hold = false
}
window.onmousemove=function(e){
if(hold){
//修改左半本书的角度,卡片旋转,阴影倾斜
//鼠标在x轴移动的距离控制角度
var deg = clamp((window.innerWidth/2-e.x+300)/300 * -90,-180,0)
front.style.transform = `rotateY(${deg}deg)`
//整本书立起来60+deg/8
book.style.transform=`rotateX(${deg/8+60}deg)`
//卡片立起来deg/2
card.style.transform = `rotateX(${deg/2}deg)`
//阴影倾斜的角度deg/8
shadow.style.transform = `skew(${deg/8}deg)`
}
}
接下来,我们为大家分析我们的JS
代码是如何编写的!!!
我们在js
代码中的主要操作就是计算Book
旋转的角度!
首先,我们获取了页面上具有特定类名的元素:'front-cover'、'book'、'card'和'shadow'
然后,我们通过一个变量hold
来监听鼠标是否被按下,用一个函数clamp
来限制一个值在特定的最小值和最大值之间。
为front-cover
元素的onmousedown
事件设置了一个处理函数,当鼠标按下时,将hold
设置为true
。同时,当鼠标松开时,将hold
设置为false
。
为window
对象设置了onmousemove
事件处理函数。当鼠标移动时,如果hold
为true
(即鼠标被按下),则它会根据鼠标的移动距离来旋转和倾斜各个元素。
计算鼠标在x
轴移动的距离来计算整本书立起来的角度 和卡片立起来的角度 和阴影倾斜的角度
最后效果!!
完结撒花!!
这样我们的效果就实现啦!!
有想尝试的小伙伴可以直接拿着我的代码去体验一下!!!
只需要插入两张属于你自己的图片就可以啦!!
如果你有任何想法和指正欢迎评论区留言!!!
看到这里啦!点个赞鼓励支持一下吧!!!🌹🌹🌹