Dipublikasikan: 22 September 2025
Saat Anda memulai transisi tampilan, browser akan otomatis mengambil snapshot sebelum dan sesudah elemen yang diberi tag dengan view-transition-name. Snapshot ini dirender dalam hierarki elemen semu. Secara default, hierarki yang dihasilkan adalah "flat". Artinya, hierarki asli dalam DOM akan hilang, dan semua grup transisi tampilan yang diambil adalah turunan 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 dengan pendekatan ini. Berikut adalah contoh efek yang dapat memiliki efek visual yang tidak diharapkan dalam hierarki datar:
- Pemangkasan (
overflow,clip-path,border-radius): pemangkasan memengaruhi turunan elemen, yang berarti bahwa elemen seinduk grup transisi tampilan tidak dapat saling memangkas. opacity,mask-image, danfilter: demikian pula, efek ini dirancang untuk berfungsi pada gambar hierarki yang sepenuhnya dirasterisasi, yang memengaruhi turunan, bukan memengaruhi setiap item satu per satu.- Transformasi 3D (
transform-style,transform,perspective): untuk menampilkan berbagai animasi transformasi 3D, beberapa hierarki perlu dipertahankan.
Contoh berikut menunjukkan hierarki semu datar, dengan elemen yang diklip oleh ancestor dalam hierarki 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 bertingkat elemen semu ::view-transition-group dalam satu sama lain. Jika grup transisi tampilan disusun bertingkat, Anda dapat memulihkan efek seperti pemangkasan selama transisi.
Browser Support
Dari pohon semu datar ke pohon semu 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, dan menggeser paragraf dari dialog ke atas atau ke bawah.
Demo Langsung
Rekaman Demo
Rekaman Demo (Versi lambat)
Jika Anda melihat demo dengan cermat, Anda akan melihat bahwa ada masalah dengan transisi: meskipun paragraf dengan deskripsi adalah turunan dari elemen <dialog> di DOM, teks tidak dipotong 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 berpengaruh apa pun.
Masalahnya adalah cara transisi tampilan membangun dan merender hierarki semu:
- Dalam pseudo-tree, secara default, semua snapshot adalah setara satu sama lain.
- Pseudo-tree dirender dalam elemen pseudo
::view-transitionyang 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 elemen seinduk yang berhasil dari pseudo ::view-transition-group(card), pseudo tersebut digambar di atas kartu.
Agar ::view-transition-group(card) memotong ::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-groupkecontain, agar berisi semua turunan denganview-transition-name. - Di semua turunan, tetapkan
view-transition-groupkeview-transition-nameinduk. Anda juga dapat menggunakannearestuntuk menargetkan grup ancestor terdekat.
Jadi, untuk demo ini, agar dapat menggunakan grup transisi tampilan bertingkat, kodenya menjadi:
button.clicked,
dialog {
view-transition-group: contain;
}
Atau
button.clicked,
dialog *,
view-transition-group: nearest;
}
Dengan kode ini, pseudo ::view-transition-group(.text) kini disusun bertingkat di dalam pseudo ::view-transition-group(card). Hal ini dilakukan dalam pseudo ::view-transition-group-children(…) tambahan, yang menyatukan semua pseudo bertingkat:
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
└─ …
Terakhir, agar pseudo ::view-transition-group(card) memotong paragraf, 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 (Versi lambat)
Pseudo ::view-transition-group-children hanya ada jika grup bertingkat digunakan. Ukurannya disesuaikan dengan kotak batas elemen asli dan diberi batas transparan dengan bentuk dan ketebalan batas yang sama dengan elemen yang menghasilkan elemen pseudo—card dalam contoh sebelumnya.
Pemotongan 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 akan berputar bersama kartu.
Demo Langsung
Rekaman Demo
Rekaman Demo (Versi lambat)
Dengan menyusun bertingkat pseudo avatar dan nama di dalam kartu, efek 3D dapat dipulihkan. Namun, itu bukan satu-satunya hal yang perlu Anda lakukan. Selain merotasi pseudo ::view-transition-old(card) dan ::view-transition-new(card), Anda juga perlu merotasi 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 (Versi lambat)
Demo lainnya
Dalam contoh berikut, grup transisi tampilan bertingkat digunakan untuk memastikan kartu dipangkas oleh scroller ancestor-nya. Anda dapat mengaktifkan atau menonaktifkan penggunaan grup transisi tampilan bertingkat menggunakan kontrol yang disertakan.
Demo Langsung
Rekaman Demo
Hal yang menarik dari demo ini adalah semua pseudo ::view-transition-group(.card) disusun bertingkat di dalam—dan diklip oleh—pseudo ::view-transition-group(cards) ancestor. #targeted-card dikecualikan karena animasi masuk/keluarnya tidak boleh dipotong 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;
}
Rangkuman
Transisi tampilan bertingkat memungkinkan Anda mempertahankan beberapa topologi hierarki DOM saat membuat elemen pseudo. 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 guna membuat efek lanjutan. Seperti yang telah disebutkan, transisi tampilan cakupan elemen juga dapat mencapai subset efek dengan model yang lebih sederhana. Sebaiknya coba kedua fitur tersebut untuk menentukan mana yang paling sesuai dengan kebutuhan Anda.