การ Encapsulate สไตล์
Shadow boundary คืออะไร?
หัวข้อที่มีชื่อว่า “Shadow boundary คืออะไร?”Shadow boundary คือเส้นกั้นที่ป้องกันไม่ให้ CSS รั่วผ่าน shadow root เส้นกั้นนี้ทำงานสองทิศทาง:
- สไตล์ที่ประกาศ ภายใน shadow root จะไม่ส่งผลต่อ element ใดๆ ใน light DOM
- selector CSS จาก ภายนอก shadow root ไม่สามารถกำหนดเป้าหมาย element ภายใน shadow tree ได้
ลักษณะนี้เรียกว่า style encapsulation และเป็นหนึ่งในคุณประโยชน์หลักของ Shadow DOM
สไตล์ใน shadow ไม่รั่วออก
หัวข้อที่มีชื่อว่า “สไตล์ใน shadow ไม่รั่วออก”ลองดู shadow element ที่ประกาศ .box { color: red; } ไว้ภายใน shadow root:
class EncDemo extends HTMLElement { connectedCallback() { this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = '<style>.box { color: red; font-weight: bold; }</style>' + '<div class="box">Red — shadow style</div>'; }}กฎ .box { color: red; } นี้ไม่มีผลใดๆ เลยต่อ element .box ที่อยู่นอก component ตัวนี้
สไตล์ของหน้าอยู่แค่ภายนอก
หัวข้อที่มีชื่อว่า “สไตล์ของหน้าอยู่แค่ภายนอก”ลองดู CSS ระดับหน้าที่กำหนดเป้าหมายไปที่ .box:
/* page stylesheet */.box { color: blue; font-weight: bold; border: 2px solid blue;}กฎนี้ใช้กับ .box ทุกตัวใน light DOM แต่ไม่ใช้กับ .box ที่อยู่ภายใน shadow root ของ <enc-demo> shadow boundary กันมันไว้
หลักฐานเชิงภาพ
หัวข้อที่มีชื่อว่า “หลักฐานเชิงภาพ”ตัวอย่างด้านล่างมี .box สอง element ที่ใช้ class name เดียวกัน ตัวที่อยู่นอก custom element ถูกสไตล์เป็นสีฟ้าโดย page CSS ส่วนตัวที่อยู่ใน shadow root ถูกสไตล์เป็นสีแดงโดย shadow CSS ไม่มีสไตล์ไหนข้ามขอบเขตไปหาอีกฝั่งเลย
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
| Style encapsulation (shadow boundary) | สไตล์ของ component ไม่ชนกับสไตล์หน้าโดยไม่ตั้งใจ ปลอดภัยต่อการนำไปใช้ซ้ำ | ธีมจากภายนอกเข้าถึง internal ไม่ได้โดยตรง ต้องพึ่ง CSS custom properties หรือ ::part แทน |
| ไม่ใช้ Shadow DOM (global CSS ธรรมดา) | ปรับสไตล์จากภายนอกได้อิสระ ไม่ต้องเปิด API เพิ่ม | เสี่ยง class name ชนกัน และสไตล์รั่วเข้า-ออกโดยไม่ตั้งใจเมื่อโปรเจกต์โต |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- คาดหวังให้ CSS หน้าเว็บ selector ธรรมดาเข้าไปสไตล์ภายใน shadow root ได้ — เช่นเขียน
.my-widget .title { color: red }แล้วสงสัยว่าทำไมไม่ทำงาน shadow boundary ถูกออกแบบมาให้กันแบบนี้โดยเจตนา - ลืมว่า class name ข้างในและข้างนอก shadow root เป็นคนละ scope — ตั้ง
.boxทั้งสองฝั่งแล้วคิดว่าต้องแก้ไขให้ไม่ชนกัน ทั้งที่จริงๆ ไม่ชนกันอยู่แล้วเพราะ encapsulation - ไม่รู้ว่ามี escape hatch อย่าง CSS custom properties และ
::part— พอ styling จากภายนอกไม่ได้เลยเลิกใช้ Shadow DOM ทั้งที่ควรออกแบบ custom property API ให้ theme ได้แบบควบคุมได้
💡 ตัวอย่างจากของจริง
Salesforce Lightning (LWC) — ใช้ style encapsulation เพื่อให้ component นับพันตัวจากทีมต่างๆ ไม่ชนสไตล์กันใน enterprise app ขนาดใหญ่ (salesforce/lwc)