前言
對於js全景圖嚮往已久,貌似從16年開始看到的。當時自己還是一個小菜雞(雖然現在也不是大佬),由於工作原因前端的很多方面都沒有及時瞭解,現在惡補中。。。
準備工作
瞭解transform中的一些基本概念,比如:
rotate 旋轉
translate 定義 2D 轉換
translateZ 定義 3D 轉換
perspective 為 3D 轉換元素定義透視檢視。
transform-style: preserve-3d; 指定子元素定位在三維空間內。另外,該屬性是非繼承的。
要開始講咯~
有一個立方體的demo放在我的github中,如圖:
立方體原理
立方體我們大家都知道,是由六個的正方形組成的正多面體。如下圖:
全景圖
這裡我們用全景圖來舉例,幫助我們理解perspective和translateZ。
全景圖的組成方式有兩種,分別是 立方體、球體(稜柱),我們這裡使用的是立方體來舉例。
這裡我還沒有搞明白球體和稜柱的區別, 所以等我理解以後,我們們後面再說
製作立方體
一、製作6個面
因為立方體是由6個正方形組成,所以我們先來製作它的組成部分,最後再進行組裝。
我們這裡用face來當做面,而top、bottom、left、right、after、first來分別代表上、下、左、右、前、後幾個面。
這裡我們的視角正對著first
我們定義了一個視窗stage、透視盒子ctx 和 立方體容器facelist。
我們先將視窗定義為800*800相對頁面垂直居中
我們先將立方體定義為寬高為800px; 接下來將每個面的寬高也定義為800px, 並給予每個面一個不同的顏色用以區分。
程式碼如下:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>立方體全景</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
.stage {
width: 800px;
height: 800px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.face {
width: 800px;
height: 800px;
}
.top {
background: green;
}
.bottom {
background: yellow;
}
.after {
background: red;
}
.left {
background: black;
}
.right {
background: blue;
}
.first {
background: blueviolet;
}
</style>
</head>
<body>
<div class='stage'>
<div class='ctx'>
<div class='facelist'>
<div class='face top'>1</div>
<div class='face bottom'>2</div>
<div class='face after'>3</div>
<div class='face left'>4</div>
<div class='face right'>5</div>
<div class='face first'>6</div>
</div>
</div>
</div>
<script>
</script>
</body>
</html>
複製程式碼
二、組合
到這裡我們立方體的6個面製作完成,但是他們是一次排列在頁面中,並不是我們想要的;
接下來讓我們將他們先放在一起。給face新增position: absolute;
這樣他們是重合在一起的,我們需要這樣操作:
1. 把它們旋轉到對應的角度
比如:
.top的面我們將它繞X軸旋轉90度;
.left的面我們將它繞Y軸旋轉90度;
···
複製程式碼
圖片摘自思否
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>立方體全景</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
.stage {
width: 800px;
height: 800px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.face {
width: 800px;
height: 800px;
position: absolute;
}
.top {
background: green;
transform: rotateX(90deg);
}
.bottom {
background: yellow;
transform: rotateX(90deg);
}
.after {
background: red;
transform: rotateX(0deg);
}
.left {
background: black;
transform: rotateY(90deg);
}
.right {
background: blue;
transform: rotateY(90deg);
}
.first {
background: blueviolet;
transform: rotateY(0deg);
}
</style>
</head>
<body>
<div class='stage'>
<div class='ctx'>
<div class='facelist'>
<div class='face top'>1</div>
<div class='face bottom'>2</div>
<div class='face after'>3</div>
<div class='face left'>4</div>
<div class='face right'>5</div>
<div class='face first'>6</div>
</div>
</div>
</div>
<script>
</script>
</body>
</html>
複製程式碼
旋轉後的圖形 應該是這樣的
這樣看起來好像什麼都沒有變化,我們來看看這個圖:
把每個面都重疊在黑色的原點就是他的實際模樣,也就是說現在還不是一個立方體
因為他們的中心都是重合的,如何將它們變成立方體呢?看下面的步驟
2. 將他們按照對應的邊長通過translateZ推開
由於我們這裡是立方體,所以直接就是正方形的邊長 在這裡也就是±400px
給它們設定上對應的translateZ值,讓多個面往不同方向平移,直到組成一個完整的立方體。
複製程式碼
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>立方體全景</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
.stage {
width: 800px;
height: 800px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.face {
width: 800px;
height: 800px;
position: absolute;
}
.top {
background: green;
transform: rotateX(90deg) translateZ(400px);
}
.bottom {
background: yellow;
transform: rotateX(90deg) translateZ(-400px);
}
.after {
background: red;
transform: rotateX(0deg) translateZ(-400px);
}
.left {
background: black;
transform: rotateY(90deg) translateZ(-400px);
}
.right {
background: blue;
transform: rotateY(90deg) translateZ(400px);
}
.first {
background: blueviolet;
transform: rotateY(0deg) translateZ(400px);
}
</style>
</head>
<body>
<div class='stage'>
<div class='ctx'>
<div class='facelist'>
<div class='face top'>1</div>
<div class='face bottom'>2</div>
<div class='face after'>3</div>
<div class='face left'>4</div>
<div class='face right'>5</div>
<div class='face first'>6</div>
</div>
</div>
</div>
<script>
</script>
</body>
</html>
複製程式碼
3. 加上3D效果
我們給ctx盒子加上3D屬性 讓3D變得立體化
···
.ctx {
/* 3d視角 */
transform-style: preserve-3d;
}
···
複製程式碼
4.將我們的視角推到中心點
先調整stage的視距,將我們的眼睛(視角)調整到ctx的first面的位置
這個時候我們距離after面有800px的距離 離ctx的面有400px的距離
然後我們將ctx這個透視盒子向外推1/2width的距離 也就是400px,將我們的眼睛(視角)置於中心
不理解的童鞋 請注意看下面的單獨講解;
.stage {
width: 800px;
height: 800px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* 從何處(哪裡)檢視一個元素的角度 */
/* 從當前視角到對應面的距離 在這裡是 stage到ctx的距離 */
perspective: 400px;
/* 調整角度 */
/* perspective-origin: 50% 100%; */
}
.ctx {
/* 3d視角 */
transform-style: preserve-3d;
/* 把視角推到中心 */
transform: translateZ(400px) rotateY(0deg);
}
複製程式碼
三、完事
這樣我們已經將一個3D立方體做出來了 並且把我們的視角放在了這個立方體內部的中心點。
我們可以通過 改變 perspective-origin 的值來觀察整個立方體
調整角度,在不同角度看到的立方體,有助於更快的理解perspective。
單獨講解perspective和translateZ
我呢找到了一個幫助我理解的圖片:
這裡Z指的就是 translateZ ,d指的是 perspective
這裡我們要知道,Z軸向外為正值。
所以總結下就是:
- perspective是指 從當前視角到所看平面的距離
- translateZ指的是 從所看平面到推進視角之間的距離,大白話就是從當前距離 把你看的拉進或者拉遠的距離
- 人的視角在3D投影效果中是 近大遠小
重中之重
理解 近大遠小 和 眼睛與平面的透視關係 也就是上面那張圖!!!
結語
這些東西對於初學css 3D的人來說可能理解起來比較吃力;
對於大部分人來說,其實只靠讀文章是不可能完全理解的;
所以還有一句名言警句送給大家:
實踐是檢驗真理的唯一標準
希望大家可以一直以實踐為主、閱讀為輔,自己真正理解的才是自己的。謝謝!