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

Nama CSS yang ditetapkan oleh penulis dan shadow DOM seharusnya bisa digunakan bersama. Namun, browser tidak konsisten dengan spesifikasi, terkadang dengan masing-masing satu lagi, dan setiap nama CSS tidak konsisten dengan cara yang sedikit berbeda.

Artikel ini mendokumentasikan status terkini perilaku nama CSS yang ditetapkan penulis lintas cakupan bayangan, dengan harapan menjadi 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, awalnya diperkenalkan untuk aturan @keyframes, yang menentukan <keyframe-name> sebagai ID khusus atau string. Tujuan dari 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 lain yang menggunakan nama CSS adalah font, deklarasi properti, kueri container, dan yang baru-baru ini menampilkan transisi, penempatan anchor, dan animasi berbasis scroll. Tabel tidak komprehensif berikut ini menyertakan nama yang diperiksa statusnya.

Fitur Pernyataan nama Referensi nama
Frame utama @keyframes animation-name
Font @font-face { }
@font-palette-values
font-family
font-palette
Pernyataan Properti @property Semua properti khusus
Lihat transisi view-transition-name
view-transition-class
::view-transition-group()
Pemosisian Anchor anchor-name position-anchor
Animasi berbasis scroll animation-timeline view-timeline-name
scroll-timeline-name
Gaya penghitung @counter-style
Counter-reset
counter-set
counter-increment
list-style
Kueri container container-name @container
Variabel CSS --something var(--something)
Halaman @page

Seperti yang dapat dilihat dalam tabel, name CSS biasanya memiliki CSS yang sesuai referensi ini. Misalnya, animation-name adalah referensi ke @keyframes nama. Nama CSS berbeda dengan nama yang ditetapkan dalam DOM, seperti atribut serta nama tag, seperti yang dideklarasikan, kemudian direferensikan dalam konteks spreadsheet gaya.

Bagaimana nama berhubungan dengan shadow DOM

Sementara nama CSS dibuat untuk menciptakan hubungan antara berbagai bagian dokumen atau stylesheet, Shadow DOM adalah dibuat untuk melakukan hal sebaliknya. IA mengenkapsulasi hubungan sehingga tidak bocor komponen web yang seharusnya memiliki namespace sendiri.

Dengan menyatukan nama CSS dan shadow DOM, pengalaman penyusunan komponen web harus terasa cukup ekspresif untuk bisa fleksibel tetapi terkendala untuk stabil.

Teori ini bagus. Dalam praktiknya, browser tidak konsisten dengan cara CSS nama berinteroperasi dengan shadow DOM, keduanya di antara fitur yang sama browser, di seluruh browser, serta di antara fitur dan spesifikasi.

Cara nama dan shadow DOM bekerja sama

Untuk memahami masalahnya, penting untuk memahami bagaimana bagian-bagian CSS ini harus bekerja sama secara teori.

Aturan umum

Aturan umum tentang bagaimana nama CSS berperilaku di seluruh pohon bayangan didefinisikan dalam Spesifikasi Cakupan CSS Level 1. Ringkasnya: nama CSS bersifat global di dalam cakupan tempat nama tersebut didefinisikan, yang berarti dapat diakses dari pohon bayangan turunan, tetapi tidak dari pohon seinduk atau pohon bayangan nenek moyang. 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 lain, properti CSS tidak dienkapsulasi oleh shadow DOM. Sebaliknya, ini adalah cara umum untuk meneruskan parameter pada bayangan yang berbeda pohon. Hal ini membuat Deskripsi @property spesial: seharusnya berperilaku seperti deklarasi tipe {i>document-global<i} yang menentukan cara properti bernama berfungsi. Karena properti harus cocok di seluruh pohon bayangan, ketidakcocokan deklarasi properti akan menyebabkan hasil, sehingga deklarasi @property ditentukan untuk diratakan dan di-resolve sesuai dengan urutan dokumen.

Cara kerja aturan dengan ::part

Bagian bayangan mengekspos elemen dalam pohon bayangan ke pohon induknya. Dengan demikian, struktur induk dapat mengakses elemen tersebut serta menata gayanya menggunakan ::part .

Karena ::part mengizinkan dua cakupan hierarki untuk menata gaya elemen yang sama, ditentukan urutannya:

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

Ini berarti bahwa nama dari dalam shadow DOM tidak bisa direferensikan dari ::part, karena ::part adalah gaya cakupan host, bukan cakupan bayangan gaya. 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 secara terprogram menggunakan skrip, akan menjadi cakupan tempat elemen yang akan digunakan. Itu karena untuk menerapkan gaya ke elemen yang perlu Anda akses {i>handle<i} elemen, dan kemudian ke akar bayangan itu sendiri.

Cara nama CSS dan shadow DOM bekerja sama dalam kenyataan

Meskipun aturan sebelumnya telah didefinisikan dengan baik dan konsisten, aturan yang tidak selalu mencerminkan hal itu. Dalam praktiknya, @property berfungsi secara berbeda dari spesifikasi secara konsisten di seluruh {i>browser<i}, dan sebagian besar fitur lainnya memiliki {i>bug<i} terbuka (beberapa di antaranya adalah belum dirilis, jadi masih ada waktu untuk memperbaikinya).

Untuk menguji dan mendemonstrasikan cara kerja fitur ini dalam praktiknya, 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 harus Anda.
  • Referensi luar ke nama bagian dalam: ini seharusnya tidak berfungsi, karena akan berarti nama yang didefinisikan dalam konteks bayangan telah bocor.
  • Referensi dalam ke nama luar: ini seharusnya berfungsi, sebagai nama cakupan hierarki diwarisi oleh akar bayangan.
  • Inner reference to inner name: ini seharusnya berfungsi, baik karena merupakan nama berada dalam cakupan yang sama.
  • Referensi ::part ke nama luar: ini seharusnya berfungsi, baik karena ::part dan namanya dideklarasikan dalam cakupan yang sama.
  • Referensi ::part ke nama dalam: ini seharusnya tidak berfungsi, karena cakupan luar seharusnya tidak mendapatkan pengetahuan tentang nama yang dideklarasikan di dalam shadow DOM.

@keyframes

Seperti yang didefinisikan dalam spesifikasi, Anda seharusnya dapat mereferensikan nama keyframe dari dalam root bayangan, selama @keyframes pada aturan berada dalam ancestor ruang lingkup proyek. Dalam praktiknya, tidak ada browser yang menerapkan perilaku ini, dan keyframe hanya dapat dirujuk dalam ruang lingkup di mana definisi tersebut didefinisikan. Lihat masalah 10540.

@property

Sebagaimana ditentukan dalam spesifikasi, setiap deklarasi @property akan diratakan ke ruang lingkup dokumen. Namun saat ini, di semua browser, Anda hanya dapat deklarasikan @property dalam cakupan dokumen dan pernyataan @property dalam akar bayangan diabaikan.
Lihat masalah 10541.

Bug khusus browser

Fitur lainnya tidak menunjukkan perilaku yang konsisten di seluruh browser:

  • @font-face disatukan ke cakupan root di Safari.
  • Chromium tidak mengizinkan pewarisan aturan @anchor-name dalam 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 dalam root bayangan.
  • view-transition-class dapat ditentukan di dalam root bayangan (transisi itu sendiri berada di luar shadow-root).
  • Firefox memungkinkan ::part mengakses nama bayangan dalam (kueri container, keyframe).
  • Firefox dan Safari tidak mematuhi @counter-style dalam root bayangan.

Perhatikan bahwa counter-reset, counter-set, counter-increment memiliki sedikit aturan yang berbeda karena merupakan nama implisit, dan mendeklarasikan properti CSS memiliki seperangkat aturan yang mapan dan teruji dengan baik.

Kesimpulan

Kabar buruknya adalah ketika memeriksa {i>snapshot<i} dari status interop saat ini sehubungan dengan nama CSS dan {i>shadow DOM<i}, pengalaman itu tidak konsisten dan banyak bug. Tidak ada fitur yang telah kita pelajari di sini berperilaku konsisten di seluruh browser dan sesuai dengan spesifikasi. Kabar baiknya adalah bahwa delta untuk membuat pengalaman konsisten adalah daftar {i>bug<i} dan masalah spesifikasi. Mari kita perbaiki. Sementara itu, ringkasan ini diharapkan dapat membantu jika Anda mengalami kesulitan dengan inkonsistensi yang dijelaskan dalam artikel ini.