Kodokon kodokon.com

Cascade layers (@layer) และ @scope

เชี่ยวชาญเกณฑ์ cascade ใหม่สองอย่าง คือ layers และ scope proximity เพื่อออกแบบสถาปัตยกรรมสไตล์ของคุณโดยไม่ต้องทำสงคราม specificity

10 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

cascade แก้ไขข้อขัดแย้งของการประกาศต่าง ๆ โดยใช้เกณฑ์ที่เรียงลำดับไว้: origin และ importance, จากนั้นคือ context, แล้วสไตล์จากแอตทริบิวต์ style, จากนั้นคือ layers (@layer), แล้วจึงเป็น specificity และสุดท้ายคือลำดับการปรากฏ ประเด็นสำคัญคือ: layers ถูกประเมิน ก่อน specificity ดังนั้นกฎ .button ที่อยู่ในเลเยอร์ที่มีลำดับความสำคัญสูงกว่าจึงชนะ #nav div.menu a.button ที่อยู่ในเลเยอร์ที่ลำดับความสำคัญต่ำกว่า specificity ของมันที่ (1,2,2) ไม่มีความหมายเลยเมื่อเทียบกับลำดับของเลเยอร์ นี่คือสิ่งที่ทำให้ @layer ทรงพลังอย่างมากในการออกแบบสถาปัตยกรรม design system: ลำดับความสำคัญถูกประกาศเพียงครั้งเดียวในเชิงโครงสร้าง แทนที่จะต้องต่อสู้กันทีละเซเลกเตอร์

CSS
@layer reset, base, components, utilities;

@layer components {
  .button { background: rebeccapurple; }
}

@layer base {
  button { background: gray; }
}
การประกาศไว้ล่วงหน้าเป็นตัวกำหนดลำดับ: components ชนะ base เสมอ ไม่ว่าลำดับของบล็อกในไฟล์จะเป็นอย่างไร

มีรายละเอียดปลีกย่อยในสเปกสองอย่างที่คุณจำเป็นต้องรู้อย่างยิ่ง อย่างแรก: สไตล์ที่อยู่ นอกเลเยอร์ใด ๆ จะชนะสไตล์ที่อยู่ในเลเยอร์ (สำหรับการประกาศแบบปกติ) เพราะมันก่อตัวเป็นเลเยอร์โดยปริยายที่ถูกวางไว้เป็นลำดับสุดท้าย ดังนั้นการเขียนทับในระดับท้องถิ่นของคุณจึงชนะไลบรารีที่ใช้เลเยอร์เสมอ อย่างที่สอง: เมื่อใช้ !important ลำดับจะ กลับด้านโดยสิ้นเชิง เลเยอร์ที่ถูกประกาศก่อนจะชนะ และ !important ภายในเลเยอร์จะชนะ !important ที่อยู่นอกเลเยอร์ใด ๆ การประกาศ !important ในเลเยอร์ reset ของคุณจึงแทบจะเอาชนะไม่ได้เลย

CSS
@layer base, theme;

@layer base {
  a { color: black !important; }
}

@layer theme {
  a { color: purple !important; }
}
เมื่อใช้ !important ลำดับจะกลับด้าน: สีดำชนะเพราะ base ถูกประกาศก่อน

@scope จำกัดขอบเขตชุดของกฎไว้ระหว่าง scoping root และ ขอบเขตล่าง ที่ระบุหรือไม่ก็ได้: @scope (.card) to (.card__content) จะเล็งไปยังเอลิเมนต์ที่เป็นลูกหลานของ .card แต่อยู่นอก .card__content นี่คือ donut scope อันโด่งดัง ซึ่งเหมาะอย่างยิ่งสำหรับการจัดสไตล์กรอบของคอมโพเนนต์โดยไม่รั่วไหลเข้าไปในเนื้อหาที่ถูกฉีดเข้ามา ภายในขอบเขตนั้น :scope หมายถึงตัว root เอง และ @scope ยังนำเสนอเกณฑ์ cascade ใหม่เอี่ยม: proximity (ความใกล้) เมื่อ specificity เท่ากัน กฎที่มี scoping root อยู่ใกล้เอลิเมนต์มากที่สุดจะชนะ ซึ่งเป็นสิ่งที่ทั้ง BEM หรือ combinator ก็ไม่เคยแสดงออกมาได้

CSS
@scope (.card) to (.card__content) {
  :scope {
    padding: 1rem;
    border: 1px solid oklch(0.85 0.02 260);
  }
  img { border-radius: 8px; }
}
เอลิเมนต์ img ในกรอบของ .card จะถูกเล็งเป้า ส่วนที่ถูกฉีดเข้าไปใน .card__content จะอยู่นอกขอบเขต

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. ด้วย @layer a, b; และการประกาศแบบปกติสองรายการที่มี specificity เท่ากัน อยู่ใน a หนึ่งและ b หนึ่ง อันไหนจะมีผล?
    • อันที่อยู่ในเลเยอร์ a ซึ่งถูกประกาศก่อน
    • อันที่อยู่ในเลเยอร์ b เพราะเลเยอร์ที่ถูกประกาศเป็นลำดับสุดท้ายชนะ
    • อันที่ปรากฏล่าสุดในไฟล์ โดยไม่สนใจเลเยอร์
  2. การประกาศแบบปกติที่อยู่นอกเลเยอร์ใด ๆ ต้องเผชิญกับการประกาศแบบปกติที่วางอยู่ในเลเยอร์ ผลลัพธ์เป็นอย่างไร?
    • การประกาศที่อยู่ในเลเยอร์ชนะเสมอ
    • การประกาศที่ไม่ได้ใช้เลเยอร์ชนะ
    • specificity ของเซเลกเตอร์เป็นตัวตัดสิน
    • เบราว์เซอร์รายงานว่าเกิดข้อขัดแย้ง
  3. ใน @scope (.card) to (.card__content) กฎภายในสามารถเล็งเป้าไปยังเอลิเมนต์ใดได้บ้าง?
    • ลูกหลานทั้งหมดของ .card โดยไม่มีข้อยกเว้น
    • ลูกหลานของ .card ที่อยู่นอก .card__content (donut scope)
    • เฉพาะ .card__content และลูก ๆ ของมันเท่านั้น