Nama CSS dan shadow DOM yang ditetapkan penulis: Dalam spesifikasi dan dalam praktik

Nama CSS yang ditentukan penulis dan shadow DOM seharusnya berfungsi bersama. Namun, browser tidak konsisten dengan spesifikasi, terkadang dengan browser lain, dan setiap nama CSS tidak konsisten dengan cara yang sedikit berbeda.

Artikel ini mendokumentasikan status saat ini tentang perilaku nama CSS yang ditentukan penulis di seluruh cakupan bayangan, dengan harapan dapat berfungsi sebagai panduan untuk meningkatkan interoperabilitas dalam waktu dekat.

Apa yang dimaksud dengan nama CSS yang ditentukan penulis?

Nama CSS yang ditentukan penulis adalah mekanisme sintaksis CSS yang relatif lama, yang awalnya diperkenalkan untuk aturan @keyframes, yang menentukan <keyframe-name> sebagai identitas kustom atau string. Tujuan konsep ini adalah untuk mendeklarasikan sesuatu di satu bagian stylesheet, dan merujuknya di bagian lain.

/* "fade-in" is a CSS name, representing a set of keyframes */
@keyframes fade-in {
  from { opacity: 0 };
  to { opacity: 1 }
}

.card {
  /* "fade-in" is a reference to the above keyframes */
  animation-name: fade-in;
}

Fitur CSS lainnya yang menggunakan nama CSS adalah font, deklarasi properti, kueri penampung, dan transisi tampilan, posisi anchor, dan animasi yang didorong scroll yang lebih baru. Tabel non-komprehensif berikut menyertakan nama yang statusnya diperiksa oleh Chrome.

Fitur Pernyataan nama Referensi nama
Frame utama @keyframes animation-name
Font @font-face { }
@font-palette-values
font-family
font-palette
Deklarasi Properti @property
Deklarasi properti kustom yang tidak terdaftar
var()
Melihat transisi view-transition-name
view-transition-class
::view-transition-* elemen pseudo
Penempatan Anchor anchor-name position-anchor
Animasi berbasis scroll view-timeline-name
scroll-timeline-name
animation-timeline
Gaya daftar @counter-style list-style
Penghitung counter-reset
counter-set
counter-increment
Kueri penampung container-name @container
Halaman page @page

Seperti yang dapat Anda lihat dalam tabel, nama CSS biasanya memiliki referensi CSS yang sesuai. Misalnya, animation-name adalah referensi ke nama @keyframes. Nama CSS berbeda dengan nama yang ditentukan di DOM, seperti atribut dan nama tag, karena dideklarasikan, lalu dirujuk dalam konteks stylesheet.

Hubungan nama dengan shadow DOM

Meskipun nama CSS dibuat untuk membuat hubungan antara berbagai bagian dokumen atau stylesheet, Shadow DOM dibuat untuk melakukan hal sebaliknya. Class ini mengenkapsulasi hubungan sehingga tidak bocor di seluruh komponen web yang seharusnya memiliki namespace-nya sendiri.

Dengan menggabungkan nama CSS dan shadow DOM, pengalaman dalam menyusun komponen web akan terasa cukup ekspresif agar fleksibel, tetapi cukup dibatasi agar stabil.

Hal ini bagus secara teori. Dalam praktiknya, browser tidak konsisten dalam cara nama CSS beroperasi dengan shadow DOM, baik di antara fitur dalam browser yang sama, di seluruh browser, maupun di antara fitur dan spesifikasi.

Cara nama dan shadow DOM harus bekerja sama

Untuk memahami masalahnya, sebaiknya pahami cara kerja bagian-bagian CSS ini secara teori.

Aturan umum

Aturan umum tentang perilaku nama CSS di seluruh hierarki bayangan ditentukan dalam spesifikasi CSS Scoping Level 1. Untuk meringkas: nama CSS bersifat global di dalam cakupan tempatnya ditentukan, yang berarti nama tersebut dapat diakses dari hierarki turunan, tetapi tidak dari hierarki saudara atau hierarki induk. Perhatikan bahwa ini tidak seperti nama di platform web seperti ID elemen, yang dienkapsulasi dalam cakupan hierarki yang sama.

Pengecualian untuk aturan: @property

Tidak seperti nama CSS lainnya, properti CSS tidak dienkapsulasi oleh shadow DOM. Sebaliknya, ini adalah cara umum untuk meneruskan parameter di berbagai hierarki bayangan. Hal ini membuat deskripsi @property khusus: deskripsi ini seharusnya berperilaku seperti deklarasi jenis global dokumen yang menentukan cara kerja properti bernama tertentu. Karena properti harus cocok di seluruh hierarki bayangan, ketidakcocokan deklarasi properti akan menghasilkan hasil yang tidak terduga, sehingga deklarasi @property ditentukan untuk diratakan dan diselesaikan sesuai dengan urutan dokumen.

Cara kerja aturan dengan ::part

Bagian bayangan mengekspos elemen di dalam hierarki bayangan ke hierarki induknya. Dengan demikian, hierarki induk dapat mengakses elemen tersebut dan juga menata gayanya menggunakan elemen ::part.

Karena ::part memungkinkan dua cakupan hierarki menata gaya elemen yang sama, urutan cascade berikut ditentukan:

  1. Pertama, periksa gaya di dalam konteks bayangan. Ini adalah gaya "default" bagian.
  2. Kemudian, terapkan gaya eksternal seperti yang ditentukan di ::part. Ini adalah gaya "kustom" bagian.
  3. Kemudian, terapkan gaya internal apa pun yang ditentukan bersama dengan !important. Hal ini memungkinkan elemen kustom mendeklarasikan bahwa properti tertentu dari bagian tertentu tidak dapat disesuaikan oleh ::part.

Artinya, nama dari dalam shadow DOM tidak dapat direferensikan dari ::part, karena ::part adalah gaya cakupan host, bukan gaya cakupan bayangan. Contoh:

// inside the shadow DOM:
@keyframes fade-in {
  from { opacity: 0}
}

// This shouldn't work!
// The host style shouldn't know the name "fade-in"
::part(slider) {
  animation-name: fade-in;  
}

Cara kerja aturan dengan gaya inline

Tidak seperti ::part, gaya inline dengan atribut style, atau gaya yang menetapkan gaya secara terprogram menggunakan skrip, dicakup ke tempat elemen dicakup. Hal ini karena untuk menerapkan gaya ke elemen, Anda memerlukan akses ke handle elemen, dan dengan demikian ke root bayangan itu sendiri.

Cara nama CSS dan DOM bayangan bekerja sama dalam kenyataan

Meskipun aturan sebelumnya ditentukan dengan baik dan konsisten, penerapan saat ini tidak selalu mencerminkannya. Dalam praktiknya, @property berfungsi secara berbeda dari spesifikasi dengan cara yang konsisten di seluruh browser, dan sebagian besar fitur lainnya memiliki bug terbuka (beberapa di antaranya belum dirilis, jadi ada waktu untuk memperbaikinya).

Untuk menguji dan mendemonstrasikan cara kerja fitur ini dalam praktik, kami telah membuat halaman berikut: https://css-names-in-the-shadow.glitch.me/. Halaman ini memiliki beberapa iframe, masing-masing berfokus pada salah satu fitur dan menguji enam skenario:

  • Referensi luar ke nama luar: tidak ada shadow DOM yang terlibat, ini seharusnya berfungsi.
  • Referensi luar ke nama dalam: hal ini tidak akan berfungsi, karena hal itu berarti nama yang ditentukan dalam konteks bayangan telah bocor.
  • Referensi dalam ke nama luar: ini akan berfungsi, karena nama cakupan hierarki diwarisi oleh root bayangan.
  • Referensi dalam ke nama dalam: ini akan berfungsi, karena nama referensi berada dalam cakupan yang sama.
  • Referensi ::part ke nama luar: ini akan berfungsi, karena ::part dan nama dideklarasikan dalam cakupan yang sama.
  • Referensi ::part ke nama dalam: hal ini tidak akan berfungsi, karena cakupan luar tidak boleh mendapatkan pengetahuan tentang nama yang dideklarasikan di dalam shadow DOM.

@keyframes

Seperti yang ditentukan dalam spesifikasi, Anda harus dapat mereferensikan nama keyframe dari dalam root bayangan, selama aturan at @keyframes berada dalam cakupan ancestor. Dalam praktiknya, tidak ada browser yang menerapkan perilaku ini, dan definisi keyframe hanya dapat dirujuk dalam cakupan tempat definisi tersebut ditentukan. Lihat masalah 10540.

@property

Seperti yang ditentukan dalam spesifikasi, deklarasi @property apa pun akan diratakan ke cakupan dokumen. Namun, saat ini, di semua browser, Anda hanya dapat mendeklarasikan @property dalam cakupan dokumen dan deklarasi @property dalam root bayangan akan diabaikan.
Lihat masalah 10541.

Bug khusus browser

Fitur lainnya tidak menunjukkan perilaku yang konsisten di seluruh browser:

  • @font-face diratakan ke cakupan root di Safari.
  • Chromium tidak mengizinkan pewarisan aturan anchor-name di root bayangan
  • scroll-timeline-name dan view-timeline-name tidak dicakup dengan benar di ::part (juga di Chromium).
  • Tidak ada browser yang mengizinkan deklarasi @font-palette-values di root bayangan.
  • view-transition-class dapat ditentukan di dalam root bayangan (transisi itu sendiri berada di luar root bayangan).
  • Firefox memungkinkan ::part mengakses nama bayangan dalam (kueri penampung, keyframe).
  • Firefox dan Safari tidak mematuhi @counter-style di root bayangan.

Perhatikan bahwa counter-reset, counter-set, counter-increment memiliki aturan yang sedikit berbeda karena merupakan nama implisit, dan mendeklarasikan properti CSS memiliki kumpulan aturan yang telah ditetapkan dan diuji dengan baik.

Kesimpulan

Kabar buruknya adalah saat memeriksa snapshot status interop saat ini terkait nama CSS dan shadow DOM, pengalamannya tidak konsisten dan bermasalah. Tidak ada fitur yang kami periksa di sini yang berperilaku konsisten di seluruh browser dan sesuai dengan spesifikasi. Berita baiknya adalah delta untuk membuat pengalaman konsisten adalah daftar bug dan masalah spesifikasi yang terbatas. Mari kita perbaiki. Sementara itu, ringkasan ini semoga dapat membantu jika Anda mengalami inkonsistensi yang dijelaskan dalam artikel ini.