發布日期:2025 年 9 月 22 日
啟動檢視畫面轉換時,瀏覽器會自動擷取標記 view-transition-name 的元素前後快照。這些快照會顯示在虛擬元素樹狀結構中。根據預設,產生的樹狀結構為「扁平」。這表示 DOM 中的原始階層會遺失,且所有擷取的檢視畫面轉換群組都是單一 ::view-transition 虛擬元素下的同層元素。
這種扁平樹狀結構方法適用於許多用途,但有些樣式用途無法透過這種方法達成。以下是可能在扁平樹狀結構中產生非預期視覺效果的效果範例:
- 裁剪 (
overflow、clip-path、border-radius):裁剪會影響元素的子項,也就是說,檢視畫面轉換群組同層元素無法互相裁剪。 opacity、mask-image和filter:同樣地,這些效果旨在對樹狀結構的完整光柵化圖片產生作用,影響子項,而非個別影響每個項目。- 3D 轉換 (
transform-style、transform、perspective):如要顯示完整的 3D 轉換動畫,必須維持部分階層。
以下範例顯示扁平的虛擬樹狀結構,其中元素會由 DOM 樹狀結構中的祖系裁剪。這些元素在檢視畫面轉換期間會失去裁剪效果,導致視覺效果不完整。
巢狀檢視畫面轉換群組是檢視畫面轉換的擴充功能,可讓您在彼此之間建立巢狀 ::view-transition-group 虛擬元素。如果檢視畫面轉換群組為巢狀結構,則可在轉換期間還原剪輯等效果。
Browser Support
從扁平虛擬樹狀結構到巢狀虛擬樹狀結構
在下列試用版中,您可以點選使用者顯示圖片,查看該使用者的詳細資訊。動畫是由相同文件檢視畫面轉場效果處理,可將點選的按鈕變形為對話方塊、在畫面上移動顯示圖片和名稱,以及向上或向下滑動對話方塊中的段落。
現場示範
Demo 錄音
Demo 錄音 (慢速版)
如果仔細觀察示範,就會發現轉場效果有問題:雖然含有說明的段落是 DOM 中 <dialog> 元素的子項,但文字在轉場期間並未遭到 <dialog> 方塊裁剪:
<dialog id="info_bramus" closedby="any">
<h2><img alt="…" class="avatar" height="96" width="96" src="avatar_bramus.jpg"> <span>Bramus</span></h2>
<p>Bramus is …</p>
<p>…</p>
</dialog>
在 <dialog> 上套用 overflow: clip 也不會執行任何動作。
問題在於檢視畫面轉換建構及算繪虛擬樹狀結構的方式:
- 在虛擬樹狀結構中,所有快照預設互為同層級。
- 虛擬樹狀結構會在
::view-transition虛擬元素中算繪,並在整份文件上方算繪。
具體來說,這個試用版的 DOM 樹狀結構如下所示:
html
├─ ::view-transition
│ ├─ ::view-transition-group(card)
│ │ └─ ::view-transition-image-pair(card)
│ │ ├─ ::view-transition-old(card)
│ │ └─ ::view-transition-new(card)
│ ├─ ::view-transition-group(name)
│ │ └─ ::view-transition-image-pair(name)
│ │ ├─ ::view-transition-old(name)
│ │ └─ ::view-transition-new(name)
│ ├─ ::view-transition-group(avatar)
│ │ └─ ::view-transition-image-pair(avatar)
│ │ ├─ ::view-transition-old(avatar)
│ │ └─ ::view-transition-new(avatar)
│ ├─ ::view-transition-group(paragraph1.text)
│ │ └─ ::view-transition-image-pair(paragraph1.text)
│ │ └─ ::view-transition-new(paragraph1.text)
│ └─ ::view-transition-group(paragraph2.text)
│ └─ ::view-transition-image-pair(paragraph2.text)
│ └─ ::view-transition-new(paragraph2.text)
├─ head
└─ body
└─ …
由於 ::view-transition-group(.text) 虛擬元素是 ::view-transition-group(card) 虛擬元素的後續同層元素,因此會繪製在資訊卡上方。
如要讓 ::view-transition-group(card) 裁剪 ::view-transition-group(.text),::view-transition-group(.text) 虛擬元素應為 ::view-transition-group(card) 的子項。為此,請使用 view-transition-group,為產生的 ::view-transition-group() 虛擬元素指派「父項群組」。
如要變更上層群組,有以下兩種方法:
- 在上層,將
view-transition-group設為contain,使其包含所有具有view-transition-name的子項。 - 在所有子項上,將
view-transition-group設為父項的view-transition-name。您也可以使用nearest指定最接近的上層群組。
因此,在這個示範中,如要使用巢狀檢視畫面轉換群組,程式碼會變成:
button.clicked,
dialog {
view-transition-group: contain;
}
或
button.clicked,
dialog *,
view-transition-group: nearest;
}
加入這段程式碼後,::view-transition-group(.text) 虛擬元素現在會巢狀嵌入 ::view-transition-group(card) 虛擬元素中。這是在額外的 ::view-transition-group-children(…) 虛擬元素中完成,可將所有巢狀虛擬元素放在一起:
html
├─ ::view-transition
│ ├─ ::view-transition-group(card)
│ │ ├─::view-transition-group-children(card)
│ │ │ ├─ ::view-transition-group(paragraph1.text)
│ │ │ │ └─ ::view-transition-image-pair(paragraph1.text)
│ │ │ │ └─ ::view-transition-new(paragraph1.text)
│ │ │ └─ ::view-transition-group(paragraph2.text)
│ │ │ └─ ::view-transition-image-pair(paragraph2.text)
│ │ │ └─ ::view-transition-new(paragraph2.text)
│ │ └─ ::view-transition-image-pair(card)
│ │ ├─ ::view-transition-old(card)
│ │ └─ ::view-transition-new(card)
│ ├─ ::view-transition-group(name)
│ │ └─ ::view-transition-image-pair(name)
│ │ ├─ ::view-transition-old(name)
│ │ └─ ::view-transition-new(name)
│ └─ ::view-transition-group(avatar)
│ └─ ::view-transition-image-pair(avatar)
│ ├─ ::view-transition-old(avatar)
│ └─ ::view-transition-new(avatar)
├─ head
└─ body
└─ …
最後,如要讓 ::view-transition-group(card) 虛擬元素裁剪段落,請將 overflow: clip 套用至 ::view-transition-group-children(card) 虛擬元素:
::view-transition-group-children(card) {
overflow: clip;
}
結果如下:
現場示範
Demo 錄音
Demo 錄音 (慢速版)
只有在使用巢狀群組時,才會出現 ::view-transition-group-children 虛擬元素。其大小會調整為原始元素的邊框方塊,並提供透明邊框,其形狀和邊框粗細與產生虛擬元素的元素相同,即上一個範例中的 card。
剪輯和其他功能
巢狀檢視畫面轉換群組用於剪輯效果以外的地方。另一個例子是 3D 效果。在以下示範中,有一個選項可在轉場期間以 3D 旋轉資訊卡。
html:active-view-transition-type(open) {
&::view-transition-old(card) {
animation-name: rotate-out;
}
&::view-transition-new(card) {
animation-name: rotate-in;
}
}
html:active-view-transition-type(close) {
&::view-transition-old(card) {
animation-name: rotate-in;
}
&::view-transition-new(card) {
animation-name: rotate-out;
}
}
如果沒有巢狀檢視畫面轉換群組,顯示圖片和名稱就不會隨著資訊卡旋轉。
現場示範
Demo 錄音
Demo 錄音 (慢速版)
只要將顯示圖片和名稱虛擬元素嵌套在資訊卡內,就能還原 3D 效果。但這並非唯一需要執行的操作。除了輪替 ::view-transition-old(card) 和 ::view-transition-new(card) 虛擬金鑰外,您也需要輪替 ::view-transition-group-children(card) 虛擬金鑰。
html:active-view-transition-type(open) {
&::view-transition-group-children(card) {
animation: rotate-in var(--duration) ease;
backface-visibility: hidden;
}
}
html:active-view-transition-type(close) {
&::view-transition-group-children(card) {
animation: rotate-out var(--duration) ease;
backface-visibility: hidden;
}
}
現場示範
Demo 錄音
Demo 錄音 (慢速版)
更多示範
在以下範例中,巢狀檢視轉換群組用於確保資訊卡會由其祖系捲動器裁剪。您可以使用內建控制項,切換是否使用巢狀檢視畫面轉換群組。
現場示範
Demo 錄音
這個示範的有趣之處在於,所有 ::view-transition-group(.card) 虛擬元素都會巢狀置於上層 ::view-transition-group(cards) 虛擬元素中,並由該元素裁剪。#targeted-card 則不包含在內,因為其進入/退出動畫不應由 ::view-transition-group(cards) 裁剪。
/* The .cards wrapper contains all children */
.cards {
view-transition-name: cards;
view-transition-group: contain;
}
/* Contents that bleed out get clipped */
&::view-transition-group-children(cards) {
overflow: clip;
}
/* Each card is given a v-t-name and v-t-class */
.card {
view-transition-name: match-element;
view-transition-class: card;
}
/* The targeted card is given a unique name (to style the pseudo differently)
and shouldn't be contained by the ::view-transition-group-children(cards) pseudo */
#targeted-card {
view-transition-name: targeted-card;
view-transition-group: none;
}
重點回顧
巢狀檢視畫面轉場效果可讓您在建構虛擬元素時,保留 DOM 樹狀結構的部分拓撲。這可解鎖各種先前無法透過檢視畫面轉換達成的效果,其中一些效果已在本文中說明。
巢狀結構會變更檢視畫面轉場效果的建構模式,可用於建立進階效果。如前所述,元素範圍檢視轉換也可以透過更簡單的模型,達成部分效果。建議您試用這兩項功能,找出最符合需求的選項。