การจัดสไตล์เนื้อหาใน Slot
pseudo-element ::slotted(selector) ช่วยให้คุณเขียน CSS rules ภายใน shadow root เพื่อกำหนดเป้าหมาย node ใน light DOM ที่ถูก project เข้าไปใน <slot> เมื่อผู้ใช้วาง <p> หรือ <strong> ไว้ภายใน custom element ของคุณ node เหล่านั้นยังคงอยู่ใน light DOM แต่ถูก render ให้เห็นภายใน shadow tree — ::slotted() คือวิธีจัดสไตล์ node เหล่านั้นจากภายใน
::slotted(p) { color: steelblue; }::slotted(strong) { color: #e11d48; }rule ข้างต้นอยู่ภายในบล็อก <style> ของ shadow ของ component element <p> หรือ <strong> ใดๆ ที่ผู้ใช้ slot เข้ามาใน component จะได้รับสไตล์เหล่านั้น
ข้อจำกัด
หัวข้อที่มีชื่อว่า “ข้อจำกัด”::slotted() สามารถ match ได้เฉพาะ node ที่ถูก slot โดยตรงระดับบนสุด — children โดยตรงของ host ที่ตกลงไปอยู่ใน slot ไม่สามารถเข้าถึง subtree ของ element ที่ถูก slot ได้:
::slotted(div span)ไม่ ทำงาน — คุณไม่สามารถกำหนดเป้าหมาย<span>ที่ซ้อนอยู่ภายใน<div>ที่ถูก slot ได้- เฉพาะ compound selectors ที่มี slotted element ระดับเดียวเท่านั้นที่ถูกต้อง
- specificity ของ
::slotted()ต่ำ — เทียบเท่ากับ(0,0,1,0)— ดังนั้นสไตล์ของหน้าบน element เดียวกันสามารถชนะได้
หากคุณต้องการควบคุม subtree ที่ถูก slot ในระดับลึกขึ้น ให้ปรับโครงสร้าง HTML ของคุณเพื่อ slot element ในสุดโดยตรง หรือส่ง CSS custom properties เข้าไปใน shadow root จากหน้า
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
::slotted() จาก shadow root | ผู้เขียน component กำหนด default style ให้เนื้อหาที่ถูก slot ได้ โดยผู้ใช้ไม่ต้องเขียน CSS เองเลย | match ได้เฉพาะ node ที่ถูก slot โดยตรงระดับบนสุดเท่านั้น ควบคุม subtree ลึกไม่ได้ และ specificity ต่ำ ทำให้ page CSS override ได้ง่าย |
| ปล่อยให้หน้าจัดสไตล์ light DOM เอง / ส่ง custom properties เข้าไป | ผู้ใช้ควบคุม styling ของเนื้อหาตัวเองได้เต็มที่อยู่แล้วเพราะเป็น light DOM ไม่ต้องพึ่ง ::slotted() เลย | component author เสียการควบคุม default appearance ถ้าไม่ตั้ง baseline ไว้เลย เนื้อหาที่ slot เข้ามาอาจดูไม่สอดคล้องกับ component |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- คาดหวังว่า descendant selector ใน
::slotted()จะทำงาน — เขียน::slotted(p) span {}แล้วคาดว่าจะจัดสไตล์spanที่ซ้อนอยู่ในpที่ถูก slot ได้ แต่ไวยากรณ์นี้ ไม่ถูกต้อง —::slotted()match ได้แค่ตัว element ที่ถูก slot โดยตรงระดับบนสุดเท่านั้น ไม่ใช่ descendant ของตัวเอง - ใช้ compound selector ลึกอย่าง
::slotted(div span)— คาดว่าจะกำหนดเป้าหมายspanที่ซ้อนอยู่ในdivที่ถูก slot ได้ แต่ spec อนุญาตให้ match ได้เฉพาะ compound selector ระดับเดียวกับ slotted node เท่านั้น - ลืมว่า specificity ของ
::slotted()ต่ำ — เทียบเท่ากับ(0,0,1,0)เท่านั้น ทำให้สไตล์ของหน้าที่กำหนดเป้าหมาย element เดียวกันโดยตรงสามารถชนะได้อย่างเงียบ ๆ โดยไม่ต้องใช้!important
💡 ตัวอย่างจากของจริง
Shoelace — component อย่าง
<sl-card>ใช้::slotted()ตั้ง margin เริ่มต้นให้ content ที่ผู้ใช้ slot เข้ามา เผื่อผู้ใช้ไม่ได้ตั้งสไตล์เอง โดยยอมรับข้อจำกัดว่าปรับได้แค่ node ระดับบนสุดAdobe Spectrum (Spectrum Web Components) — เลือกส่ง CSS custom properties เข้าไปในบาง component แทนการพึ่ง
::slotted()ลึก ๆ เพราะโครงสร้างเนื้อหาที่ผู้ใช้ slot เข้ามามักซับซ้อนเกินกว่าที่ selector ระดับตื้นจะจัดการได้