ชื่อ CSS ที่ผู้เขียนกำหนดและ Shadow DOM: เป็นไปตามข้อกำหนดและในทางปฏิบัติ

ชื่อ CSS ที่กําหนดโดยผู้เขียนและ Shadow DOM ควรทํางานร่วมกัน อย่างไรก็ตาม เบราว์เซอร์ไม่สอดคล้องกับข้อกำหนด และบางครั้งก็ใช้ชื่อ CSS ที่ไม่สอดคล้องกัน และชื่อ CSS แต่ละชื่อก็มีความไม่สอดคล้องกันเล็กน้อย

บทความนี้จะบันทึกสถานะปัจจุบันของลักษณะการทํางานของชื่อ CSS ที่กําหนดโดยผู้เขียนในขอบเขตเงา โดยหวังว่าบทความนี้จะใช้เป็นแนวทางในการปรับปรุงความสามารถในการทำงานร่วมกันในอนาคตอันใกล้

ชื่อ CSS ที่ผู้เขียนกำหนดคืออะไร

ชื่อ CSS ที่นักเขียนกำหนดเป็นกลไกไวยากรณ์ CSS ที่ค่อนข้างเก่า ซึ่งเดิมทีมีไว้สำหรับกฎ @keyframes ซึ่งกำหนด <keyframe-name> เป็นตัวระบุที่กำหนดเองหรือสตริง แนวคิดนี้มีไว้เพื่อประกาศบางอย่างในส่วนหนึ่งของสไตล์ชีต แล้วอ้างอิงในส่วนอื่น

/* "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;
}

ฟีเจอร์อื่นๆ ของ CSS ที่ใช้ชื่อ CSS ได้แก่ แบบอักษร การประกาศพร็อพเพอร์ตี้ การค้นหาคอนเทนเนอร์ และล่าสุดคือการเปลี่ยนมุมมอง การจัดตำแหน่งจุดยึด และภาพเคลื่อนไหวที่ทำงานด้วยการเลื่อน ตารางต่อไปนี้ไม่ได้ครอบคลุมทั้งหมด แต่มีชื่อของรายการที่ Chrome ตรวจสอบสถานะ

ฟีเจอร์ การประกาศชื่อ การอ้างอิงชื่อ
คีย์เฟรม @keyframes animation-name
แบบอักษร @font-face { }
@font-palette-values
font-family
font-palette
การประกาศพร็อพเพอร์ตี้ @property
การประกาศพร็อพเพอร์ตี้ที่กำหนดเองซึ่งไม่ได้ลงทะเบียน
var()
ดูการเปลี่ยน view-transition-name
view-transition-class
::view-transition-* องค์ประกอบจำลอง
ตำแหน่งโฆษณา Anchor anchor-name position-anchor
ภาพเคลื่อนไหวที่ทำงานตามการเลื่อน view-timeline-name
scroll-timeline-name
animation-timeline
รูปแบบรายการ @counter-style list-style
ตัวนับ counter-reset
counter-set
counter-increment
การค้นหาคอนเทนเนอร์ container-name @container
หน้าเว็บ page @page

ดังที่เห็นในตาราง ชื่อ CSS มักจะมีข้อมูลอ้างอิง CSS ที่เกี่ยวข้อง เช่น animation-name เป็นการอ้างอิงถึงชื่อ @keyframes ชื่อ CSS แตกต่างจากชื่อที่กําหนดใน DOM เช่น แอตทริบิวต์และชื่อแท็ก เนื่องจากมีการประกาศชื่อแล้วอ้างอิงภายในบริบทของสไตล์ชีต

ความสัมพันธ์ของชื่อกับ Shadow DOM

แม้ว่าชื่อ CSS จะสร้างขึ้นเพื่อสร้างความสัมพันธ์ระหว่างส่วนต่างๆ ของเอกสารหรือสไตล์ชีต แต่ Shadow DOM สร้างขึ้นเพื่อทําตรงกันข้าม โดยจะรวมความสัมพันธ์ไว้เพื่อไม่ให้ความสัมพันธ์ดังกล่าวแสดงในคอมโพเนนต์เว็บที่ควรจะเป็นเนมสเปซของตัวเอง

การนำชื่อ CSS และ Shadow DOM มารวมกันจะทำให้ประสบการณ์การคอมโพสิทคอมโพเนนต์เว็บมีความยืดหยุ่นมากพอ แต่ก็มีข้อจำกัดมากพอที่จะคงเสถียร

แนวคิดนี้ฟังดูดี ในทางปฏิบัติ เบราว์เซอร์ใช้ชื่อ CSS โต้ตอบกับ Shadow DOM อย่างไม่สอดคล้องกัน ทั้งระหว่างฟีเจอร์ในเบราว์เซอร์เดียวกัน เบราว์เซอร์ต่างๆ และระหว่างฟีเจอร์กับข้อกำหนด

วิธีที่ชื่อและ Shadow DOM ควรทํางานร่วมกัน

ในการทำความเข้าใจปัญหานี้ คุณควรทำความเข้าใจว่าส่วนต่างๆ ของ CSS ควรทำงานร่วมกันอย่างไรในทางทฤษฎี

กฎทั่วไป

กฎทั่วไปสำหรับลักษณะการทำงานของชื่อ CSS ในทรีเงาจะระบุไว้ในข้อกำหนดระดับ 1 เกี่ยวกับการกำหนดขอบเขต CSS สรุปคือ ชื่อ CSS จะเป็นแบบส่วนกลางภายในขอบเขตที่กำหนด ซึ่งหมายความว่าสามารถเข้าถึงได้จากต้นไม้เงาของรายการที่สืบทอด แต่เข้าถึงจากต้นไม้เงาของรายการพี่น้องหรือบรรพบุรุษไม่ได้ โปรดทราบว่าชื่อนี้แตกต่างจากชื่อในแพลตฟอร์มเว็บ เช่น รหัสองค์ประกอบ ซึ่งจะรวมอยู่ในขอบเขตต้นไม้เดียวกัน

ข้อยกเว้นของกฎ: @property

พร็อพเพอร์ตี้ CSS ไม่ได้อยู่ภายใน Shadow DOM ต่างจากชื่อ CSS อื่นๆ แต่เป็นเพียงวิธีทั่วไปในการส่งพารามิเตอร์ไปยัง Shadow Tree ต่างๆ ด้วยเหตุนี้ ตัวบ่งชี้ @property จึงมีความพิเศษ เนื่องจากควรจะทํางานเหมือนการประกาศประเภทระดับเอกสารที่กําหนดวิธีทํางานของพร็อพเพอร์ตี้ที่มีชื่อหนึ่งๆ เนื่องจากพร็อพเพอร์ตี้ต้องตรงกันทั่วทั้งต้นไม้เงา การประกาศพร็อพเพอร์ตี้ที่ไม่ตรงกันจะทำให้เกิดผลลัพธ์ที่ไม่คาดคิด ดังนั้นจึงมีการระบุการประกาศ @property ให้ยุบและแก้ไขตามลําดับเอกสาร

วิธีที่กฎควรทํางานกับ ::part

ชิ้นส่วนเงาจะแสดงองค์ประกอบภายในต้นไม้เงาต่อต้นไม้หลัก ซึ่งจะทำให้ต้นไม้หลักเข้าถึงองค์ประกอบนั้นได้และจัดรูปแบบโดยใช้องค์ประกอบ ::part ด้วย

เนื่องจาก ::part อนุญาตให้สโคปต้นไม้ 2 รายการจัดสไตล์องค์ประกอบเดียวกัน ระบบจึงระบุลําดับการแสดงผลตามลำดับต่อไปนี้

  1. ก่อนอื่น ให้ตรวจสอบสไตล์ภายในบริบทเงา รูปแบบนี้เป็นรูปแบบ "เริ่มต้น" ของชิ้นส่วน
  2. จากนั้นใช้รูปแบบภายนอกตามที่ระบุไว้ใน ::part นี่คือสไตล์ "ที่กำหนดเอง" ของชิ้นส่วน
  3. จากนั้นใช้สไตล์ภายในที่กําหนดไว้ร่วมกับ !important ซึ่งช่วยให้องค์ประกอบที่กำหนดเองประกาศได้ว่า ::part ไม่สามารถปรับแต่งพร็อพเพอร์ตี้บางอย่างของส่วนใดส่วนหนึ่งได้

ซึ่งหมายความว่าชื่อจากภายใน Shadow DOM จะอ้างอิงจาก ::part ไม่ได้ เนื่องจาก ::part เป็นสไตล์ระดับโฮสต์ ไม่ใช่สไตล์ระดับ Shadow เช่น

// 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;  
}

วิธีที่กฎควรทำงานร่วมกับสไตล์ในบรรทัด

รูปแบบแทรกในบรรทัดที่มีแอตทริบิวต์ style หรือรูปแบบที่ตั้งค่าสไตล์โดยใช้สคริปต์แบบเป็นโปรแกรมจะกำหนดขอบเขตตามขอบเขตขององค์ประกอบนั้นๆ ซึ่งต่างจาก ::part เนื่องจากหากต้องการใช้สไตล์กับองค์ประกอบ คุณต้องมีสิทธิ์เข้าถึงแฮนเดิลองค์ประกอบ และเข้าถึงรูทเงาได้

วิธีที่ชื่อ CSS และ Shadow DOM ทํางานร่วมกันในชีวิตจริง

แม้ว่ากฎข้างต้นจะชัดเจนและสอดคล้องกัน แต่การใช้งานในปัจจุบันอาจไม่ได้เป็นไปตามกฎดังกล่าวเสมอไป ในทางปฏิบัติ @property ทำงานแตกต่างจากข้อกำหนดในลักษณะที่สอดคล้องกันในเบราว์เซอร์ต่างๆ และฟีเจอร์อื่นๆ ส่วนใหญ่ยังมีข้อบกพร่องอยู่ (บางฟีเจอร์ยังไม่ได้เปิดตัว จึงมีเวลาแก้ไข)

เราได้สร้างหน้าต่อไปนี้เพื่อทดสอบและสาธิตวิธีการทำงานของฟีเจอร์เหล่านี้จริง https://css-names-in-the-shadow.glitch.me/ หน้านี้มี iframe หลายรายการ โดยแต่ละรายการจะมุ่งเน้นที่ฟีเจอร์ใดฟีเจอร์หนึ่งและทดสอบสถานการณ์ 6 รูปแบบ ดังนี้

  • การอ้างอิงภายนอกถึงชื่อภายนอก: ไม่มี Shadow DOM ที่เกี่ยวข้อง วิธีนี้น่าจะใช้ได้
  • การอ้างอิงภายนอกถึงชื่อภายใน: การดำเนินการนี้ไม่ควรใช้งานได้ เนื่องจากจะหมายความว่าชื่อที่กําหนดไว้ในบริบทเงามีการรั่วไหล
  • การอ้างอิงภายในถึงชื่อภายนอก: การดำเนินการนี้ควรใช้งานได้ เนื่องจากรูทเงาจะรับค่าชื่อระดับต้นไม้
  • การอ้างอิงภายในถึงชื่อภายใน: การดำเนินการนี้ควรใช้งานได้ เนื่องจากทั้งชื่อการอ้างอิงอยู่ในขอบเขตเดียวกัน
  • การอ้างอิง ::part ไปยังชื่อภายนอก: การดำเนินการนี้ควรใช้งานได้ เนื่องจากทั้ง ::part และชื่อได้รับการประกาศในสโคปเดียวกัน
  • ::part การอ้างอิงชื่อภายใน: การดำเนินการนี้ไม่ควรทำงานเนื่องจากขอบเขตภายนอกไม่ควรได้รับข้อมูลเกี่ยวกับชื่อที่ประกาศภายใน Shadow DOM

@keyframes

ตามที่กำหนดไว้ในข้อกำหนด คุณควรอ้างอิงชื่อเฟรมหลักได้จากภายในรูทเงา ตราบใดที่ @keyframes at-rule อยู่ในขอบเขตของบรรพบุรุษ ในทางปฏิบัติ ไม่มีเบราว์เซอร์ใดใช้ลักษณะการทำงานนี้ และคำจำกัดความของคีย์เฟรมจะอ้างอิงได้ในขอบเขตที่กำหนดเท่านั้น ดูปัญหา 10540

@property

ตามที่กำหนดไว้ในข้อกำหนด การประกาศ @property ใดๆ จะได้รับการยุบรวมให้อยู่ในขอบเขตเอกสาร แต่ในปัจจุบัน คุณประกาศ @property ได้เฉพาะในสโกปเอกสารในเบราว์เซอร์ทุกประเภท และระบบจะไม่สนใจการประกาศ @property ภายในรูทเงา
ดูปัญหา 10541

ข้อบกพร่องเฉพาะเบราว์เซอร์

ฟีเจอร์อื่นๆ แสดงลักษณะการทำงานที่ไม่สอดคล้องกันในเบราว์เซอร์ต่างๆ ดังนี้

  • @font-face จะยุบเป็นขอบเขตรูทใน Safari
  • Chromium ไม่อนุญาตให้รับค่ากฎ anchor-name ในรูทเงา
  • scroll-timeline-name และ view-timeline-name ไม่ได้กําหนดขอบเขตอย่างถูกต้องใน ::part (และใน Chromium ด้วย)
  • ไม่มีเบราว์เซอร์ใดอนุญาตให้ประกาศ @font-palette-values ในรูทเงา
  • view-transition-class สามารถกําหนดภายในรูทเงา (ทรานซิชันอยู่นอกรูทเงา)
  • Firefox อนุญาตให้ ::part เข้าถึงชื่อเงาภายใน (การค้นหาคอนเทนเนอร์ เฟรมหลัก)
  • Firefox และ Safari ไม่สนใจ @counter-style ในรูทเงา

โปรดทราบว่า counter-reset, counter-set, counter-increment มีกฎที่ต่างกันเล็กน้อยเนื่องจากเป็นชื่อที่ระบุไว้โดยนัย และการประกาศพร็อพเพอร์ตี้ CSS มีชุดกฎที่กำหนดไว้และผ่านการทดสอบอย่างดี

บทสรุป

ข่าวร้ายคือเมื่อตรวจสอบภาพรวมสถานะการทำงานร่วมกันในปัจจุบันเกี่ยวกับชื่อ CSS และ Shadow DOM พบว่าประสบการณ์การใช้งานไม่สอดคล้องกันและมีข้อบกพร่อง ไม่มีฟีเจอร์ใดที่เราตรวจสอบที่นี่ทำงานอย่างสอดคล้องกันในเบราว์เซอร์ต่างๆ และเป็นไปตามข้อกำหนด ข่าวดีคือความแตกต่างที่จะทำให้ประสบการณ์การใช้งานสอดคล้องกันนั้นมีจำนวนจำกัด นั่นคือรายการข้อบกพร่องและปัญหาเกี่ยวกับข้อกำหนด มาแก้ปัญหานี้กัน ในระหว่างนี้ เราหวังว่าภาพรวมนี้จะช่วยคุณได้หากพบปัญหาเกี่ยวกับความไม่สอดคล้องตามที่อธิบายไว้ในบทความนี้