सिलेक्टर और @-rule के कॉम्बिनेशन

वेब की सुविधाएं: कंटेनर स्टाइल क्वेरी

समस्या

हमें अक्सर अलग-अलग तरह की फ़िल्टरिंग शर्तों को जोड़ने की ज़रूरत पड़ती है. जैसे, सिलेक्टर + मीडिया क्वेरी, मीडिया क्वेरी + कंटेनर क्वेरी वगैरह.

उदाहरण के लिए, (prefers-color-scheme: dark) को ऐसे सिलेक्टर के साथ जोड़ना जो कलर स्कीम के बदलावों को टारगेट करता है (जैसे, :root:has(> head > meta[name="color-scheme"][content="dark"]) या :root.dark), ताकि हल्के/गहरे रंग वाले मोड में कुछ स्टाइल लागू की जा सकें. भले ही, कलर स्कीम को कैसे भी सेट किया गया हो.

इस तरीके से कोड डुप्लीकेट हो जाता है:

/* Light mode styles */
.card.featured {
  font-weight: 400;
}

#logo-dark {
  display: none;
}

@media (prefers-color-scheme: dark) {
  /* Dark mode styles */
  :root:not(.light) {
    .card.featured {
      font-weight: 300;
    }

    #logo-dark {
      display: inline;
    }

    #logo {
      display: none;
    }
  }
}

/* Dark mode styles, again */
:root.dark {
  .card.featured {
    font-weight: 300;
  }

  #logo-dark {
    display: inline;
  }

  #logo {
    display: none;
  }
}

इसके बजाय, क्या करना चाहिए

कंबाइन किए गए फ़िल्टर के नतीजे को किसी कस्टम प्रॉपर्टी पर सेव करें. इसके बाद, उस प्रॉपर्टी के आधार पर नियम सेट करने के लिए, कंटेनर स्टाइल क्वेरी का इस्तेमाल करें.

अहम जानकारी: कंटेनर क्वेरी के काम करने के तरीके की वजह से, यह तकनीक सिर्फ़ तब काम करती है, जब हम मैच होने वाले किसी भी नियम के पैरंट पर कस्टम प्रॉपर्टी सेट कर सकें.

1. लागू किए गए नियमों से, चुनने के लॉजिक को अलग करना

:root {
  --color-scheme: light;

  @media (prefers-color-scheme: dark) {
    --color-scheme: dark;
  }

  &:has(> head > meta[name="color-scheme"][content="dark"]) {
    --color-scheme: dark;
  }

  &:has(> head > meta[name="color-scheme"][content="light"]) {
    --color-scheme: light;
  }
}

2. लागू किए गए नियमों के लिए कस्टम प्रॉपर्टी की कुंजी

@container not style(--color-scheme: dark) {
  .card.featured {
    font-weight: 400;
  }

  #logo-dark {
    display: none;
  }
}

@container style(--color-scheme: dark) {
  .card.featured {
    font-weight: 300;
  }

  #logo {
    display: none;
  }
}

3. ज़रूरी नहीं: विज़िबिलिटी को टॉगल करने के लिए यूटिलिटी क्लास

आम तौर पर, विज़िबिलिटी को टॉगल करने के लिए, यह देखा जाता है कि शर्तें पूरी हो रही हैं या नहीं. यूटिलिटी क्लास को आर्बिट्रेरी कॉम्पोनेंट स्टाइल (इसलिए !important) से बेहतर होना चाहिए. साथ ही, उनके दिखाए गए display के बारे में जानकारी नहीं है. इसलिए, वे ओवरराइड का इस्तेमाल नहीं कर सकते — उन्हें not style(...) से गेट करें:

@container not style(--color-scheme: dark) {
  .if-dark {
    display: none !important;
  }
}

@container not style(--color-scheme: light) {
  .if-light {
    display: none !important;
  }
}

फ़ॉलबैक

फ़ॉलबैक दो तरह के होते हैं. यह इस बात पर निर्भर करता है कि ब्रांचिंग कितनी ज़रूरी है और किस तरह के फ़ॉलबैक को स्वीकार किया जा सकता है.

  1. ज़रूरी ब्रांचिंग के लिए, जहां स्टाइल क्वेरी काम न करने पर भी सभी स्टेट सही तरीके से काम करने चाहिए, वहां स्टाइल क्वेरी का इस्तेमाल नहीं किया जा सकता. इसके बजाय, ऊपर बताए गए आसान तरीके का इस्तेमाल करें. इसमें हर राज्य के लिए नियमों को डुप्लीकेट किया जाता है. यूटिलिटी क्लास का इस्तेमाल तब तक किया जा सकता है, जब तक उन्हें भी उसी तरह से तय किया जाता है.
  2. नॉन-क्रिटिकल ब्रांचिंग के लिए, जहां डिफ़ॉल्ट स्थिति स्वीकार की जा सकती है, वहां किसी भी @container नियम के बाहर बेस स्टाइल तय की जा सकती हैं. साथ ही, स्टाइल क्वेरी का इस्तेमाल सिर्फ़ ओवरराइड के तौर पर किया जा सकता है. इससे इस तरीके की ज़्यादातर खूबियां बनी रहती हैं. हालांकि, इसकी मुख्य कमी यह है कि ओवरराइड की वजह से वैल्यू आपस में जुड़ जाती हैं.
#logo-dark {
  display: none;
}

@container style(--color-scheme: dark) {
  #logo-dark {
    display: inline; /* override */
  }

  #logo {
    display: none;
  }
}