CSS3_3D变换和动画

3D坐标轴

前端中的3D坐标轴和我们印象中的有点不一样,我们可以这样记,屏幕水平(左右)方向为X轴,垂直(上下)方向为Y轴,面向穿过你自己为Z轴,我是这样记的,感觉比较好记

景深,舞台,灭点和景深基点

要在前端页面上实现3D效果,我们必须明确以下几个概念

景深(perspective):是指相机对焦点前后相对清晰的成像范围
太抽象了,简单的理解就是我们肉眼离显示器的距离,景深越大,元素离我们越近,效果越不好,景深作用于所有后代元素,并且景深会叠加

舞台(transform-style):应用景深的元素称为"舞台元素",舞台元素的所有后代元素都会受影响,作用在于营造有层级的3D舞台,不可继承

灭点:指的是立体图形两边的延伸线所产生的相交点,透视点的消失点。
百度的图片,看一下吧
在这里插入图片描述
我们只需要知道,景深越大,灭点越远,元素变形越不明显,反之亦然

景深基点(perspective-origin):用来控制视角的位置,简单来说就是你眼睛的位置

backface-visibility属性:用于设置元素背面是否为可见

3D变换

同2D的基本一致,就是多了一个Z轴的变换

  1. 3D旋转
    roateX(角度) rotateY() rotateZ()
    rotate3d(x,y,z) 按照原点到点(x,y,z)的射线转
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			html,body{
				height: 100%;
				overflow: hidden;
			}
			#wrap{
				width: 400px;
				height: 400px;
				border: 1px solid;
				position: absolute;
				left: 50%;
				top: 50%;
				margin-top: -200px;
				margin-left: -200px;
				perspective: 120px;
			}
			#inner{
				width: 200px;
				height: 200px;
				background: pink;
				border: 1px solid;
				border-radius: 50%;
				position: absolute;
				left: 50%;
				top: 50%;
				margin-top: -100px;
				margin-left: -100px;
				text-align: center;
				font: 30px/200px "微软雅黑";
				transition: 2s;
			}
			#wrap:hover>#inner{
				/* transform: rotateY(360deg); */
				transform: rotate3d(1,1,1,360deg);
			}
		</style>
	</head>
	<body>
		<div id="wrap">
			<div id="inner">
			月下Ctrlc
		</div>
		</div>
	</body>
</html>

  1. 3D平移
    translateX() translateY() translateZ()
    translate3d(x,y,z) z轴上偏移量不能写百分比,因为元素没有厚度
    例子 就在上面那个例子的基础上改就行了
  2. 3D缩放
    scaleZ() 意义在影响Z轴上的平移,一个东西离你近了看起来就大了
    scaleZ(2) translateZ(100px) 就相当于 translateZ(200px)
    scale3d(x,y,z)
    例子自己对应修改吧

3D实例

  1. 立方体(第一种实现)
    先展开,后旋转
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			#wrap{
				width: 400px;
				height: 400px;
				position: absolute;
				top: 0;
				right: 0;
				bottom: 0;
				left: 0;
				margin: auto;
				border: 1px solid;
				perspective: 100px;
				transform-style: preserve-3d;
			}
			#wrap>.box{
				width: 100px;
				height: 100px;
				position: absolute;
				left: 50%;
				top: 50%;
				margin-top: -50px;
				margin-left: -50px;
				text-align: center;
				font: 50px/100px "微软雅黑";
				transform-style: preserve-3d;
				transform-origin: center center -50px;
				transition: 3s;
			}
			#wrap>.box>div{
				width: 100px;
				height: 100px;
				background: pink;
				position: absolute;
				border-radius: 50%;
			}
			#wrap>.box>div:nth-child(5){
				top: -100px;
				transform-origin: bottom;
				transform: rotateX(90deg);
			}
			#wrap>.box>div:nth-child(6){
				bottom: -100px;
				transform-origin: top;
				transform: rotateX(-90deg);
			}
			#wrap>.box>div:nth-child(3){
				left: -100px;
				transform-origin: right;
				transform: rotateY(-90deg);
			}
			#wrap>.box>div:nth-child(4){
				right: -100px;
				transform-origin: left;
				transform: rotateY(90deg);
			}
			#wrap>.box>div:nth-child(2){
				transform: translateZ(-100px) rotateX(180deg);
			}
			#wrap>.box>div:nth-child(1){
				z-index: 1;
			}
			#wrap:hover>.box{
				transform: rotateX(360deg);
			}
		</style>
	</head>
	<body>
		<div id="wrap">
			<div class="box">
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
			</div>
		</div>
	</body>
</html>

  1. 立方体(第二种实现)
    直接旋转
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			#wrap{
				width: 400px;
				height: 400px;
				position: absolute;
				top: 0;
				right: 0;
				bottom: 0;
				left: 0;
				margin: auto;
				border: 1px solid;
				perspective: 100px;
			}
			#wrap>.box{
				width: 100px;
				height: 100px;
				position: absolute;
				left: 50%;
				top: 50%;
				margin-top: -50px;
				margin-left: -50px;
				text-align: center;
				font: 50px/100px "微软雅黑";
				transform-style: preserve-3d;
				transform-origin: center center -50px;
				transition: 3s;
			}
			#wrap>.box>div{
				width: 100px;
				height: 100px;
				background: pink;
				position: absolute;
				transform-origin: center center -50px;
				/* 设置背面为不可见 */
				backface-visibility: hidden;
			}
			#wrap>.box>div:nth-child(5){
				transform: rotateX(90deg);
			}
			#wrap>.box>div:nth-child(6){
				transform: rotateX(270deg);
			}
			#wrap>.box>div:nth-child(4){
				transform: rotateY(90deg);
			}
			#wrap>.box>div:nth-child(3){
				transform: rotateY(270deg);
			}
			#wrap>.box>div:nth-child(2){
				transform: rotateY(180deg) rotate(180deg);
			}
			#wrap>.box>div:nth-child(1){
				
			}
			#wrap:hover>.box{
				transform: rotateX(360deg);
			}
		</style>
	</head>
	<body>
		<div id="wrap">
			<div class="box">
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
				<div></div>
			</div>
		</div>
	</body>
</html>
  1. 多棱柱(封装成函数)
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			html,body{
				height: 100%;
				overflow: hidden;
			}
			#wrap{
				width: 400px;
				height: 400px;
				position: absolute;
				top: 0;
				right: 0;
				bottom: 0;
				left: 0;
				margin: auto;
				border: 1px solid;
				perspective: 500px;
			}
			#wrap>.box{
				/* 这里可以改变宽度,获取不同宽度的棱柱 */
				/* 记得下面的居中也要改一下 */
				width: 300px;
				height: 300px;
				position: absolute;
				left: 50%;
				top: 50%;
				margin-top: -150px;
				margin-left: -150px;
				text-align: center;
				font: 50px/300px "微软雅黑";
				transform-style: preserve-3d;
				/* 过渡只给transform,不然基点也会过渡,出现不好的效果,打你脸上 */
				transition: transform 3s;
			}
			#wrap>.box>div{
				width: 100%;
				height: 100%;
				background: pink;
				position: absolute;
				/* 设置背面为不可见 */
				backface-visibility: hidden;
			}
			#wrap:hover>.box{
				transform: rotateY(360deg);
			}
		</style>
	</head>
	<body>
		<div id="wrap">
			<div class="box"></div>
		</div>
	</body>
	<script type="text/javascript">
		window.onload = function(){
			createLZ(10);
		}
		function createLZ(n){
			var boxNode = document.querySelector("#wrap>.box");
			var styleNode = document.createElement("style");
			var degOut = 360 / n;         //外角
			var degIn = 180 - 360/n;      //内角
			var length = boxNode.offsetWidth;
			var divHTML = "";
			var cssHTML = "";
			for(let i = 0; i < n; i++){
				divHTML += `<div>${i+1}</div>`;
				cssHTML += `#wrap>.box>div:nth-child(${i+1}){transform: rotateY(${i*degOut}deg)}`;
			}
			cssHTML += `#wrap>.box{transform-origin: center center ${-(length/2)*Math.tan(degIn*Math.PI/360)}px;}`;
			cssHTML += `#wrap>.box>div{transform-origin: center center ${-(length/2)*Math.tan(degIn*Math.PI/360)}px;}`;
			boxNode.innerHTML = divHTML;
			styleNode.innerHTML = cssHTML;
			document.head.appendChild(styleNode);
		}
	</script>
</html>

动画

  1. API
    1.1 动画内的属性
    animation-name 指定动画的名称,默认值为none,表示无关键帧
    animation-duration 指定一个动画的执行周期,默认为0,负值无效,低版本的浏览器会将负值解析为0
    animation-timing-function 运动形式,可以指定贝塞尔函数,我讲不清楚,大家自己百度吧,贝赛尔
    animation-direction 运动的方向,指定参数为reverse的时候,反转的是关键帧和运动形式

  2. 动画外的属性
    2.1 animation-delay:指定动画开始之前的延迟

  3. imation-iteration-count 指定动画的执行次数,动画内的范畴,不影响动画外的属性,重复的是关键帧

  4. animation-fill-mode 确定元素在动画外的状态
    动画外的状态指的是from之前to之后
    参数:
    backwards from之前的状态与from的状态保持一致
    forwards to之后的状态与to的状态保持一致
    both backwards和forwards两者加起来的效果

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			#wrap{
				position: absolute;
				width: 300px;
				height: 300px;
				border: 1px solid;
				top: 0;
				right: 0;
				bottom: 0;
				left: 0;
				margin: auto;
			}
			#wrap>.inner{
				position: absolute;
				left: 50%;
				top: 50%;
				margin-left: -50px;
				margin-top: -50px;
				height: 100px;
				width: 100px;
				background: pink;
				text-align: center;
				font: 20px/100px "微软雅黑";
				
				
				animation-name: move;
				animation-duration: 2s;
				animation-timing-function: linear;
				animation-direction: normal;
				animation-delay: 3s;
				animation-iteration-count: 3;
				
				/* 确定元素在动画外的状态 */
				/* 动画外的状态指的是from之前to之后 */
				/* 
				 backwards: from之前的状态与form的状态保持一致
				 forwards: to之后的状态与to的状态保持一致
				 both: 两者都保持
				 */
				animation-fill-mode: both;
			}
			
			@keyframes move{
				from{transform: translateY(-100px);}
				to{transform: translateY(100px);}
			}
			#wrap:hover>.inner{
				animation-play-state: paused;
			}
		</style>
	</head>
	<body> 
	  <div id="wrap">
	  	<div class="inner">
	  		月下Ctrlc
	  	</div>
	  </div>
	</body>
</html>
  1. 关键帧 (定义动画的形式)
    @keyframes animationName {
    keyframes-selector {
    CSS-style;
    }
    }
    animationName 定义动画的名称 必须写
    keyframes-selector 必须写,动画持续时间的百分比 from(0%) to(100%)
    CSS-style CSS声明
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			#wrap{
				position: absolute;
				width: 300px;
				height: 300px;
				border: 1px solid;
				top: 0;
				right: 0;
				bottom: 0;
				left: 0;
				margin: auto;
			}
			#wrap>.inner{
				position: absolute;
				left: 50%;
				top: 50%;
				margin-left: -50px;
				margin-top: -50px;
				height: 100px;
				width: 100px;
				background: pink;
				text-align: center;
				font: 20px/100px "微软雅黑";
				
				
				animation-name: move;
				animation-duration: 4s;
				animation-timing-function: ease-in;
				animation-direction: alternate;
				animation-delay: 2s;
				animation-iteration-count: 3;
				animation-fill-mode: both;
			}
			
			@keyframes move{
				/* 百分比平分的是动画执行一次的周期animation-duration */
				/* 运动形式animation-timing-function体现在每个区间 */
				/* ease-in就表示没0~25,25~50等区间都是采用ease-in的运动形式 */
				0%{transform: translateY(-100px);}
				25%{transform: translateY(-50px);}
				50%{transform: translateY(0px);}
				100%{transform: translateY(50px);}
			}
			#wrap:hover>.inner{
				animation-play-state: paused;
			}
		</style>
	</head>
	<body> 
	  <div id="wrap">
	  	<div class="inner">
	  		月下Ctrlc
	  	</div>
	  </div>
	</body>
</html>
  1. 应用
    兔斯基(图片轮播)
    在这里插入图片描述
    使用动画依次从左到右依次展示图片,因为视觉暂留的原理,看起来就是动画
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			*{
				margin: 0;
				padding: 0;
			}
			html,body{
				height: 100%;
				overflow: hidden;
			}
			#tsj{
				position: absolute;
				left: 50%;
				top: 50%;
				transform: translate(-50%,-50%);
				width: 48px;
				height: 48px;
				background: url(01_3D&动画/img/animation.png) no-repeat;
				/* start看不见第一帧,end看不见最后一帧 */
				animation: move .8s steps(12,end) infinite;
			}
			@keyframes move{
				from{background-position: 0 0;}
				to{background-position: -576px 0;}
			}
		</style>
	</head>
	<body>
		<div id="tsj">
			
		</div>
	</body>
</html>

开机动画(上下跳动的文字,延迟设为不同便可实现)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<!-- 移动端开发记得加这个标签 -->
		<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			html,body{
				height: 100%;
				overflow: hidden;
			}
			#wrap{
				height: 100%;
				background: black;
				position: relative;
			}
			#wrap>.inner{
				position: absolute;
				left: 50%;
				top: 50%;
				transform: translate(-50%,-50%);
				white-space: nowrap;
			}
			#wrap>.inner>span{
				position: relative;
				/* animation: jump 1s linear infinite alternate; */
			}
			@keyframes jump{
				from{top: 0px}
				to{top: -12px;}
			}
		</style>
	</head>
	<body>
		<div id="wrap">
			<div class="inner">
				<span></span>
				<span></span>
				<span></span>
				<span></span>
				<span></span>
				<span></span>
				<span></span>
				<span></span>
				<span></span>
				<span></span>
				<span></span>
				<span></span>
				<span></span>
				<span></span>
			</div>
		</div>
	</body>
	<script type="text/javascript">
		window.onload = function(){
			var spanNodes = document.querySelectorAll("#wrap>.inner>span");
			var colors = ['red','orange','yellow','green','blue','pink','purple','red','orange','yellow','green','blue','pink','purple'];
			for(let i = 0; i < spanNodes.length; i++){
				spanNodes[i].style.animation = `jump .3s ${i*50}ms linear infinite alternate`;
				spanNodes[i].style.color = colors[i];
			}
		}
	</script>
</html>

开机动画(3D版本)
data.js里面都是本地图片的地址
在这里插入图片描述

在这里插入图片描述
网络在谷歌浏览器上切换
在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			html,body{
				height: 100%;
				overflow: hidden;
			}
			#wrap{
				height: 100%;
				position: relative;
				perspective: 200px;
			}
			#wrap>.inner{
				position: relative;
				left: 50%;
				top: 50%;
				transform: translate(-50%,-50%);
				transform-style: preserve-3d;
			}
			#wrap>.inner>img{
				width: 30%;
				margin-top: -45px;
				animation: xuanzhuan 2s linear infinite;
			}
			#wrap>.inner>img,#wrap>.inner>p{
				position: absolute;
				left: 50%;
				top: 50%;
				transform: translate(-50%,-50%) rotateY(0deg);
			}
			@keyframes xuanzhuan{
				from{transform: translate(-50%,-50%) rotateY(0deg);}
				to{transform: translate(-50%,-50%) rotateY(360deg);}
			}
		</style>
	</head>
	<body>
		<div id="wrap">
			<div class="inner">
				<img src="img/load/logo3.png" >
				<p>已加载0%</p>
			</div>
		</div>
	</body>
	<script src="js/data.js" type="text/javascript" charset="utf-8"></script>
	<script type="text/javascript">
		window.onload = function(){
			var arr = [];
			var flag = 0;
			var pNode = document.querySelector("#wrap>.inner>p");
			//获取所有的图片地址链接数组
			for(item in imgData){
				arr = arr.concat(imgData[item]);
			}
			//模拟发ajax请求获取数据
			//因为图片都在本地
			//所以将浏览器Network conditions调为slow 3G 观看 效果才明显
			for(let i = 0; i < arr.length; i++){
				var img = new Image();
				img.src = arr[i];
				img.onload = function(){
					flag++;
					pNode.innerHTML = `已加载${Math.round(flag/arr.length*100)}%`;
				}
				img.onerror = function(){
					console.log("加载失败!");
				}
			}
			// console.log(arr);
		}
	</script>
</html>

好了,我的分享就到这里了,谢谢大家

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值