การเรียงซ้อนเลเยอร์จะพร้อมใช้งานในเบราว์เซอร์ของคุณ

เลเยอร์ตามลำดับชั้น (@layer กฎ CSS) จะพร้อมใช้งานใน Chromium 99, Firefox 97 และ Safari 15.4 เบต้า ซึ่งช่วยให้ควบคุมไฟล์ CSS ได้อย่างชัดเจนมากขึ้นเพื่อป้องกันความขัดแย้งเฉพาะสไตล์ ซึ่งจะเป็นประโยชน์อย่างยิ่งสำหรับฐานโค้ดขนาดใหญ่ ระบบการออกแบบ และเมื่อต้องจัดการสไตล์ของบุคคลที่สามในแอปพลิเคชัน

การจัดเรียง CSS ในลักษณะที่ชัดเจนจะช่วยป้องกันไม่ให้เกิดการลบล้างสไตล์ที่ไม่คาดคิดและส่งเสริมสถาปัตยกรรม CSS ที่ดีขึ้น

ความเฉพาะเจาะจงของ CSS และลําดับชั้น

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

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

ภาพ BEM ของการ์ดที่มีชั้นเรียน
ตัวอย่างภาพของการเรียกชื่อ BEM จาก keepinguptodate.com

เลเยอร์ Cascade มีไว้เพื่อแก้ปัญหานี้ โดยจะเพิ่มเลเยอร์ใหม่ในลำดับชั้น CSS เมื่อใช้สไตล์ที่วางซ้อนกัน ลำดับความสำคัญของเลเยอร์จะเหนือกว่าความเฉพาะเจาะจงของตัวเลือกเสมอ

เช่น ตัวเลือก .post a.link มีความเฉพาะเจาะจงมากกว่า .card a หากพยายามจัดรูปแบบลิงก์ภายในการ์ดในโพสต์ คุณจะเห็นว่ามีการใช้ตัวเลือกที่เฉพาะเจาะจงมากขึ้น

การใช้ @layer จะช่วยให้คุณระบุความเฉพาะเจาะจงของสไตล์แต่ละรายการได้ชัดเจนยิ่งขึ้น และตรวจสอบว่าสไตล์ของลิงก์การ์ดลบล้างสไตล์ของลิงก์โพสต์ แม้ว่าความเฉพาะเจาะจงอาจลดลงหาก CSS ทั้งหมดอยู่ในระนาบเดียวกัน เนื่องจากลําดับความสำคัญของการแสดงผลตามลำดับขั้น สไตล์ที่วางซ้อนกันจะสร้าง "ระนาบ" ใหม่แบบเรียงซ้อน

ภาพจากเดโมโปรเจ็กต์ของการแยก UI

@layer กำลังดำเนินการ

การสาธิตที่แสดงสีลิงก์ที่มีการนําเข้า
ดูเดโมใน Codepen

ตัวอย่างนี้แสดงประสิทธิภาพของเลเยอร์ Cascade โดยใช้ @layer มีลิงก์หลายรายการที่แสดงอยู่ โดยบางลิงก์ไม่มีการใช้ชื่อคลาสเพิ่มเติม ลิงก์หนึ่งมีคลาส .link และอีกลิงก์หนึ่งมีคลาส .pink จากนั้น CSS จะเพิ่มเลเยอร์ 3 เลเยอร์ ได้แก่ base, typography และ utilities ดังนี้

@layer base {
  a {
    font-weight: 800;
    color: red; /* ignored */
  }

  .link {
    color: blue; /* ignored */
  }
}

@layer typography {
  a {
    color: green; /* styles *all* links */
  }
}

@layer utilities {
  .pink {
    color: hotpink;  /* styles *all* .pink's */
  }
}

สุดท้ายแล้ว ลิงก์ทั้งหมดจะเป็นสีเขียวหรือชมพู เนื่องจากแม้ว่า .link จะมีความเฉพาะเจาะจงระดับตัวเลือกสูงกว่า a แต่ก็มีสไตล์สีใน a ใน @layer ที่มีลําดับความสําคัญสูงกว่า a { color: green } จะลบล้าง .link { color: blue } เมื่อกฎสีเขียวอยู่ในเลเยอร์หลังกฎสีน้ำเงิน

ลําดับชั้นจะมีความสำคัญเหนือกว่าความเฉพาะเจาะจงขององค์ประกอบ

การจัดระเบียบเลเยอร์

คุณสามารถจัดระเบียบเลเยอร์ในหน้าเว็บโดยตรงตามที่แสดงด้านบน หรือจะจัดระเบียบที่ด้านบนของไฟล์ก็ได้

ลําดับเลเยอร์จะสร้างขึ้นเมื่อชื่อเลเยอร์แต่ละรายการปรากฏในโค้ดเป็นครั้งแรก

ซึ่งหมายความว่าหากคุณเพิ่มข้อมูลต่อไปนี้ไว้ที่ด้านบนของไฟล์ ลิงก์ทั้งหมดจะปรากฏเป็นสีแดง และลิงก์ที่มีคลาส .link จะปรากฏเป็นสีน้ำเงิน

@layer utilities, typography, base;

เนื่องจากตอนนี้ลำดับเลเยอร์กลับกัน โดยให้สาธารณูปโภคอยู่ก่อนและฐานข้อมูลอยู่หลังสุด ดังนั้น กฎสไตล์ในเลเยอร์ base จึงมีความเฉพาะเจาะจงสูงกว่ากฎสไตล์ในเลเยอร์การจัดรูปแบบตัวอักษรเสมอ ลิงก์เหล่านี้จะไม่เป็นลิงก์สีเขียวอีกต่อไป แต่จะเปลี่ยนเป็นสีแดงหรือน้ำเงิน

ภาพหน้าจอของโปรเจ็กต์ Codepen
ดูเดโมใน Codepen

การจัดระเบียบการนําเข้า

อีกวิธีในการใช้ @layer คือการใช้กับไฟล์ที่นำเข้า คุณทําเช่นนี้ได้โดยตรงเมื่อนําเข้าสไตล์โดยใช้ฟังก์ชัน layer() ดังตัวอย่างต่อไปนี้

/* Base */
@import '../styles/base/normalize.css' layer(base); /* normalize or rest file */
@import '../styles/base/base.css' layer(base); /* body and base styles */
@import '../styles/base/theme.css' layer(theme); /* theme variables */
@import '../styles/base/typography.css' layer(theme); /* theme typography */
@import '../styles/base/utilities.css' layer(utilities); /* base utilities */

/* Layouts */
@import '../styles/components/post.css' layer(layouts); /* post layout */

/* Components */
@import '../styles/components/cards.css' layer(components); /* imports card */
@import '../styles/components/footer.css' layer(components); /* footer component */

ข้อมูลโค้ดด้านบนมี 3 เลเยอร์ ได้แก่ base,layouts และ components ไฟล์การแปลงค่าให้เป็นมาตรฐาน ธีม และแบบอักษรใน base โดยมีไฟล์ post ใน layouts และ cards และ footer อยู่ใน components เมื่อนำเข้าไฟล์ ระบบจะสร้างอินสแตนซ์เลเยอร์โดยใช้ฟังก์ชันเลเยอร์ อีกวิธีหนึ่งคือการจัดระเบียบเลเยอร์ที่ด้านบนของไฟล์ โดยประกาศเลเยอร์ก่อนการนําเข้า

@layer base,
       theme,
       layouts,
       components,
       utilities;

ตอนนี้ลำดับที่คุณ@importสไตล์จะไม่ส่งผลต่อลําดับเลเยอร์ เนื่องจากมีการสร้างลําดับไว้แล้วในอินสแตนซ์แรกของชื่อเลเยอร์ คุณจะไม่ต้องกังวลเรื่องนั้นอีกต่อไป คุณยังคงตั้งค่าไฟล์ที่นำเข้าไปยังเลเยอร์ที่ต้องการได้ แต่ระบบจะจัดลําดับไว้แล้ว

ภาพหน้าจอจากโปรเจ็กต์ Codepen
ดูโปรเจ็กต์ใน Codepen

เลเยอร์และการแสดงผลตามลำดับขั้น

มาดูกันทีละขั้นว่าเลเยอร์มีการใช้งานอย่างไรเมื่อเกี่ยวข้องกับการแสดงผลตามลำดับขั้นที่กว้างขึ้น

ภาพ Cascade

ลําดับความสําคัญมีดังนี้

  • User Agent ปกติ (ลําดับความสําคัญต่ำสุด)
  • ผู้ใช้ภายใน @layer
  • ผู้ใช้ภายในแบบปกติ
  • ผู้เขียน @layers
  • ผู้เขียนแบบปกติ
  • ผู้เขียน !important
  • ผู้เขียน @layer !important
  • ผู้ใช้ในเครื่อง !important
  • User Agent !important** (ลําดับความสําคัญสูงสุด)

คุณอาจสังเกตเห็นว่าสไตล์ @layer !important กลับหัว รูปแบบที่ซ้อนกันจะมีลําดับความสําคัญสูงกว่า ไม่ใช่เฉพาะเจาะจงน้อยกว่ารูปแบบที่ไม่ซ้อนกัน (ปกติ) สาเหตุคือ !important ทำงานแบบตามลำดับชั้น ซึ่งจะทำลายลำดับชั้นตามปกติในสไตล์ชีตและกลับความเฉพาะเจาะจงระดับเลเยอร์ตามปกติ (ลําดับความสําคัญ)

เลเยอร์ที่ซ้อนกัน

นอกจากนี้ คุณยังฝังเลเยอร์ภายในเลเยอร์อื่นๆ ได้ด้วย ตัวอย่างต่อไปนี้มาจากคำอธิบายเลเยอร์ Cascade จาก Miriam Suzanne

@layer default {
  p { max-width: 70ch; }
}

@layer framework {
  @layer default {
    p { margin-block: 0.75em; }
  }

  p { margin-bottom: 1em; }
}

ในข้อมูลโค้ดด้านบน คุณสามารถเข้าถึง framework.default โดยใช้ . เป็นตัวบ่งชี้เลเยอร์ default ที่ฝังอยู่ภายใน framework คุณยังเขียนในรูปแบบที่สั้นลงได้ดังนี้

@layer framework.default {
  p { margin-block: 0.75em }
}

เลเยอร์และลําดับเลเยอร์ที่ได้จะเป็นดังนี้

  • ค่าเริ่มต้น
  • framework.default
  • framework ยกเลิกการวางซ้อน
  • ไม่ได้ซ้อนทับ

สิ่งที่ควรระวัง

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

กฎข้อที่ 1: อย่าใช้ @layer เพื่อกําหนดขอบเขต

เลเยอร์ Cascade ไม่ได้ช่วยแก้ปัญหาการกําหนดขอบเขต หากคุณมีไฟล์ CSS ที่มี @layer เช่น card.css และต้องการกำหนดสไตล์ลิงก์ทั้งหมดภายในการ์ด อย่าเขียนสไตล์ดังนี้

a {
  
}

ซึ่งจะทำให้แท็ก a ทั้งหมดในไฟล์ได้รับการลบล้างนี้ คุณยังคงต้องกําหนดขอบเขตสไตล์อย่างเหมาะสม

.card a {
  
}

กฎที่ 2: เลเยอร์ Cascading จะจัดเรียงไว้หลัง CSS ที่ไม่มีเลเยอร์

โปรดทราบว่าไฟล์ CSS แบบเลเยอร์จะไม่ลบล้าง CSS ที่ไม่มีเลเยอร์ เราตั้งใจที่จะทําเช่นนี้เพื่อให้นําเข้าเลเยอร์ได้ง่ายขึ้นด้วยวิธีที่สมเหตุสมผลมากขึ้นเพื่อทํางานกับโค้ดเบสที่มีอยู่ ตัวอย่างเช่น การใช้ไฟล์ reset.css เป็นจุดเริ่มต้นและ Use Case ที่ยอดเยี่ยมสําหรับเลเยอร์แคสเคด

กฎ 3: !important กลับความเฉพาะเจาะจงของการแสดงโฆษณาตามลำดับขั้น

แม้ว่าโดยทั่วไปแล้ว รูปแบบที่มีเลเยอร์จะเจาะจงน้อยกว่ารูปแบบที่ไม่มีเลเยอร์ แต่การใช้ !important จะทําให้รูปแบบมีความละเอียดมากขึ้น ในการวางซ้อน การประกาศที่มีกฎ !important จะเฉพาะเจาะจงมากกว่าสไตล์ที่ไม่มีการวางซ้อน

ในกรณีนี้ รูปแบบ !important จะกลับความเฉพาะเจาะจง แผนภาพด้านบนแสดงข้อมูลนี้เพื่อเป็นข้อมูลอ้างอิง: author @layers มีลําดับความสําคัญต่ำกว่า author normal ซึ่งมีลําดับความสําคัญต่ำกว่า author !important ซึ่งมีลําดับความสําคัญต่ำกว่า author @layer !important

หากคุณมีเลเยอร์หลายเลเยอร์ เลเยอร์แรกที่มี !important จะมีลําดับความสําคัญของ !important มากกว่าและเป็นสไตล์ที่เฉพาะเจาะจงที่สุด

กฎข้อที่ 4: ทําความเข้าใจจุดฉีด

เนื่องจากระบบจะกำหนดลําดับเลเยอร์เมื่อชื่อเลเยอร์แต่ละชื่อปรากฏในโค้ดเป็นครั้งแรก หากคุณใส่การประกาศ @layer หลังการนําเข้าและการตั้งค่า layer() หรือหลังคำสั่ง @layer อื่น ระบบจะไม่สนใจการประกาศนั้น ซึ่งต่างจาก CSS ที่ระบบจะใช้กฎสไตล์ที่อยู่ด้านล่างสุดของหน้าสำหรับเลเยอร์แคสเคด โดยระบบจะกำหนดลําดับตั้งแต่แรก

ซึ่งอาจเป็นรายการ ในบล็อกเลเยอร์ หรือในการนําเข้าก็ได้ หากคุณใส่ @layer หลังรายการการนําเข้าที่มี layer() ระบบจะไม่ทําการใดๆ การวางที่ด้านบนของไฟล์จะเป็นการกำหนดลําดับเลเยอร์ และช่วยให้คุณเห็นเลเยอร์ภายในสถาปัตยกรรมได้อย่างชัดเจน

กฎข้อ 5: ตรวจสอบความเฉพาะเจาะจง

เมื่อใช้เลเยอร์ตามลำดับชั้น ตัวเลือกที่เฉพาะเจาะจงน้อยกว่า (เช่น a) จะลบล้างตัวเลือกที่เฉพาะเจาะจงมากกว่า (เช่น .link) หากตัวเลือกที่เฉพาะเจาะจงน้อยกว่าอยู่ในเลเยอร์ที่มีความเฉพาะเจาะจงมากกว่า ลองพิจารณาสิ่งเหล่านี้

a ใน layer(components) จะลบล้าง .pink ใน layer(utilities) ในกรณีที่มีการระบุ @layer utilities, components แม้ว่าจะเป็นส่วนหนึ่งที่ตั้งใจสร้างขึ้นของ API แต่การดำเนินการนี้อาจสร้างความสับสนและหงุดหงิดได้หากคุณไม่คาดคิด

ดังนั้น หากคุณเขียนคลาสยูทิลิตี ให้รวมไว้ในเลเยอร์ที่มีลําดับสูงกว่าคอมโพเนนต์ที่คุณต้องการลบล้างเสมอ คุณอาจคิดว่า "ฉันเพิ่งเพิ่มคลาส .pink นี้เพื่อเปลี่ยนสี แต่ระบบไม่ใช้คลาสดังกล่าว"

ดูข้อมูลเพิ่มเติมเกี่ยวกับเลเยอร์ตามลําดับชั้น

นอกจากนี้ คุณยังดูข้อมูลเพิ่มเติมเกี่ยวกับเลเยอร์ตามลำดับขั้นได้จากแหล่งข้อมูลต่อไปนี้