Menjalankan transisi tampilan serentak dan bertingkat dengan transisi tampilan cakupan elemen

Dipublikasikan: 27 Mar 2026

Transisi tampilan cakupan elemen memungkinkan beberapa transisi tampilan berjalan secara bersamaan, memungkinkan transisi tampilan yang sedang berlangsung disarangkan dalam transisi tampilan lain, dan menyelesaikan masalah z-index yang mungkin Anda alami dengan transisi tampilan cakupan dokumen—sekaligus menjaga agar bagian halaman lainnya tetap interaktif. Baca panduan ini untuk mempelajari cara menggunakannya.

Video promosi: Membayangkan kembali web dengan Transisi Tampilan Berlingkup. Coba demo langsung (Chrome 147 atau yang lebih baru)

Kebutuhan akan transisi tampilan dengan cakupan yang lebih sempit

Saat Anda memulai transisi tampilan dalam dokumen yang sama dengan document.startViewTransition() (atau melalui padanannya lintas dokumen), browser akan mencakup transisi tampilan yang dihasilkan ke dokumen.

Setelah callback update dieksekusi dan browser mengambil semua elemen yang diperlukan, overlay ::view-transition yang dihasilkan dan hierarki elemen semunya dilampirkan ke elemen :root, html dalam contoh berikut.

html
  ├─ ::view-transition
  │  └─ ::view-transition-group(root)
  │     └─ ::view-transition-image-pair(root)
  │        ├─ ::view-transition-old(root)
  │        └─ ::view-transition-new(root)
  ├─ head
  └─ body
     └─ …

Karena lapisan ::view-transition dirender di atas root transisi, hal ini dapat menyebabkan situasi yang tidak terduga. Misalnya, elemen yang berpartisipasi dalam transisi tampilan dapat tiba-tiba tumpang-tindih dengan elemen non-peserta lainnya, atau elemen mungkin tidak lagi dipangkas oleh wrapper induknya selama transisi tampilan.

Demo Langsung

Rekaman Demo

Mengaktifkan kembali pointer-events di ::view-transition atau menggunakan grup transisi tampilan bertingkat dapat mengatasi beberapa efek samping yang ditimbulkan oleh transisi tampilan cakupan dokumen. Namun, metode ini tidak dapat menyelesaikan semua masalah.

Misalnya, elemen dengan position: fixed atau popover masih terhalang oleh transisi tampilan cakupan dokumen saat transisi aktif — juga dikenal sebagai masalah z-index.

Alihkan popover dalam demo berikut, lalu pilih tombol Acak untuk memulai transisi tampilan cakupan dokumen. Grup transisi tampilan bertingkat menyelesaikan masalah pemangkasan, tetapi masalah pelapisan tetap ada.

Demo Langsung

Rekaman Demo

Salah satu solusinya adalah mengambil popover sebagai bagian dari transisi tampilan dengan memberinya view-transition-name. Meskipun cara ini mungkin berfungsi untuk satu instance, cara ini sulit dipertahankan dan membebani proses pengambilan snapshot secara tidak perlu.

Transisi tampilan cakupan elemen

Transisi tampilan cakupan elemen memungkinkan Anda memulai transisi tampilan pada subtree DOM. Daripada memanggil document.startViewTransition(), Anda memanggil element.startViewTransition() pada elemen arbitrer, yang mencakup transisi tampilan ke elemen tersebut.

Dalam cuplikan berikut, browser memulai transisi tampilan cakupan elemen pada elemen <ul>.

document.querySelector('ul').startViewTransition({
  callback: () => {
    // … code that manipulates the contents of <ul>
  },
})

Elemen tempat Anda memanggil element.startViewTransition()—misalnya <ul>—disebut root transisi atau cakupan.

Saat browser mencakup transisi tampilan ke elemen, transisi tersebut diisolasi dari DOM lainnya:

  • Browser mencari elemen yang akan diambil snapshotnya hanya dalam subhierarki cakupan.
  • Selama proses pengambilan snapshot—saat callback update dijalankan—hanya rendering cakupan yang berhenti.
  • Hasil pohon semu ::view-transition disuntikkan ke root transisi.

Misalnya, dengan <ul>, hierarki DOM terlihat seperti ini saat transisi tampilan aktif:

html
  ├─ head
  └─ body
     ├─ ul
     │  ├─ ::view-transition
     │  │  └─ ::view-transition-group(root)
     │  │     ├─ ::view-transition-group-children(root)
     │  │     │  └─ …
     │  │     └─ ::view-transition-image-pair(root)
     │  │        ├─ ::view-transition-old(root)
     │  │        └─ ::view-transition-new(root)
     │  ├─ li
     │  ├─ li
     │  └─ li
     ├─ button#showpopover
     ├─ button#reorder
     └─ div#popover
        └─ p

Pseudo ::view-transition memiliki ukuran dan bentuk yang sama dengan root transisi dan hanya dirender di atas root transisi. Oleh karena itu, urutan lapisan elemen di luar root transisi akan dipertahankan.

Misalnya, jika Anda memiliki popover yang terlihat di atas elemen <ul>, lalu memulai transisi tampilan cakupan elemen pada elemen <ul>, popover tidak akan tertutup oleh pseudo-tree transisi tampilan.

Coba demo berikut. Alat ini memiliki dua tombol. Tombol pertama mengalihkan popover, dan tombol kedua menyusun ulang item daftar menggunakan transisi tampilan yang tercakup elemen.

Demo Langsung

Rekaman Demo

Karena transisi tampilan cakupan elemen digunakan, popover tetap terlihat di atas elemen <ul> saat transisi aktif.

Selain itu, elemen di luar elemen <ul>—misalnya tombol—tetap interaktif, karena elemen tersebut bukan bagian dari cakupan.

Cakupan yang berpartisipasi sendiri dan grup transisi tampilan bertingkat

Saat Anda memulai transisi tampilan cakupan elemen pada elemen yang memangkas overflow-nya (yaitu, saat overflow-nya disetel ke hidden, scroll, atau clip), Anda akan melihat bahwa konten transisi tampilan tetap dipangkas secara visual.

Hal ini karena transisi tampilan cakupan elemen menangani hal berikut secara otomatis:

  • Cakupan otomatis diterapkan view-transition-name: root, yang membuatnya berpartisipasi sendiri.
  • Cakupan otomatis diterapkan view-transition-group: contain untuk mengaktifkan grup transisi tampilan bertingkat.
  • Pseudo ::view-transition-group-children(root) yang dihasilkan akan otomatis memangkas kontennya menggunakan overflow: clip jika root cakupan memangkas overflow-nya, yang mencegah pseudo keluar secara visual dari root transisi.

Dengan demikian, Anda dapat menjaga CSS yang digunakan dengan transisi tampilan cakupan elemen hanya berfokus pada elemen yang ingin Anda ambil. Misalnya, dalam demo daftar, CSS hanya menambahkan nama ke item daftar:

ul li {
  view-transition-name: match-element;
  view-transition-class: album;
}

Coba demo berikut. Hal ini memungkinkan Anda mengganti partisipasi sendiri. Jika cakupan bersifat berpartisipasi sendiri (perilaku default), semuanya akan berfungsi seperti yang diharapkan. Jika cakupan tidak berpartisipasi sendiri, batasnya akan langsung berubah, dan kontennya akan keluar dari wrapper selama transisi.

Demo Langsung

Rekaman Demo

Sebagai referensi, pseudo-tree untuk demo ini dengan partisipasi mandiri terlihat seperti ini:

html
  ├─ head
  └─ body
     ├─ ul
     │  ├─ ::view-transition
     │  │  └─ ::view-transition-group(root)
     │  │     ├─ ::view-transition-group-children(root)
     │  │     │  ├─ ::view-transition-group(item1)
     │  │     │  │  └─ ::view-transition-image-pair(item1)
     │  │     │  │     ├─ ::view-transition-old(item1)
     │  │     │  │     └─ ::view-transition-new(item1)
     │  │     │  ├─ ::view-transition-group(item2)
     │  │     │  │  └─ …
     │  │     │  …
     │  │     └─ ::view-transition-image-pair(root)
     │  │        ├─ ::view-transition-old(root)
     │  │        └─ ::view-transition-new(root)
     │  ├─ li
     │  ├─ li
     │  └─ li
     └─ button#reorder

Karena root transisi, elemen <ul>, memangkas kontennya secara vertikal, ::view-transition-group-children(root) juga otomatis menerapkan klip.

Transisi tampilan cakupan elemen serentak

Karena transisi tampilan cakupan elemen berjalan secara terpisah, beberapa transisi tampilan cakupan elemen dapat berjalan secara bersamaan jika memiliki cakupan yang berbeda.

Demo berikut memiliki dua tombol pengurutan ulang, satu untuk setiap daftar. Setiap tombol memulai transisi tampilan yang tercakup elemen hanya pada daftarnya masing-masing. Karena hierarki DOM kedua daftar tidak tumpang-tindih, kedua transisi tampilan cakupan elemen dapat berjalan secara bersamaan secara terpisah.

Demo Langsung

Rekaman Demo

Sifat terisolasi ini juga memungkinkan Anda menggunakan kembali nilai view-transition-name di berbagai cakupan. Selama nama tetap unik dalam cakupannya, tidak ada konflik.

Transisi tampilan dengan cakupan elemen bertingkat dan penampungan view-transition-name

Jika pohon DOM dari beberapa transisi tampilan cakupan elemen tumpang-tindih, ada risiko tabrakan nilai view-transition-name. Oleh karena itu, browser secara otomatis menetapkan view-transition-scope: all ke transisi tampilan cakupan elemen aktif untuk mengurangi risiko ini.

Mirip dengan cara anchor-scope mencakup nilai anchor-name, properti view-transition-scope memastikan bahwa nilai view-transition-name dicakup ke subpohon elemen. Properti ini menerima none, daftar nama yang cakupannya ingin Anda tetapkan, atau all untuk menetapkan cakupan semua nilai.

Selain mencegah nama meluber, view-transition-scope juga mencegah elemen dan isinya direkam oleh transisi tampilan serentak yang lebih luar. Saat proses pengambilan snapshot melintasi subhierarki untuk menemukan elemen yang akan diambil snapshot-nya, proses ini akan mengabaikan elemen (dan seluruh subhierarkinya) yang menerapkan view-transition-scope: all. Hal ini mengasumsikan bahwa elemen tersebut sudah berpartisipasi dalam transisi tampilan cakupan elemen yang berbeda.

Demo berikut adalah variasi dari demo sebelumnya. Selain dua tombol yang mengacak konten daftar, tombol ini juga memiliki tombol Tukar untuk menukar daftar. Mengalihkan class .reversed pada #lists-wrapper menangani pertukaran.

Demo Langsung

Rekaman Demo

Karena view-transition-scope: all diterapkan secara otomatis selama transisi pengacakan, Anda dapat memulai transisi pertukaran luar yang bersamaan saat transisi pengacakan masih berlangsung.

Karena view-transition-scope: all juga mencegah elemen diambil screenshot dalam transisi luar, demo juga menambahkan nilai view-transition-name ke elemen yang membungkus elemen <ul>.

#list1-wrapper, #list2-wrapper {
  view-transition-name: attr(id type(<custom-ident>));
}

Pseudo-tree untuk demo ini, setelah memulai pengacakan pada daftar kedua, lalu menukar kedua daftar, akan terlihat seperti ini:

html
  ├─ head
  └─ body
     └─ #lists-wrapper.reversed (SCOPE)
        ├─ ::view-transition
        │  └─ ::view-transition-group(lists-wrapper)
        │     ├─ ::view-transition-group-children(lists-wrapper)
        │     │  ├─ ::view-transition-group(list1-wrapper)
        │     │  │  └─ ::view-transition-image-pair(list1-wrapper)
        │     │  │     ├─ ::view-transition-old(list1-wrapper)
        │     │  │     └─ ::view-transition-new(list1-wrapper)
        │     │  └─ ::view-transition-group(list2-wrapper)
        │     │     └─ ::view-transition-image-pair(list2-wrapper)
        │     │        ├─ ::view-transition-old(list2-wrapper)
        │     │        └─ ::view-transition-new(list2-wrapper)
        │     └─ ::view-transition-image-pair(lists-wrapper)
        │        ├─ ::view-transition-old(lists-wrapper)
        │        └─ ::view-transition-new(lists-wrapper)
        ├─ div#list1-wrapper
        │  ├─ ul
        │  │  ├─ li#item1
        │  │  ├─ li#item2
        │  │  └─ li#item3
        │  └─ button.reorder
        └─ div#list2-wrapper
           ├─ ul (SCOPE)
           │  ├─ ::view-transition
           │  │  └─ ::view-transition-group(list)
           │  │     ├─ ::view-transition-group-children(list    )
           │  │     │  ├─ ::view-transition-group(item4)
           │  │     │  │  └─ ::view-transition-image-pair(item4)
           │  │     │  │     ├─ ::view-transition-old(item4)
           │  │     │  │     └─ ::view-transition-new(item4)
           │  │     │  ├─ ::view-transition-group(item5)
           │  │     │  │  └─ …
           │  │     │  …
           │  │     └─ ::view-transition-image-pair(list)
           │  │        ├─ ::view-transition-old(list)
           │  │        └─ ::view-transition-new(list)
           │  ├─ li#item4
           │  ├─ li#item5
           │  └─ li#item6
           └─ button.reorder

Pelajari lebih lanjut

Untuk mempelajari lebih lanjut transisi tampilan cakupan elemen, lihat penjelasan, spesifikasi css-view-transitions-2, dan daftar pengeditan spesifikasi terbuka.