ใช้ CSS แบบมีเงื่อนไขตามการรองรับ At-Rule

ฟีเจอร์บนเว็บ: at-rule()

ใช้ @supports at-rule(@<at-rule name>) {…} เพื่อใช้กฎหรือการประกาศ CSS บางอย่างแบบมีเงื่อนไขเฉพาะในกรณีที่เบราว์เซอร์รองรับ At-rule บางรายการ ซึ่งอาจมีกฎทั้งหมด หรือใช้ร่วมกับการฝัง CSS เพื่อใช้การประกาศบางอย่างแบบมีเงื่อนไข

.foo {
  background: var(--accent-color);

  @supports at-rule(@property) {
    background-image: var(--rainbow-gradient);
    animation: sliding-rainbow 1s linear infinite;
  }
}

อย่าใช้ @supports at-rule() เพื่อใช้ At-Rule ที่ตรวจพบแบบมีเงื่อนไขและไม่มีอะไรอื่น

/* BAD: CSS already ignores rules the browser doesn't understand, so this is unnecessary */
@supports at-rule(@starting-style) {
  @starting-style {
    /* ... */
  }
}

การตรวจหาการรองรับ At-rule เมื่อ @supports at-rule() ไม่เหมาะสม

เมื่อไม่สามารถใช้ at-rule() ได้ ไม่ว่าจะเนื่องจากการรองรับของเบราว์เซอร์หรือเพราะจำเป็นต้องมีการตรวจจับที่ละเอียดยิ่งขึ้น คุณสามารถใช้คำแนะนำด้านล่างได้

ลองใช้พร็อพเพอร์ตี้ ค่า หรือตัวเลือกก่อน

@supports สามารถตรวจหาพร็อพเพอร์ตี้ ค่า และตัวเลือกได้อยู่แล้ว (ผ่าน @supports selector(...)) ในหลายกรณี คุณสามารถใช้สิ่งเหล่านี้เพื่อตรวจหาการรองรับฟีเจอร์โดยไม่ต้องตรวจสอบ At-Rule เอง

เช่น คุณสามารถใช้ @supports (color: --foo()) แทน @supports at-rule(@function) เพื่อตรวจหาการรองรับฟังก์ชันที่กำหนดเอง

ในกรณีอื่นๆ อาจมีคลาสเทียมหรือองค์ประกอบเทียมที่ใช้ได้เฉพาะเมื่อรองรับ At-rule บางรายการ ซึ่งสามารถใช้เพื่อตรวจหาการรองรับได้

การตรวจหาประเภทการค้นหาคอนเทนเนอร์

at-rule() อนุญาตให้ตรวจหา At-rule ตามชื่อเท่านั้น แต่จะไม่อนุญาตให้ตรวจจับไวยากรณ์หรือข้อบ่งชี้อื่นๆ ตัวอย่างเช่น ตัวอย่างต่อไปนี้จะใช้ไม่ได้

@supports at-rule(@container style(--a: 1)) {
  /* ... */
}

สำหรับการค้นหาคอนเทนเนอร์หลายประเภท คุณสามารถใช้ container-type กับค่าที่เหมาะสมได้ เช่น @supports (container-type: scroll-state) สำหรับการค้นหาสถานะการเลื่อน หรือ @supports (container-type: size)container-type: anchoredforanchored()`

อย่างไรก็ตาม ไม่มี container-type สำหรับคำค้นหาเกี่ยวกับสไตล์ สำคัญ: อย่าพยายามใช้ @supports (container-type: style) เพื่อตรวจหาการรองรับการค้นหาสไตล์ เนื่องจากจะไม่ได้ผล

แต่คุณสามารถลองใช้การค้นหาสไตล์ที่เป็นจริงเสมอแทนได้ ดังนี้

@container style(--a: 1) or (not (style(--a: 1))) {
  /* Rules here will only be applied if style queries are supported */
}

ซึ่งจะจับคู่ในเบราว์เซอร์ที่รองรับการค้นหาสไตล์ ไม่ว่าคุณจะใช้ชื่อหรือค่าพร็อพเพอร์ตี้ใดก็ตาม โดยต้องเป็นชื่อหรือค่าเดียวกันในทั้ง 2 รายการ

คุณสมบัติที่กำหนดเองที่ลงทะเบียนไว้ (@property)

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

/* Use a custom property to conditionally include the dash animation */
@property --progress-dash-animation {
  syntax: "*";
  inherits: false;
  initial-value: , progress-dash 3s ease-in-out infinite;
}

.spinner {
  /* The dash animation is only included if @property is supported */
  animation:
    progress-spin var(--_used-spinner-duration) linear infinite
    var(--progress-dash-animation, );
}

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

{# Testcase: https://codepen.io/leaverou/pen/KwWzpVr #}

@property --supports-atproperty {
    syntax: "*";
    inherits: false;
}

:root {
    --supports-atproperty: ;
}

body {
  /* The background is only applied if @property is supported */
    background: var(--supports-atproperty, green);
}

หมายเหตุ:

  • ทั้ง 2 วิธีนี้จะใช้ได้ก็ต่อเมื่อช่องว่างเป็นทางเลือกที่ยอมรับได้ ในกรณีอื่นๆ คุณจะต้องใช้ JS ตามที่อธิบายไว้ด้านล่าง
  • โซลูชันอเนกประสงค์จะขึ้นอยู่กับการไม่รับค่า ดังนั้นจึงใช้ไม่ได้กับการประกาศในองค์ประกอบรูท

การใช้ JavaScript เป็นทางเลือกสุดท้าย

สำหรับ At-rule ทั้งหมด ให้ตรวจสอบว่ามีอินเทอร์เฟซบางอย่างใน JavaScript หรือไม่ เช่น หากมีการกำหนด globalThis.CSSFunctionRule ระบบจะรองรับ @function

หากต้องการทดสอบอย่างละเอียดมากขึ้น (เช่น สำหรับ Prelude, กฎที่ซ้อนกัน, ตัวบ่งชี้บางอย่าง) คุณสามารถตั้งค่าการทดสอบและตรวจสอบวิธีแยกวิเคราะห์ได้ดังนี้

const sheet = new CSSStyleSheet();
sheet.replaceSync(`
  @page {
    @top-left {
      content: "test";
    }
  }
`);
const SUPPORTS_PAGE_MARGINS = Boolean(sheet.cssRules[0]?.cssRules?.[0]);

สำคัญ:

  • เมื่อใช้ JS เพื่อตรวจหาการรองรับฟีเจอร์ CSS อย่าใช้รูปแบบจาก JS โดยตรง แต่ให้ใช้คลาสกับองค์ประกอบรูทและแยกสาขาออกจากคลาสนั้นใน CSS แทน
  • โปรดทราบว่าระบบจะแยกวิเคราะห์การค้นหาคอนเทนเนอร์แม้ว่าจะไม่รู้จักส่วนนำ และไม่มีวิธีตรวจหาการรองรับการค้นหาคอนเทนเนอร์บางประเภทจากโครงสร้าง CSSOM
  • อย่าใช้ CSS.registerProperty เพื่อตรวจหาการรองรับ @property เนื่องจากการรองรับนั้นกว้างกว่าเล็กน้อย

กลยุทธ์สำรอง

เว้นแต่ว่านี่จะอยู่ภายในเป้าหมายการรองรับของคุณ ให้ใช้ @supports (at-rule()) เท่านั้นเพื่อตรวจหา At-rule ที่มีการรองรับแคบกว่าฟีเจอร์ @supports (at-rule()) เอง

หากต้องการใช้ CSS แบบมีเงื่อนไขตามการรองรับ At-Rule ที่จัดส่งก่อนฟีเจอร์นี้ ให้ใช้คำแนะนำในส่วนด้านบน

หากต้องการตรวจหาการรองรับฟีเจอร์ @supports at-rule() โดยตรง คุณสามารถใช้ At-rule ที่รับประกันว่ามีอยู่ในเบราว์เซอร์ทั้งหมดที่รองรับ @supports at-rule() เช่น @supports at-rule(@media) { ... }