目录
前言
本文将带大家来实现一个非常有趣的案例——打开书本效果。我们平常冲浪时是不是看过一些学校高级的录取通知书,翻开通知书就能看见里面的内容,呈现出逼真的3D效果!
先来看效果图:
思路准备
- 把这本书看成是2个容器组成——左半本书和右半本书,左半本书有外表面和内表面,右半本书也有自己的内表面和外表面,相当于两个小矩形。
- 当鼠标点击书本向左移动时实现翻开效果,也就是只有左半本书可以翻动——绕着y轴旋转。
- 同时右半本书的卡片会竖起来,阴影也会随之倾斜,整本书也会旋转一定角度。
正文
一、CSS实现
1、搭建基本框架
首先是一本书,用class="book"
的容器装全部,里面分右半本书和左半本书——分别用class="back-cover"
、class="front-cover"
的div容器表示。右半本书分内壳和外壳——class="page front"
、class="page back"
,同理左半本书也分内壳和外壳,也分别用相同类名。右半本书中放卡片和阴影,分别用class="shadow"、class="card"
的div装。而左半本书内壳放一些文字,为了方便,给一些盒子加上公共类名。具体如下:
<div class="book p3d"> <!-- 右半本 --> <div class="back-cover p3d"> <div class="page back flip"></div> <div class="page front p3d"> <div class="shadow"></div> <div class="card"></div> </div> </div> <!-- 左半本 --> <div class="front-cover p3d"> <div class="page front flip p3d"> <p>Solutions to over 1000 popular algorithm problems. All problems are from leetcode.com. Solutions include: - Problem statement - Python code with comments - Description of solution s trategy - Time and space complexity Does not require internet connection. Forward solutions by email. Please let me have your comments, correctio…</p> </div> <div class="page back"></div> </div> </div>
2、编写CSS
1)设置背景颜色,实现渐变效果。
body { height: 100%; font: 100%/1.25 Arial, Helvetica, sans-serif;//字体类型 color: #fff; perspective: 1000px; //必不可少! background: #444; background-image: linear-gradient(to bottom, #444, #999); }
tips: perspective——定义了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果,值越大看到的东西越小,不设置看不出translateZ轴移动的近大远小的感觉。perspective-origin——相当于人的眼睛看哪里,默认是父元素中间地方。这两个属性都是设置在父元素身上。
2)设置最外层容器book的样式:宽高设置具体值并使它们在屏幕中间显示——主要利用定位position:absolute
实现,top、left的值都为50%,再让它们的左外边距和上外边距为自身宽高的负一半可以实现垂直居中显示。
.book { width: 300px; height: 300px; position: absolute; top: 50%; left: 50%; margin-top: -150px; margin-left: -150px; }
3)设置左半本书和右半本书里面的页面的宽高——和书一样大小,并利用定位——脱离文档流,让这些页面在同一个位置,同时设置内壳背景色为红色,外壳为白色(方便放背景图),让左半本书绕着Y轴旋转。同时设置3D立体效果
.book .page { width: 300px; height: 300px; padding: 1em; position: absolute; left: 0; top: 0; text-indent: 2em; } .book .front { background-color: #d93e2b; } .book .back { background-color: #fff; } .book .front-cover { cursor: move; //鼠标放上去呈十字架形状 transform-origin: 0 50%; //transform:rotateY(-160deg) //可以利用这个看看旋转的效果 } .p3d { transform-style: preserve-3d; }
4)设置左半本书外层的封面以及右半书的外壳向Z轴平移(解决书的外层布局)
.book .front-cover .back { background-image: url("https://preview.qiantucdn.com/58pic/35/01/38/55A58PICaUy8sV83Dd78m_PIC2018.jpg%21w1024_new_3072"); background-repeat: no-repeat; background-size: cover; transform: translateZ(3px); } .book .back-cover .back { transform: translateZ(-3px); }
5)此时你会发现里面的文字反了,解决办法是让那页反着的页面旋转180度就能正常了。到此为止左半本就完成了!
.book .flip { transform: rotateY(180deg); }
6)设置右半本书的竖起来的卡片和倒影的位置、大小、颜色,起初两者重叠。
.book .shadow, .book .card { width: 196px; height: 132px; position: absolute; top: 60px; left: 60px; transform-origin: 0 100%; //设置旋转起点 } .book .card { background: url("https://preview.qiantucdn.com/58pic/35/01/38/55A58PICaUy8sV83Dd78m_PIC2018.jpg%21w1024_new_3072"); background-size: cover; } .book .shadow { background-color: rgba(0,0,0,0.5); }
二、JS实现
1)引入js文件到html中
<script src="./index.js"></script>
2)获取到需要的元素。先拿到整本书,再拿到左半本书、卡片、阴影.
let book=document.querySelector('.book'), leftPage=document.querySelector('.front-cover'), card=document.querySelector('.card'), shadow=document.querySelector('.shadow')
3)鼠标点击到前半本书移动时开始触发监听事件,可以再window身上设置
window.onmousemove = function(event){}
4)用一个变量表示鼠标的状态是点击、移动还是松开,类似于一个开关变量。默认是松开状态。
let hold=false //鼠标是按住的状态 leftPage.onmousedown=function(){ hold=true } window.addEventListener('mouseup',function(){ //鼠标不一定在page身上松开可能在其他地方松开,所以在window身上设置监听事件 hold=false })
5)设置移动事件。监听此时鼠标按下去的那一刻点的X坐标以及移动中的X轴上的变化,从而设置一个合理的值,让它绕Y轴旋转。让书、前半本书、卡片、阴影都能旋转移动角度。
window.onmousemove = function(event){ if(hold){ console.log(event.pageX); var angle= clamp((window.innerWidth/2 - event.pageX + 300)/300* -90,-180,0) //300为书的宽度 //该angle公式中的值不固定,可以设置其他 // leftPage.style.transform='rotate('+angle+'deg)' leftPage.style.transform=`rotateY(${angle}deg)` card.style.transform=`rotateX(${angle/2}deg)` shadow.style.transform=`skewX(${angle/10}deg)` book.style.transform=`rotateX(${60+angle/8}deg)` } }
tips:
- clamp函数中——min:-180deg,max:0deg,中间值:(window.innerWidth/2 - event.pageX + 300)/300* -90。总之这样设置是为了旋转角度比较契合,你也可以设置其他值。该值是在-180~0之间
skewX()
:指定对象绕X轴斜切扭曲。- 这些旋转的角度都可以设置其他值,不过得设置的比较符合。
6)设置给定3个值中取中间值的函数
let clamp=function(val,min,max) { return Math.max(min,Math.min(val,max)) }
到此为止,动态翻书效果案例结束啦!有没有觉得一种恍然大悟的感觉!说不定以后会用上哟!
完整代码可以点击js/OPENBOOK · nry/first_demo这里下载哟!