發布日期: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
從扁平的虛擬樹狀結構到巢狀虛擬樹狀結構
在下列試用版中,您可以點選使用者的個人資料相片,查看該使用者的詳細資訊。動畫是由同文件檢視區塊轉場效果處理,可將點選的按鈕變形為對話方塊、在畫面上移動大頭貼和名稱,以及上下滑動對話方塊中的段落。
現場示範
示範錄音
示範錄音 (慢速)
仔細觀察示範,您會發現轉場效果有問題:即使說明段落是 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-image-pair(card)
│ │ │ ├─ ::view-transition-old(card)
│ │ │ └─ ::view-transition-new(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-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;
}
結果如下:
現場示範
示範錄音
示範錄音 (慢速)
只有在使用巢狀群組時,才會出現 ::view-transition-group-children
虛擬元素。大小會調整為原始元素的 border-box,並提供透明邊框,形狀和邊框粗細與產生虛擬元素的元素相同,也就是上一個範例中的 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;
}
}
如果沒有巢狀檢視區塊轉場效果群組,頭像和名稱就不會隨著卡片旋轉。
現場示範
示範錄音
示範錄音 (慢速)
將虛擬人偶和名稱虛擬元素巢狀內嵌至資訊卡中,即可還原 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;
}
}
現場示範
示範錄音
示範錄音 (慢速)
更多示範
在下列範例中,巢狀檢視區塊轉換群組用於確保卡片會遭到祖先捲軸裁剪。您可以使用隨附的控制項,切換是否要使用巢狀檢視畫面轉場群組。
現場示範
示範錄音
這個範例的有趣之處在於,所有 ::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 樹狀結構的拓撲。這項功能可解鎖各種效果,是先前檢視區塊轉場效果無法實現的,我們已在此處說明部分效果。
巢狀結構會改變建構檢視區塊轉場效果的模型,適用於建立進階效果。如前所述,元素範圍的檢視畫面轉場效果也能以較簡單的模型,達成部分效果。建議您試用這兩項功能,找出最符合需求的功能。