「CSS 3D 專題」搞懂 CSS 3D,你必須理解 perspective(視域)這個屬性

2021-02-19 前端達人

上一章節《學習前,你需要了解什麼是CSS 3D?》裡,我們一起了解什麼是CSS 3D,本篇章節筆者將帶著大家學習 perspective(視域)這個重要屬性,在我們接觸 CSS 3D 時,大多數開發人員都使用過,但是深入理解其原理的不知有多少。

首先強調下,理解這個屬性至關重要,這個 perspective(視域)屬性通常作用在外部容器元素上,例如body,figure和 div 等標籤上。這樣我們就在3D空間操作內在的子元素。你可以將這個屬性理解為類似flexbox這個屬性,因為其也可以影響內部元素的外觀和位置。如果沒有這個屬性,即使我們應用了 CSS 3D 的Transforms屬性我們也無法看到預期的3D視覺效果。

其實計算機的3D場景就是對現實世界的模擬,在了解這個屬性前,我們先設想一下這個場景:隨著愛好攝影的人越來越多,我們會經常拿著自己心愛的相機去拍照。拍照最重要莫過於這三前提要素:

第一個:鏡頭,第二個:拍攝的環境的空間,第三個:要拍攝的物件。

相機鏡頭主要定義了觀看者的角度,使用長焦距的望遠鏡頭,物體可以拉近且比較不會變形,使用短焦距的廣角鏡,拍攝的物體就容易變形,從下圖可以看出,鏡頭的焦距可以讓空間內的物體產生不同的變形。如下圖所示:

所以在CSS 3D的世界裡,最重要的也就是要找到並創建這三個物件要素,不過因為在CSS世界裡並沒有攝影鏡頭、拍攝的環境的空間等這些真實世界拍攝需要的要素,所以變成都用div進行展現,在對應的div 上頭加入對應的style屬性,就可以進行模擬,藉由上面所提到的三個要素,我們這裡就必須要用到三層div,最外層是攝影鏡頭,第二層為立體空間,第三層則是立體空間內的立體元素,寫出來的 HTML 長得就像下面這樣:

<div class = 「camera」 >
< div class = 「space」 >
< div class = 「box」 > </ div >
</ div >
</ div>

如上述代碼我們將最外層的div(以下通稱camera )定義為相機鏡頭,為了讓其具有相機的拍攝功能,我們就要為其定義相關的屬性,camera包含兩個屬性:perspective-origin 和 perspective。

這兩個屬性到底是啥呢?簡單的來說就是透視點以及鏡頭到透視點的距離,如果你想了解的更清楚些,你也許和我一樣在網絡上進行查詢,八九不離十你會看到如下所示的圖(來源:http://mathworld.wolfram.com/Perspective.html,佛羅倫斯建築師 Florentine architect(1377-1446)闡述的透視圖的原理):

這張圖我也不解釋太多,有點太理論,主要講述了透視的原理規則,感興趣的可以去上述連結進行查看。

然而在W3C網站對於perspective的解釋則是下圖這樣,透視點同樣也是物體到攝影機的距離( d ) ,但又因為CSS的3D空間裡頭具有Z軸,所以perspective的距離會因為Z軸的關係而有所縮放( 不過千萬要注意,這裡的Z指的是物體的Z軸,也就是translateZ,不是攝影機的)。

此外,perspective-origin 是攝影機的中心點位置,預設相對應空間div ( 以下都稱為space ) 的中心點,不做設定的話預設都是center center ( 或50% 50% ),換句話說,作為攝影鏡頭的camera 的三個維度,perspective-origin 代表了X 和Y 軸,而perspective 代表Z 軸( 和內容物體的Z 軸相減才會變成攝影機的),camera 就可以在三維空間裡頭進行移動,下圖同樣是W3C網站 對於perspective-origin 所作的解釋,當攝影鏡頭往上移動,圖形的下半部就看不到了。

如果你能理解上述文字,那實在是太好了,你已經前進了一大步,接下來看我們一起來看下本章節的第一段CSS代碼,我們可以像下面這樣進行定義,這時候我們還無法體驗3D效果,這是正常的,我們這裡只是告訴了計算機攝像機在哪,還沒定義拍攝環境的空間。

回到CSS 來看的話,我們可以像下面這樣設定,這時候會完全沒有畫面是正常的,因為還沒有設定空間和物體。

.camera{
width:200px;
height:200px;
perspective-origin:center center;
-moz-perspective-origin:center center;
-webkit-perspective-origin:center center;
perspective:500px;
-moz-perspective:500px;
-webkit-perspective:500px;
}

請注意,上面的值是近似值:精確整數和度量單位取決於許多因素,包括容器和子元素的相對大小。

攝影機完成後,我們需要定義一個立體空間space,這個空間設定的方式很簡單,只要設定一個屬性:transform-style,這個屬性默認值為flat,也就是只要是這個div內的子元素,一律都是以扁平( flat )的方式呈現,所屬的變換transform也默認一律都是用flat的方式變換,換句話說就是沒有Z軸的存在,為了讓內容元素都是立體元素,所以我們要將transform-style的值設為3d屬性,如此一來內容元素就全部都可以用3D進行變換,為了方便區分,下面我將會設置space的boder屬性設置為黑色虛線用於識別。

.space{
width:100%;
height:100%;
border:1px dashed #000;
transform-style:3d;
-moz-transform-style:3d;
-webkit-transform-style:3d;
}

上述代碼的效果如下圖:

最後就是內容元素box了,我們可以添加一個100px x 100px的box,接下來,我們先用這個box來驗證一下前面講的觀點,在沒有設定box的traslateZ、rotate的情形下,不論我們如何去修改camera的perspective-origin和perspective的值,box的大小和位置都不會有變化,為什麼呢?因為在沒有設定的box的translateZ或rotate,讓Z的深度有所變化,攝影機透過perspective看上去的位置都是相同的,也造成不論怎麼去看這個box都是一樣的大小。示例代碼如下:

.box{
width:100px;
height:100px;
background:#069;
transform:translateX(50px) translateY(50px);
-moz-transform:translateX(50px) translateY(50px);
-webkit-transform:translateX(50px) translateY(50px);
}

無論你怎麼修改camera的perspective屬性,效果都是一致的,效果如下圖:

不過當我們給box改變Z軸的深度之後(這裡我先把translateZ設定為150px ),再去改變camera的perspective-origin和perspective,終於能看到有效果變化了。

.box{
width:100px;
height:100px;
background:#069;
transform:translateX(50px) translateY(50px) translateZ(150px);
-moz-transform:translateX(50px) translateY(50px) translateZ(150px);
-webkit-transform:translateX(50px) translateY(50px) translateZ(150px);
}

大概了解之後,讓我們把box旋轉一下角度,看得應該就會更清楚,當攝影機的變成廣角,也就是perspective變短,整個旋轉後變形的效果也會更加明顯,大家可以用谷歌瀏覽器的開發者工具修改camera的perspective就會明白。

.box{
width:100px;
height:100px;
background:#069;
transform:translateX(50px) translateY(50px) rotateY(60deg);
-moz-transform:translateX(50px) translateY(50px) rotateY(60deg);
-webkit-transform:translateX(50px) translateY(50px) rotateY(60deg);
}

改變一下perspective-origin 也會很有趣味:

你可能要變換多個物體,接下來我們嘗試下添加多個box。並且讓這些box的位置改變或旋轉,看看效果如何,這裡比較需要注意的是我們必須要在最外層的div加入position:absolute的屬性,因為div本身為block屬性,會互相擠壓,要設定位置為絕對位置,才會正確地放在space空間裡。

示例代碼如下:

.space div{
position:absolute;
width:100px;
height:100px;
}
.box1{
background:#069;
transform:translateX(50px) translateY(50px) rotateY(60deg);
-moz-transform:translateX(50px) translateY(50px) rotateY(60deg);
-webkit-transform:translateX(50px) translateY(50px) rotateY(60deg);
}
.box2{
background:#c00;
transform:translateX(100px) translateY(20px) rotateX(60deg);
-moz-transform:translateX(100px) translateY(20px) rotateX(60deg);
-webkit-transform:translateX(100px) translateY(20px) rotateX(60deg);
}
.box3{
background:#f90;
transform:translateX(0px) translateZ(-250px) rotateY(20deg);
-moz-transform:translateX(0px) translateZ(-250px) rotateY(20deg);
-webkit-transform:translateX(0px) translateZ(-250px) rotateY(20deg);
}
.box4{
background:#0c9;
transform:translateX(20px) translateY(80px) rotateX(-80deg);
-moz-transform:translateX(20px) translateY(80px) rotateX(-80deg);
-webkit-transform:translateX(20px) translateY(80px) rotateX(-80deg);
}

如上圖所示,上述的三個3D元素,就這樣被我們展現在了3D空間裡了,不過除了camera、space和box之外,還有一個最重要最重要最重要的使用規則(因為很重要所以要講三次),這個規則就是tramsform裡頭是有順序的,因為CSS 3D完全是藉由2D演算而來,並不是真的像3D軟體構建是真的有3D的空間,所以就變成會「按照順序」進行演算,而且又因為transform會造成物體的整個坐標軸會隨著變換而變換,在順序的編排上就格外重要,順序不同效果就有所不同

接下來我們來看一個順序不同,效果不同的例子。例如我先讓box在X軸上水平位移100px再繞著Y軸順時針轉60度,和先繞Y軸順時針轉60度,再在X軸上頭水平位移100px的結果會完全不同,因為當我先繞了Y軸轉動,整個X軸也會跟著轉動,這時候再做水平位移,位置就會像是在深度做變換。示例代碼如下:

.space div{
position:absolute;
width:100px;
height:100px;
}
.box1{
background:#069;
transform:translateY(50px) translateX(100px) rotateY(60deg);
-moz-transform:translateY(50px) translateX(100px) rotateY(60deg);
-webkit-transform:translateY(50px) translateX(100px) rotateY(60deg);
}
.box2{
background:#c00;
transform:translateY(50px) rotateY(60deg) translateX(100px);
-moz-transform:translateY(50px) rotateY(60deg) translateX(100px);
-webkit-transform:translateY(50px) rotateY(60deg) translateX(100px);
}

上述代碼的效果如下圖:

你是不是覺得transform的數量和變化類型少?效果不是太明顯?,接下來讓其更效果加明顯,我們往transform裡塞更多的內容,數量越多造成的視覺差異就強烈,這也是在玩CSS 3D最最最最最需要注意的重點所在,一定要注意,一定要注意,一定要注意,非常重要所以再講三次呀!示例代碼如下:

.space div{
position:absolute;
width:100px;
height:100px;
}
.box1{
background:#069;
transform:translateY(50px) translateX(100px) rotateY(60deg) rotateX(60deg) translateX(-50px);
-moz-transform:translateY(50px) translateX(100px) rotateY(60deg) rotateX(60deg) translateX(-50px);
-webkit-transform:translateY(50px) translateX(100px) rotateY(60deg) rotateX(60deg) translateX(-50px);
}
.box2{
background:#c00;
transform:translateX(-50px) translateY(50px) rotateX(60deg) rotateY(60deg) translateX(100px);
-moz-transform:translateX(-50px) translateY(50px) rotateX(60deg) rotateY(60deg) translateX(100px);
-webkit-transform:translateX(-50px) translateY(50px) rotateX(60deg) rotateY(60deg) translateX(100px);
}

上一章節,我們完成了我們的第一個例子美女看過來,在本章節的結束前,看本文的妹子有福了,你可以親自體調控視角來看帥哥,呵呵。

示例效果如下:

由於本章節篇幅有限,就不在這裡貼大量的代碼了,感興趣的點擊體驗地址(請在PC端用chrome進行體驗):https://www.qianduandaren.com/demo/css3d/02/,查看源碼。

本章節就到這裡,今天我們一起深刻理解了perspective(視域)這個重要屬性,並一起完成了幾個例子,加深了對這個屬性的理解,只有理解這個屬性後,我們才能更進一步的學習CSS 3D,今天的內容有些多,需要你慢慢消化。最後重要的事情說三遍,理解perspective(視域)很重要!理解perspective(視域)很重要!理解perspective(視域)很重要!

因為很重要,下一章節我們要繼續學習使用perspective(視域)的有哪些坑和注意事項。

專注分享當下最實用的前端技術。關注前端達人,與達人一起學習進步!

相關焦點

  • Html+Css3
    3d轉換transform透視perspective/破四百可體悟/:500px透視距離值越大離得越遠,幅度越小。值越小離得越近,幅度越大。一般設置300-500左右合適。perspective-origin: left right top bottom ;透視基點origin 基點opacity透明度0-1transform-style:preserve-3d  控制子級在3d空間內顯示 動畫:animation動畫的組成部分:關鍵幀@keyframes{
  • 大狗乾貨鋪子:CSS3 變形、過渡、動畫、關聯屬性淺析
    示例:transform: rotate(90deg) scale(1.5,0.8) translate(100px,50px) skew(45deg,45deg);/*矩陣變形*/matrix(transition:過度屬性transition:過度效果的css屬性名 過度效果時長 速度效果的速度曲線 過度效果開始時間
  • css晦澀難懂的點都在這啦
    : css大三特性是css最重要的部分,可以說如果了解了這三大特性就對css撐握了一半,對於屬性只不過是記不記的住的事,而這個是重在理解。❞選擇器❝在講這三個特性之前我們需要來全面了解下選擇器。是瀏覽器處理衝突的一個能力,如果一個屬性通過兩個相同選擇器設置到同一個元素上,那麼這個時候一個屬性就會將另一個屬性層疊掉❞樣式衝突,遵循的原則是「就近原則。」 那個樣式離著結構近,就執行那個樣式。CSS層疊性最後的執行口訣:  長江後浪推前浪,前浪死在沙灘上。
  • 美女小姐姐教大家如何用變換、過渡的屬性做一個3d立方體?
    今天小編給大家帶來的小案例是如何用變換、過度屬性,做一個旋轉的3d 立體方塊,和小時候大家玩的魔方差不多。在html中變換、過渡屬性是使用頻率方法。也是非常使用的一種。子級元素在3D空間佔據位置perspective:值 景深(設置用戶眼睛到元素的距離) 舉個慄子perspective:800px關於景深的設置可以設置給自身 這種情況景深是變換的屬性寫法是transform:perspective(
  • 《前端5分鐘》之使用CSS3實現酷炫的3D旋轉透視
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫你將學到CSS3 3D 轉換的常用API介紹CSS3 3D 應用場景CSS3 3D 實現一個立方體開始1.CSS3 3D 轉換的常用API介紹首先先上一張css 3D的坐標系:接下來我們來介紹幾個常用的
  • H5打造3d場景不完全攻略(二): Amazing CSS3D
    而css中是不存在根據坐標建立空間平面的能力的。 (插個題外話,其實css有一個屬性與坐標有關,那就是clip-path。這個屬性的特性賦予了css3一定的建模能力。實現方法可參考這篇文章 純clip-path打造的3D模型渲染器) CSS3實現3D全景 上篇文章介紹了Web3D的一些表現形式,這裡著重談談怎麼以CSS3實現3D全景。
  • 前端頁面如何實現2d3d動態效果詳解
    transform屬性向元素應用 2D 或 3D 轉換該屬性允許我們對元素進行旋轉縮放移動或傾斜。縱向傾斜度數 y取值為正,y軸不動,x軸順時針傾斜一定角度 y取值為負,y軸不動,x軸逆時針傾斜一定角度 3、skewX(xdeg) 4、skewY(ydeg)案列劃上圖片放大 誰動給誰加過度不是hover誰給誰加超出盒子範圍 隱藏<style type="text/css
  • CSS Display屬性的雙值寫法
    display屬性,なに?display屬性用來控制一個元素及其子元素的格式化上下文,你應該在剛剛學習CSS的時候就知道,有些元素是塊級元素,有些則是行內元素。有了display屬性,你就可以切換元素不同的狀態。比如說,通常一個h1元素是一個塊級元素,但是通過切換,它就能以內聯元素展現。
  • CSS工程化
    j : javascript,表示這個樣式沒有實際意義,是專門提供給js獲取元素使用的「css in js」這個方案賊大膽,它覺得,css語言本身幾乎無可救藥了,乾脆直接用js對象來表示樣式,然後把樣式直接應用到元素的style中
  • 開發者的福音 CSS 3D轉換教程大放送
    也許你會因一些概念、術語等將兩者混淆,文中例舉的這幾款示例能幫你輕鬆解答困惑。對於CSS 3D愛好者來說,無疑是個不錯的選擇。一起來看下本文為您推薦的8篇非常實用的CSS 3D轉換教程吧!1.本文解釋了如何利用CSS3創建出不同功能應用,比如matrix3d,perspective,rotateX,rotateY,rotateZ,rotate3d,scaleX,scaleY,scaleZ,scale3d,translateX
  • 2020年軍隊文職考試專業科目:【Web前端基礎知識】CSS3 3D 變換
    1.transform-style屬性transform-style屬性是3D空間一個重要屬性,指定嵌套元素如何在3D空間中呈現。他主要有兩個屬性值:flat和preserve-3d。2、景深(透視)近大遠小 景深程序中實現的方法 perspective 元素距離 視線的距離(物體和眼睛的距離越小,近大遠小的效果越明顯)perspective: 1200px;(在父元素中用)transform
  • 如何理解CSS的display屬性
    display屬性定義了盒子的顯示類型。關於瀏覽器如何進行渲染在屏幕上顯示這個話題,真的令人十分陶醉。這裡我建議你閱讀Talia Garsiel書寫的瀏覽器工作原理: 現代web瀏覽器的幕後。另外一篇必讀的文章是Fantasai書寫的CSS布局演變: 始於1990年終於未來,該作者目前在W3C CSS規範組工作。
  • 10 個 GitHub 上超火的 CSS 技巧項目,找到寫 CSS 的靈感!
    這裡可以讓你尋找到使用或者是學習 CSS 的靈感,以分類的形式,展示不同 CSS 屬性或者不同的課題使用 CSS 來解決的各種方法。https://github.com/chokcoco/CSS-Inspirationcss_tricks該項目總結了一些常用的 CSS 樣式,記錄一些 CSS 的新屬性和一點奇技淫巧
  • css outline-color屬性設置輪廓顏色
    outline-color屬性定義及用法在css中,outline-color屬性是使用來設置輪廓的顏色。所謂輪廓就是繪製於元素周圍的一條線,位於邊框邊緣的外圍,是圍繞元素的邊距,不是元素尺寸的一部分,因此元素的寬度和高度屬性不包含輪廓的寬度。outline-color屬性必須和outline-style屬性一起使用,這很好理解,元素必須要有輪廓(outline-style屬性定義輪廓樣式)才能設置輪廓顏色。
  • CSS margin屬性與用法教程
    margin 屬性是css用於在一個聲明中設置所有 margin 屬性的簡寫屬性,margin是css控制塊級元素之間的距離
  • 9個非常實用的CSS圖標庫
    網站:http://www.iconfont.cn/2、Font AwesomeFont Awesome為您提供可縮放的矢量圖標,您可以使用css所提供的所有特性對它們進行更改,包括:大小、顏色、陰影或者其它任何支持的效果。
  • css right屬性右邊緣偏移
    right屬性定義及用法在css中,right屬性是使用來定義定位元素右外邊距邊界與其包含塊右邊界之間的偏移。和該屬性相似的屬性有left、top、bottom,通常相互配合用來定位元素的位置。這幾個偏移屬性必須和position屬性一起使用,而其position屬性值不能為static(默認),不然left、right、top、bottom偏移屬性是沒有效果的;對於static元素,為auto;對於長度值,則為相應的絕對長度;對於百分比數值,為指定值;否則為auto。對於相對定義元素,left的計算值始終等於right。
  • 前端開發規範(三、CSS性能優化)
    Display 屬性會影響頁面的渲染,請合理使用。多利用硬體能力,如通過 3D 變形開啟 GPU 加速一般在 Chrome 中,3D或透視變換(perspective transform)CSS屬性和對 opacity 進行 CSS 動畫會創建新的圖層,在硬體加速渲染通道的優化下,GPU 完成 3D 變形等操作後,將圖層進行複合操作(Compesite
  • CSS中behavior屬性語法簡介
    CSS中behavior屬性語法簡介 你對CSS中behavior屬性的語法是否熟悉,這裡向大家簡單描述一下,在進行CSS網頁布局的時候,我們經遇到刷新要保留表單裡內容的時候,CSS中的behavior就為我們很好的解決了這個問題。
  • css flex屬性筆記
    flex屬性定義及用法在css中,flex屬性是使用來設置或檢索彈性盒模型對象的子元素如何分配空間,是 flex-grow屬性、flex-shrink屬性和 flex-basis 屬性的簡寫屬性。flex屬性針對的是彈性盒模型對象的子元素,對於其它元素,flex屬性不起任何作用;一些主流瀏覽器還不支持flex屬性,需要在該屬性之前加對應的前綴才能識別該屬性。Internet Explorer 9及更早版本不支持flex屬性,但是可以通過-ms-flex屬性來支持, IE11 及更新版本完全支持flex屬性,不再需要-ms-前綴。