當前內容所在位置(可進入專欄查看其他譯好的章節內容)
- 第五部分 添加動效 ??
- 【第 16 章 變換】 ??
- 16.1 旋轉、平移、縮放與傾斜
- 16.1.1 變換原點的更改
- 16.1.2 多重變換的設置
- 16.1.3 單個變換屬性的設置
- 16.2 變換在動效中的應用
- 16.2.1 放大圖標(上)
- 16.2.2 帶“飛入”特效的文本標簽的創建(下)
- 16.2.3 過渡特效的交錯渲染(下)
- 16.3 動畫的性能
- 16.4 三維變換 ??
- 16.4.1 控制透視距離 ??
- 16.4.2 高級三維變換效果的實現 ??
- 16.5 本章小結 ??
文章目錄
- 16.4 三維變換 3D transforms
- 16.4.1 控制透視距離 Controlling perspective
- 16.4.2 高級三維變換效果的實現 Implementing advanced 3D transforms
- 16.4.2.1 perspective-origin 屬性(Perspective-origin property)
- 16.4.2.2 backface-visibility 屬性(backface-visibility property)
- 16.4.2.3 transform-style (preserve-3D) 屬性(transform-style (preserve-3D) property)
- 16.5 本章小結 Summary
《CSS in Depth》新版封面
譯者按
上一篇我們學習了 CSS 的底層渲染原理,這一篇就來實際應用一下相關知識點。雖然 CSS 的 3D 變換在實際工作中用得并不多,但了解里面最基本的概念和典型案例,對于構建完整的 CSS 知識體系而言也是至關重要的。除了作者提到的延伸材料外,相關屬性的實際應用案例還可以參考《Tiny CSS Projects》這本書的相關章節,可以更好地理解本節的核心概念。
16.4 三維變換 3D transforms
到目前為止我們使用的變換都是二維的。這些變換是最容易處理的(也最常見),因為頁面本身就是二維的。但我們不應該止步于此,旋轉和平移都可以在三個維度上實現:x
軸、y
軸和 z
軸。
我們可以像之前那樣使用 translate()
函數,在水平和垂直方向上平移(即 x
和 y
維度);也可以通過 translateX()
和 translateY()
函數來實現同樣的效果。下面三個聲明會產生同樣的效果:
transform: translate(15px, 50px);
transform: translateX(15px) translateY(50px);
translate: 15px 50px;
我們還可以使用 translateZ()
函數、或者給 translate
屬性提供第三個參數值來實現 z
軸上的平移變換。從概念上看,這個 z
值相當于通過平移的方式讓該元素更靠近或遠離用戶。
同理,也可以讓元素繞著三個不同的坐標軸進行旋轉。但與平移不同的是,我們已經非常熟悉 rotateZ()
函數了,因為 rotateZ()
也是 rotate()
的別名,它就是繞著 z
軸旋轉的。函數 rotateX()
和 rotateY()
分別圍繞水平方向上的 x
軸(使元素向前或向后傾斜(pitching))和垂直方向上的 y
軸(使元素向左或者向右轉動或 偏移(yawing))旋轉。有關這些函數的具體示例,如圖 16.13 所示。
【圖 16.13 透視距離為 300px 下的三個坐標軸上的旋轉效果圖(虛線表示元素的初始位置)】
在使用 rotate
屬性進行變換時,還可以指定坐標軸的名稱 x
、y
或者 z
,并帶上角度值,例如 rotate: z 20deg
或者 rotate: x 30deg
。
16.4.1 控制透視距離 Controlling perspective
在給頁面添加三維變換特效前,我們需要先明確一個概念,即 透視距離(perspective)。變換后的元素共同構成了一個 3D 場景。隨后瀏覽器會計算該 3D 場景的 2D 圖像并渲染到屏幕上。我們可以把透視距離想象成 “攝像機” 與場景之間的距離,前后移動鏡頭就可以改變整個場景在最終圖像中的展示方式。
如果鏡頭離得較近(即透視距離小),那么 3D 效果會比較強;如果鏡頭離得較遠(即透視距離大),則 3D 效果就比較弱。圖 16.14 列出了幾種不同的透視距離效果。
【圖 16.14 同一旋轉變換在不同透視距離下的頁面效果】
左側這個旋轉后的元素沒有設置透視距離,看起來不太像是 3D 的。它只是在水平方向上做了些壓縮,并沒有什么立體感。不設置透視距離的三維變換看上去像是平的(flat);元素中 “更遠” 的那部分并沒有渲染得小一些。另一方面,中間那個盒子設置了 400px
的透視距離,其右邊緣(即距離觀察者較遠的那一邊),看起來小了些;而離觀察者較近的這一側看上去則變大了些。右邊的盒子透視距離更短,只有 100px
。這樣就大大增強了 3D 效果,使得元素邊緣離得越遠,圖像縮小得也就越明顯。
我們可以通過兩種方式來指定透視距離:使用 perspective()
變換,或者使用 perspective
屬性(property)。兩種方式略有不同。下面通過一個簡單的示例來說明。這是個簡化版示例,僅用于演示透視距離的頁面效果。
首先,我們為四個元素添加旋轉特效,使用 rotateX()
將它們向后傾斜(如圖 16.5 所示)。因為每個元素旋轉同樣的角度,并且設置了相同的 perspective()
變換,所以它們看上去是一樣的。
【圖 16.15 四個元素都圍繞 x 軸旋轉、并且均設置了 perspective(200px) 后的效果圖】
為這個演示案例新建一個頁面,并復制以下代碼清單 16.12 中的 HTML。
代碼清單 16.12 用于演示三維變換及透視效果的四個盒子 HTML 標記
<div class="row"><div class="box">One</div><div class="box">Two</div><div class="box">Three</div><div class="box">Four</div>
</div>
接著,我們給每個盒子添加 3D 變換和透視距離。同時也可以來點顏色和內邊距樣式,略微擴充些尺寸大小,讓最終效果更加明顯。請根據代碼清單 16.13 同步更新本地樣式表。
代碼清單 16.13 給盒子添加三維變換特效的示例樣式代碼
.row {display: flex;gap: 4em;justify-content: center;
}.box {box-sizing: border-box;width: 150px;padding: 60px 0;text-align: center;background-color: oklch(60% 0.12 158deg);transform: perspective(200px) rotateX(30deg); /* 令盒子向后旋轉 30 度角,并指定透視距離 */
}
在本例中,每個盒子看上去都相同。它們都有自己的透視距離,并利用 perspective()
函數進行定義。這個方法可以為單個元素設置透視距離,示例中我們直接為所有盒子做了相同的設置,這樣就像給每個元素分別單獨拍照,但是拍攝位置是相同的。
警告
perspective()
變換必須在期望其影響的其他變換 之后 生效。也就是說,perspective()
在與單獨的變換屬性(如rotate
)結合使用時效果并不理想,因為這些屬性是在transform
屬性之后生效的。當使用perspective()
變換時,應該將它列為第一項,然后在同一個transform
聲明中列出其他變換函數。
有時候我們希望多個元素能共享同一套透視距離,仿佛它們都處于相同的三維空間中。圖 16.16 展示了這種情況的一個效果圖。圖中有四個相同的元素,并且它們都向著遠方的一個相同的交匯點延伸,就仿佛把四個元素放一起然后拍了一張整體的照片。要實現這種效果,需要為它們的父元素設置 perspective
屬性。
【圖 16.16 為公共祖先元素設置 perspective 屬性可以讓多個元素共享相同的透視距離】
要查看這樣的效果,可以移除各元素盒上的 perspective()
函數,并在其父容器上設置 perspective
屬性。具體樣式如代碼清單 16.14 所示。
代碼清單 16.14 建立統一透視距離的示例樣式代碼
.row {display: flex;gap: 4em;justify-content: center;perspective: 200px; /* 在容器上添加透視距離 */
}
.box {box-sizing: border-box;width: 150px;padding: 60px 0;text-align: center;background-color: oklch(60% 0.12 158deg);transform: rotateX(30deg); /* 不在盒子本身設置透視距離 */
}
通過為父容器(或其他祖先元素)設置統一的透視距離,父容器包含的所有應用了三維變換的子元素,都將共享這一相同的透視距離。
添加透視距離是三維變換中非常重要的知識點。如果不設置透視距離,既不能讓離得較遠的元素顯小,也不會讓離得較近的元素渲染得更大。上面的例子都比較簡單,下一章我們還會把這些技術應用到一個實際案例中,實現元素從遠處 “飛入” 的效果。
16.4.2 高級三維變換效果的實現 Implementing advanced 3D transforms
在對元素進行三維變換時,還有其他一些很有用的屬性(properties)。我不打算花太多精力講解這些屬性,因為在實際開發中應用場景寥寥無幾(few and far between)。但了解它們的存在也是有必要的,萬一今后用得上也不錯。想要更深入地研究這些屬性,稍后我也會提供幾個線上的示例。
16.4.2.1 perspective-origin 屬性(Perspective-origin property)
默認情況下,透視距離的渲染是假設觀察者(或相機鏡頭)位于元素中心的正前方。perspective-origin
屬性可以上下、左右移動鏡頭位置。圖 16.17 展示了剛才的示例,只是鏡頭移到了左下角位置。
【圖 16.17 移動透視原點后,元素向遠端延伸的形變增加了】
請根據代碼清單 16.15 同步更新本地樣式表,查看上述演示效果。
代碼清單 16.15 利用 perspective-origin 移動鏡頭位置的示例樣式代碼
.row {display: flex;justify-content: center;perspective: 200px;perspective-origin: left bottom; /* 將鏡頭位置調至元素左下角 */
}
還是跟之前一樣的透視距離,但是視角改變了,所有的盒子都移到了鏡頭的右側。我們既可以使用關鍵字 top
、left
、bottom
、right
和 center
來設置方位,也可以使用百分比或長度值來精確控制,并從元素的左上角開始計算偏移量(例如 perspective-origin: 25% 25%
)。
本例演示的效果較為夸張,原因在于透視距離相對較近,僅有 200px
。您也可以將該距離調大些,讓頁面的立體感沒那么強烈。
16.4.2.2 backface-visibility 屬性(backface-visibility property)
如果使用 rotateX()
或者 rotateY()
旋轉元素超過 90 度,就會發現一些有趣的現象:元素的 “正面” 不再直接朝向您;相反,它是背對您的。您會看到元素的背面。如圖 16.18 所示,圖中元素設置了 rotateY(180deg)
的變換特效,看上去就像是之前元素的鏡像圖片。
【圖 16.18 通過元素旋轉來查看其背面效果】
這就是元素背面的效果圖。默認情況下背面是可見的,但我們可以為該元素設置 backface-visibility: hidden
來進行修改。添加這句聲明后,元素只有在正面朝向觀察者的時候才是可見的,而朝向反面時將被隱藏起來。
這項技術的一個可能的應用場景,是把兩個元素背靠背放在一起,就像卡片的正反兩面。卡片的正面展示出來,背面則隱藏。然后我們可以旋轉它們的容器元素,讓這兩個元素同時翻轉過來,使得正面隱藏、背面則會顯現。卡片翻轉特效的演示案例,可以參考這篇文章:《Intro to CSS 3D Transforms: Card Flip》。
16.4.2.3 transform-style (preserve-3D) 屬性(transform-style (preserve-3D) property)
如果要使用嵌套元素來構建復雜的 3D 場景,transform-style
屬性就變得非常重要。假設我們已經對容器設置了透視距離,接下來對容器內的元素進行三維變換。容器元素在渲染時,實際上會被繪制成二維場景,如同三維對象的一張照片。這看起來沒什么問題,因為元素終將渲染到二維屏幕上。
但如果這時對容器元素進行三維旋轉,就會出問題:這樣做沒能對整個場景進行旋轉,只是旋轉了三維場景下的二維圖像。透視距離全都錯了,場景中的立體感也被破壞了。相關的頁面效果如圖 16.19 所示。
【圖 16.19 如果對 3D 變換元素的父元素再進行 3D 變換,可能需要啟用 preserve-3d 屬性(右側)】
左圖展示了通過把六個面變換到相應位置創建的一個 3D 立方體效果;中間的圖片展示的是對整個立方體(即它們的父元素)使用變換后的效果。為了修正這個問題,應該在父元素上聲明 transform-style: preserve-3d
。
想要了解更多講解內容和實用案例,可以查看 Ana Tudor 的線上教程,詳見:https://davidwalsh.name/3d-transforms。雖然這些示例很有意思,但我從未在實際項目中用過 preserve-3d
。如果您決定上手試試三維變換,想看看可以實現哪些效果,這份教程會很有幫助。
16.5 本章小結 Summary
- CSS 變換可以在二維和三維中縮放、旋轉、平移和傾斜元素。
- 可以使用
transform
屬性設置多個變換特效。這些變換是從右到左生效的。 - 利用單獨的
scale
、rotate
和translate
屬性可以實現更簡單的變換效果。 - CSS 的
transform
和opacity
屬性是在過渡和動畫特效中性能最好的兩個屬性。它們無需瀏覽器重新計算布局或重繪頁面內容。 - 在其他變換之后生效的
perspective()
變換會讓這些變換效果看起來具有三維立體感。您還可以將transform
屬性設置到容器元素上,讓子元素共享同一個三維場景。 - 自定義的定時函數曲線可以實現過渡特效中的 “彈跳” 效果。
關于《CSS in Depth》(中譯本書名《深入解析 CSS》)
第 1 版 | 第 2 版 | |
---|---|---|
讀者評分 | 原版:4.7(亞馬遜);中文版:9.3(豆瓣) | 原版:5.0(亞馬遜);中文版:暫無,待出版 |
出版時間 | 原版:2018 年 3 月;中文版:2020 年 4 月 | 原版:2024 年 7 月;中文版:暫無,待出版 |
原價 | 原版:$44.99;中文版:¥139.00 | 原版:$59.99;中文版:暫無,待出版 |
現價 | 原版:$36.49;中文版:¥52.54 起步 | 原版:$52.09;中文版:暫無,待出版 |
原版國內預訂 | 起步價 ¥461.00 | 起步價 ¥750.00 |
本專欄為該書第 2 版高分譯文專欄,全網首發,精譯精校,持續更新,計劃今年內完成全書翻譯,敬請期待!!!
目前已完結的章節(可進入本專欄查看詳情,連載期間完全免費):
- 第一章 層疊、優先級與繼承(已完結)
- 1.1 層疊
- 1.2 繼承
- 1.3 特殊值
- 1.4 簡寫屬性
- 1.5 CSS 漸進式增強技術
- 1.6 本章小結
- 第二章 相對單位(已完結)
- 2.1 相對單位的威力
- 2.2 em 與 rem
- 2.3 告別像素思維
- 2.4 視口的相對單位
- 2.5 無單位的數值與行高
- 2.6 自定義屬性
- 2.7 本章小結
- 第三章 文檔流與盒模型(已完結)
- 3.1 常規文檔流
- 3.2 盒模型
- 3.3 元素的高度
- 3.4 負的外邊距
- 3.5 外邊距折疊
- 3.6 容器內的元素間距問題
- 3.7 本章小結
- 第四章 Flexbox 布局(已完結)
- 4.1 Flexbox 布局原理
- 4.2 彈性子元素的大小
- 4.3 彈性布局的方向
- 4.4 對齊、間距等細節處
- 4.5 本章小結
- 第五章 網格布局(已完結)
- 5.1 構建基礎網格
- 5.2 網格結構剖析 (上)
- 5.2.1 網格線的編號(下)
- 5.2.2 網格與 Flexbox 配合(下)
- 5.3 兩種替代語法
- 5.3.1 命名網格線
- 5.3.2 命名網格區域
- 5.4 顯式網格與隱式網格(上)
- 5.4.1 添加變化 (中)
- 5.4.2 讓網格元素填滿網格軌道(下)
- 5.5 子網格(全新增補內容)
- 5.6 對齊相關的屬性
- 5.7 本章小結
- 第六章 定位與堆疊上下文(已完結)
- 6.1 固定定位
- 6.1.1 創建一個固定定位的模態對話框
- 6.1.2 在模態對話框打開時防止屏幕滾動
- 6.1.3 控制定位元素的大小
- 6.2 絕對定位
- 6.2.1 關閉按鈕的絕對定位
- 6.2.2 偽元素的定位問題
- 6.3 相對定位
- 6.3.1 創建下拉菜單(上)
- 6.3.2 創建 CSS 三角形(下)
- 6.4 堆疊上下文與 z-index
- 6.4.1 理解渲染過程與堆疊順序(上)
- 6.4.2 用 z-index 控制堆疊順序(上)
- 6.4.3 深入理解堆疊上下文(下)
- 6.5 粘性定位
- 6.6 本章小結
- 第七章 響應式設計(已完結)
- 7.1 移動端優先設計原則(上篇)
- 7.1.1 創建移動端菜單(下篇)
- 7.1.2 給視口添加 meta 標簽(下篇)
- 7.2 媒體查詢(上篇)
- 7.2.1 深入理解媒體查詢的類型(上篇)
- 7.2.2 頁面斷點的添加(中篇)
- 7.2.3 響應式列的添加(下篇)
- 7.3 流式布局
- 7.4 響應式圖片
- 7.5 本章小結
- 第八章 層疊圖層及其嵌套
- 8.1 用 layer 圖層來操控層疊規則(上篇)
- 8.1.1 圖層的定義(上篇)
- 8.1.2 圖層的順序與優先級(下篇)
- 8.1.3 revert-layer 關鍵字(下篇)
- 8.2 層疊圖層的推薦組織方案
- 8.3 偽類 :is() 和 :where() 的用法
- 8.4 CSS 嵌套的使用
- 8.4.1 嵌套選擇器的使用
- 8.4.2 深入理解嵌套選擇器
- 8.4.3 媒體查詢及其他 @規則 的嵌套
- 8.5 本章小結
- 第九章 CSS 的模塊化與作用域
- 9.1 模塊的定義
- 9.1.1 模塊和全局樣式
- 9.1.2 一個簡單的 CSS 模塊
- 9.1.3 模塊的變體
- 9.1.4 多元素模塊
- 9.2 將模塊組合為更大的結構
- 9.2.1 模塊中多個職責的拆分
- 9.2.2 模塊的命名
- 9.3 CSS 的作用域
- 9.3.1 CSS 作用域的就近原則
- 9.3.2 劃定作用域的邊界
- 9.3.3 CSS 中的隱式作用域
- 9.3.4 關于 CSS 作用域與層疊圖層
- 9.4 CSS 模式庫
- 9.5 本章小結
- 第十章 CSS 容器查詢
- 10.1 容器查詢的一個簡單示例
- 10.1.1 容器尺寸查詢的用法
- 10.2 深入理解容器
- 10.2.1 容器的類型
- 10.2.2 容器的名稱
- 10.2.3 容器與模塊化 CSS
- 10.3 與容器相關的單位
- 10.4 容器樣式查詢的用法
- 10.4.1 將模塊與所在容器解耦
- 10.4.2 減少重復代碼
- 10.5 本章小結
- 第 11 章 顏色與對比
- 11.1 通過對比進行交流
- 11.1.1 模式的建立
- 11.1.2 還原設計稿
- 11.2 顏色的定義
- 11.2.1 色域與色彩空間
- 11.2.2 CSS 顏色表示法(RGB、Hex、HSL、HWB、LAB/OKLAB、LCH/OKLCH)
- 11.3 利用 OKLCH 處理顏色(上篇)
- 11.3.4 從頁面其他顏色衍生出新顏色(下篇)
- 11.4 思考字體顏色的對比效果
- 11.5 本章小結
- 第 12 章 CSS 排版與間距
- 12.1 間距設置
- 12.1.1 使用 em 還是 px
- 12.1.2 對行高的深入思考
- 12.1.3 行內元素的間距設置
- 12.2 Web 字體
- 12.3 谷歌字體
- 12.4 @font-face 的工作原理
- 12.4.1 字體格式與回退處理
- 12.4.2 同一字型的多種變體形式
- 12.5 性能因素考量
- 12.5.1 font-display 屬性解析
- 12.5.2 可變字體的用法
- 12.6 調整字間距,提升可讀性
- 12.6.1 正文的字間距
- 12.6.2 標題、小元素和間距
- 12.7 本章小結
- 第 13 章 漸變、陰影與混合模式
- 13.1 漸變
- 13.1.1 使用多個顏色節點(上)
- 13.1.2 顏色插值方法(中)
- 13.1.3 徑向漸變(下)
- 13.1.4 錐形漸變(下)
- 13.2 陰影
- 13.2.1 利用漸變和陰影打造立體感
- 13.2.2 使用扁平化設計創建元素
- 13.2.3 創建混合風格的按鈕外觀
- 13.3 混合模式
- 13.3.1 為圖片上色
- 13.3.2 混合模式的類型
- 13.3.3 圖片紋理的添加
- 13.3.4 融合混合模式的用法
- 13.4 本章小結
- 第 14 章 蒙版、形狀與剪切
- 14.1 濾鏡
- 14.1.1 濾鏡的類型
- 14.1.2 背景濾鏡
- 14.2 蒙版
- 14.2.1 帶漸變效果的蒙版特效
- 14.2.2 基于亮度來定義蒙版
- 14.2.3 其他蒙版屬性
- 14.3 剪切路徑
- 14.3.1 多邊形的裁剪路徑
- 14.3.2 Firefox 內置的剪切路徑工具
- 14.3.3 其他剪切路徑類型
- 14.4 浮動與形狀
- 14.4.1 浮動
- 14.4.2 形狀的定義
- 14.5 本章小結
- 第 15 章 過渡
- 15.1 狀態間的由此及彼
- 15.2 定時函數
- 15.2.1 定制貝塞爾曲線
- 15.2.2 階躍
- 15.3 非動畫屬性
- 15.3.1 不可添加動畫效果的屬性
- 15.3.2 淡入與淡出
- 15.4 過渡到自然高度
- 15.5 自定義屬性的過渡設置
- 15.6 本章小結
- 附錄
- 附錄A:CSS 選擇器參考
- 附錄B:CSS 預處理器簡介