Dipublikasikan: 22 Sep 2025
Saat Anda memulai transisi tampilan, browser akan otomatis mengambil snapshot sebelum dan sesudah elemen yang diberi tag view-transition-name
. Snapshot ini dirender dalam struktur elemen semu. Secara default, hierarki yang dihasilkan adalah "datar". Artinya, hierarki asli di DOM akan hilang, dan semua grup transisi tampilan yang diambil menjadi elemen saudara di bawah satu elemen semu ::view-transition
.
Pendekatan hierarki datar ini sudah cukup untuk banyak kasus penggunaan, tetapi ada beberapa kasus penggunaan gaya yang tidak dapat dicapai dengannya. Berikut adalah contoh efek yang dapat memiliki efek visual yang tidak terduga dalam hierarki datar:
- Pemangkasan (
overflow
,clip-path
,border-radius
): pemangkasan memengaruhi elemen turunan, yang berarti bahwa elemen sekelompok transisi tampilan tidak dapat saling memangkas. opacity
,mask-image
, danfilter
: demikian pula, efek ini dirancang untuk berfungsi pada gambar pohon yang sepenuhnya di-raster, memengaruhi turunan, bukan memengaruhi setiap item satu per satu.- Transformasi 3D (
transform-style
,transform
,perspective
): untuk menampilkan rentang penuh animasi transformasi 3D, beberapa hierarki harus dipertahankan.
Contoh berikut menunjukkan pseudo-tree datar, dengan elemen yang dipangkas oleh ancestor di pohon DOM. Elemen ini kehilangan klipingnya selama transisi tampilan, sehingga menghasilkan efek visual yang rusak.
Grup transisi tampilan bertingkat adalah ekstensi untuk transisi tampilan yang memungkinkan Anda menyusun elemen semu ::view-transition-group
satu sama lain. Saat grup transisi tampilan disarangkan, efek seperti pemangkasan dapat dipulihkan selama transisi.
Browser Support
Dari pseudo-tree datar ke pseudo-tree bertingkat
Dalam demo berikut, Anda dapat mengklik avatar seseorang untuk melihat info selengkapnya tentang orang tersebut. Animasi ditangani oleh transisi tampilan dokumen yang sama yang mengubah tombol yang diklik menjadi dialog, memindahkan avatar dan nama di seluruh layar, serta menggeser paragraf dari dialog ke atas atau ke bawah.
Demo Langsung
Rekaman Demo
Rekaman Demo (Diperlambat)
Jika Anda melihat demo dengan cermat, Anda akan melihat bahwa ada masalah dengan transisi: meskipun paragraf dengan deskripsi adalah turunan dari elemen <dialog>
dalam DOM, teks tidak dipangkas oleh kotak <dialog>
selama transisi:
<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>
Menerapkan overflow: clip
pada <dialog>
juga tidak akan melakukan apa pun.
Masalahnya adalah cara transisi tampilan membangun dan merender pseudo tree-nya:
- Dalam pseudo-tree, secara default, semua snapshot adalah saudara kandung satu sama lain.
- Pseudo-tree dirender dalam elemen semu
::view-transition
yang dirender di atas seluruh dokumen.
Khusus untuk demo ini, hierarki DOM terlihat seperti berikut:
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
└─ …
Karena pseudo ::view-transition-group(.text)
adalah saudara kandung yang berhasil dari pseudo ::view-transition-group(card)
, pseudo ::view-transition-group(.text)
akan digambar di atas kartu.
Agar memiliki klip ::view-transition-group(card)
::view-transition-group(.text)
, pseudo ::view-transition-group(.text)
harus merupakan turunan dari ::view-transition-group(card)
. Untuk melakukannya, gunakan view-transition-group
yang memungkinkan Anda menetapkan "grup induk" untuk elemen semu ::view-transition-group()
yang dihasilkan.
Untuk mengubah grup induk, Anda memiliki dua opsi:
- Pada induk, tetapkan
view-transition-group
kecontain
, agar induk berisi semua turunan denganview-transition-name
. - Pada semua turunan, tetapkan
view-transition-group
keview-transition-name
induk. Anda juga dapat menggunakannearest
untuk menargetkan grup induk terdekat.
Jadi, untuk demo ini, guna menggunakan grup transisi tampilan bertingkat, kodenya menjadi:
button.clicked,
dialog {
view-transition-group: contain;
}
Atau
button.clicked,
dialog *,
view-transition-group: nearest;
}
Dengan adanya kode ini, pseudo ::view-transition-group(.text)
kini disarangkan di dalam pseudo ::view-transition-group(card)
. Hal ini dilakukan dalam pseudo ::view-transition-group-children(…)
tambahan, yang menjaga semua pseudo bertingkat tetap bersama:
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
└─ …
Terakhir, agar ::view-transition-group(card)
memangkas paragraf secara semu, terapkan overflow: clip
ke pseudo ::view-transition-group-children(card)
:
::view-transition-group-children(card) {
overflow: clip;
}
Hasilnya adalah sebagai berikut:
Demo Langsung
Rekaman Demo
Rekaman Demo (Diperlambat)
Pseudo ::view-transition-group-children
hanya ada saat grup bertingkat digunakan. Ukuran elemen ini disesuaikan dengan border-box elemen asli dan diberi batas transparan dengan bentuk dan ketebalan batas yang sama dengan elemen yang menghasilkan elemen semu—card
dalam contoh sebelumnya.
Kliping dan lainnya
Grup transisi tampilan bertingkat digunakan di tempat selain efek pemangkasan. Contoh lainnya adalah efek 3D. Dalam demo berikut, ada opsi untuk memutar kartu dalam 3D selama transisi.
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;
}
}
Tanpa grup transisi tampilan bertingkat, avatar dan nama tidak berputar bersama kartu.
Demo Langsung
Rekaman Demo
Rekaman Demo (Diperlambat)
Dengan menyusun avatar dan nama semu di dalam kartu, efek 3D dapat dipulihkan. Namun, bukan hanya itu yang perlu Anda lakukan. Selain memutar pseudo ::view-transition-old(card)
dan ::view-transition-new(card)
, Anda juga perlu memutar pseudo ::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 Langsung
Rekaman Demo
Rekaman Demo (Diperlambat)
Demo lainnya
Dalam contoh berikut, grup transisi tampilan bertingkat digunakan untuk memastikan kartu dipangkas oleh scroller induknya. Anda dapat mengaktifkan atau menonaktifkan penggunaan grup transisi tampilan bertingkat menggunakan kontrol yang disertakan.
Demo Langsung
Rekaman Demo
Hal menarik tentang demo ini adalah semua pseudo ::view-transition-group(.card)
disarangkan di dalam—dan dipangkas oleh—pseudo ::view-transition-group(cards)
induk. #targeted-card
dikecualikan karena animasi masuk/keluarnya tidak boleh terpotong oleh ::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;
}
Rekap
Transisi tampilan bertingkat memungkinkan Anda mempertahankan beberapa topologi hierarki DOM saat membuat elemen semu. Hal ini memungkinkan berbagai efek yang sebelumnya tidak mungkin dilakukan dengan transisi tampilan, beberapa di antaranya kami jelaskan di sini.
Penyusunan bertingkat mengubah model cara transisi tampilan dibuat, dan dimaksudkan untuk digunakan dalam membuat efek lanjutan. Seperti yang disebutkan, transisi tampilan cakupan elemen juga dapat menghasilkan sebagian efek dengan model yang lebih sederhana. Sebaiknya coba kedua fitur ini untuk memutuskan mana yang paling sesuai dengan kebutuhan Anda.