सीएसएस @scope एट-रूल की मदद से, अपने सिलेक्टर की पहुंच सीमित करें

अपने डीओएम के सीमित सबट्री में एलिमेंट चुनने के लिए, @scope का इस्तेमाल करने का तरीका जानें.

ब्राउज़र सहायता

  • Chrome: 118. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • एज: 118. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • Firefox: किसी झंडे के पीछे.
  • सफ़ारी: 17.4. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है

सोर्स

सीएसएस सिलेक्टर को लिखने की बारीक कला

सिलेक्टर को लिखते समय, हो सकता है कि आपको दो अलग-अलग चीज़ों के बीच फंसा हुआ महसूस हो. आपको यह भी बताना होगा कि आपने कौनसे एलिमेंट चुने हैं. दूसरी ओर, आपको सिलेक्टर को ऐसे रखना चाहिए कि उन्हें आसानी से बदला जा सके और उनके साथ डीओएम स्ट्रक्चर के साथ कोई तालमेल न बनाया जा सके.

उदाहरण के लिए, जब आपको “कार्ड कॉम्पोनेंट के कॉन्टेंट एरिया में हीरो इमेज” चुनना हो, तो हो सकता है कि आप .card > .content > img.hero जैसा सिलेक्टर न लिखना चाहें.

  • इस सिलेक्टर में (0,3,1) की खूबी बहुत ज़्यादा है. इसकी वजह से आपका कोड बढ़ने के साथ-साथ इसे बदलना मुश्किल हो जाता है.
  • डायरेक्ट चाइल्ड कॉम्बिनेटर पर निर्भर होने की वजह से, यह डीओएम स्ट्रक्चर से मज़बूती से जुड़ जाता है. अगर मार्कअप में कभी कोई बदलाव होता है, तो आपको अपना सीएसएस भी बदलना होगा.

हालांकि, आपको उस एलिमेंट के लिए सिलेक्टर के तौर पर सिर्फ़ img नहीं लिखना है, क्योंकि इससे आपके पेज पर मौजूद सभी इमेज एलिमेंट चुन लिए जाएंगे.

इस स्थिति में सही संतुलन बनाना काफ़ी चुनौती भरा होता है. पिछले कुछ सालों में, कुछ डेवलपर ने इस तरह की स्थितियों में आपकी मदद करने के लिए, समाधान और समाधान तैयार किए हैं. उदाहरण के लिए:

  • बीईएम जैसे तरीकों से यह पता चलता है कि एलिमेंट को card__img card__img--hero की क्लास दी जाती है, ताकि उसकी खासियत को कम रखा जा सके. साथ ही, चुने गए विकल्प के बारे में साफ़ तौर पर बताया जा सके.
  • दायरे वाले सीएसएस या स्टाइल वाले कॉम्पोनेंट जैसे JavaScript पर आधारित समाधान, अपने सिलेक्टर में रैंडम तरीके से जनरेट की गई स्ट्रिंग, जैसे कि sc-596d7e0e-4–को जोड़कर, आपके सभी सिलेक्टर को फिर से लिखते हैं. इससे वे आपके पेज के दूसरी ओर मौजूद एलिमेंट को टारगेट नहीं कर पाते.
  • कुछ लाइब्रेरी में सिलेक्टर ही पूरी तरह से इस्तेमाल नहीं किए जाते और आपको स्टाइलिंग ट्रिगर को सीधे मार्कअप में रखने की ज़रूरत होती है.

लेकिन अगर आपको उनमें से किसी की ज़रूरत न हो, तो क्या करना होगा? क्या होगा अगर सीएसएस आपको आपके चुने गए एलिमेंट के बारे में सटीक तौर पर बताने का विकल्प दे, और इसके लिए आपको ज़्यादा खासियत वाले सिलेक्टर या आपके डीओएम से मज़बूती से जुड़े हुए सिलेक्टर को लिखने की ज़रूरत न पड़े? यहां से @scope का इस्तेमाल किया जा सकता है. इसमें आपको अपने डीओएम के सब-ट्री में एलिमेंट चुनने की सुविधा मिलती है.

पेश है @scope

@scope की मदद से, चुनने वालों की पहुंच सीमित की जा सकती है. ऐसा करने के लिए स्कोपिंग रूट सेट करें, जो उस सबट्री की ऊपरी सीमा को तय करता है जिसे आपको टारगेट करना है. स्कोपिंग रूट सेट के साथ, स्कोपिंग स्टाइल के नियम नाम वाले शामिल स्टाइल नियम – डीओएम के सिर्फ़ उस सीमित सबट्री में से ही चुने जा सकते हैं.

उदाहरण के लिए, .card कॉम्पोनेंट में सिर्फ़ <img> एलिमेंट को टारगेट करने के लिए, .card को @scope ऐट-नियम के स्कोपिंग रूट के तौर पर सेट करें.

@scope (.card) {
    img {
        border-color: green;
    }
}

स्कोप वाली स्टाइल का नियम img { … }, असरदार तरीके से सिर्फ़ उन <img> एलिमेंट को चुन सकता है जो मेल खाने वाले .card एलिमेंट के स्कोप में आते हैं.

कार्ड के कॉन्टेंट एरिया (.card__content) में मौजूद <img> एलिमेंट को चुने जाने से रोकने के लिए, img सिलेक्टर को और सटीक बनाया जा सकता है. ऐसा करने का दूसरा तरीका यह है कि इस नियम का इस्तेमाल करें कि @scope के नियम में स्कोपिंग की सीमा भी स्वीकार की गई हो. इससे निचली सीमा तय होती है.

@scope (.card) to (.card__content) {
    img {
        border-color: green;
    }
}

स्कोप वाली यह स्टाइल नियम, सिर्फ़ उन <img> एलिमेंट को टारगेट करता है जिन्हें एंसेस्टर ट्री में .card और .card__content एलिमेंट के बीच रखा गया है. ऊपरी और निचली सीमा वाले इस तरह के दायरे को अक्सर डोनट स्कोप कहा जाता है

:scope सिलेक्टर

डिफ़ॉल्ट रूप से, स्कोप वाली स्टाइल के सभी नियम, स्कोपिंग रूट के मुताबिक होते हैं. स्कोपिंग रूट एलिमेंट को भी टारगेट किया जा सकता है. इसके लिए, :scope सिलेक्टर का इस्तेमाल करें.

@scope (.card) {
    :scope {
        /* Selects the matched .card itself */
    }
    img {
       /* Selects img elements that are a child of .card */
    }
}

स्कोप वाले स्टाइल के नियमों में, सिलेक्टर के तौर पर :scope पहले से जोड़ा जाता है. अगर आप चाहें, तो खुद :scope से पहले, इसके बारे में साफ़ तौर पर बताया जा सकता है. इसके अलावा, सीएसएस नेस्टिंग में जाकर, & सिलेक्टर को पहले जोड़ा जा सकता है.

@scope (.card) {
    img {
       /* Selects img elements that are a child of .card */
    }
    :scope img {
        /* Also selects img elements that are a child of .card */
    }
    & img {
        /* Also selects img elements that are a child of .card */
    }
}

स्कोपिंग सीमा, :scope pseudo-class का इस्तेमाल कर सकती है, ताकि स्कोपिंग रूट से किसी खास संबंध की ज़रूरत हो:

/* .content is only a limit when it is a direct child of the :scope */
@scope (.media-object) to (:scope > .content) { ... }

स्कोपिंग लिमिट, :scope का इस्तेमाल करके अपने स्कोपिंग रूट से बाहर के एलिमेंट का भी रेफ़रंस दे सकती है. उदाहरण के लिए:

/* .content is only a limit when the :scope is inside .sidebar */
@scope (.media-object) to (.sidebar :scope .content) { ... }

ध्यान दें कि स्कोप की गई स्टाइल के नियम, सबट्री को एस्केप नहीं कर सकते. :scope + p जैसे चुने गए विकल्प अमान्य हैं, क्योंकि इससे ऐसे एलिमेंट को चुनने की कोशिश की जाती है जो दायरे में नहीं आते.

@scope और विशेषता

@scope के शुरुआत में इस्तेमाल किए जाने वाले सिलेक्टर का असर, चुने गए सिलेक्टर पर लागू नहीं होता है. नीचे दिए गए उदाहरण में, img सिलेक्टर अब भी (0,0,1) है.

@scope (#sidebar) {
    img { /* Specificity = (0,0,1) */
        …
    }
}

:scope की खासियत, (0,1,0) नाम वाली सामान्य pseudo-class की खासियत है.

@scope (#sidebar) {
    :scope img { /* Specificity = (0,1,0) + (0,0,1) = (0,1,1) */
        …
    }
}

यहां दिए गए उदाहरण में, अंदरूनी तौर पर &, उस सिलेक्टर में फिर से लिखा जाता है जिसका इस्तेमाल स्कोपिंग रूट के लिए किया जाता है. इसे :is() सिलेक्टर के अंदर रैप किया जाता है. आखिर में, मैच करने के लिए ब्राउज़र, :is(#sidebar, .card) img को सिलेक्टर के तौर पर इस्तेमाल करेगा. इस प्रोसेस को डिसूगरिंग कहा जाता है.

@scope (#sidebar, .card) {
    & img { /* desugars to `:is(#sidebar, .card) img` */
        …
    }
}

:is() का इस्तेमाल करके & की वैल्यू तय की जाती है. इसलिए, & की खासियत, :is() की खासियत के नियमों के हिसाब से तय होती है: & की खासियत, इसके सबसे खास तर्क की विशेषता होती है.

इस उदाहरण पर लागू की गई :is(#sidebar, .card) की विशेषता, इसके सबसे खास तर्क, #sidebar की खासियत है. इसलिए, यह (1,0,0) हो जाती है. इसे img की खासियत के साथ जोड़ें–जो (0,0,1) है–और आप कॉम्प्लेक्स सिलेक्टर के लिए (1,0,1) देते हैं.

@scope (#sidebar, .card) {
    & img { /* Specificity = (1,0,0) + (0,0,1) = (1,0,1) */
        …
    }
}

@scope में :scope और & के बीच का अंतर

विशेषता की गिनती के तरीके में अंतर के अलावा, :scope और & के बीच एक और अंतर यह होता है कि :scope, मेल खाने वाले स्कोपिंग रूट को दिखाता है, जबकि &, स्कोपिंग रूट से मेल खाने वाले सिलेक्टर को दिखाता है.

इस वजह से, & का इस्तेमाल कई बार किया जा सकता है. यह :scope के उलट है, जिसका इस्तेमाल सिर्फ़ एक बार किया जा सकता है, क्योंकि स्कोपिंग रूट के अंदर के स्कोपिंग रूट को मैच नहीं किया जा सकता.

@scope (.card) {
  & & { /* Selects a `.card` in the matched root .card */
  }
  :scope :scope { /* ❌ Does not work */
    …
  }
}

प्रीलूड-लेस स्कोप

<style> एलिमेंट के साथ इनलाइन स्टाइल लिखते समय, <style> एलिमेंट के बंद होने वाले पैरंट एलिमेंट में स्टाइल के नियम जोड़े जा सकते हैं. इसके लिए, आपको कोई स्कोपिंग रूट नहीं बताना होगा. ऐसा करने के लिए, @scope के प्रस्ताव को अनदेखा किया जा सकता है.

<div class="card">
  <div class="card__header">
    <style>
      @scope {
        img {
          border-color: green;
        }
      }
    </style>
    <h1>Card Title</h1>
    <img src="…" height="32" class="hero">
  </div>
  <div class="card__content">
    <p><img src="…" height="32"></p>
  </div>
</div>

ऊपर दिए गए उदाहरण में, दायरे वाले नियम div में सिर्फ़ card__header क्लास नाम वाले एलिमेंट को टारगेट करते हैं, क्योंकि div, <style> एलिमेंट का पैरंट एलिमेंट है.

कैस्केड में @Scope

CSS Cascade के अंदर, @scope एक नई शर्त भी जोड़ता है: स्कोपिंग निकटता. यह चरण विशेषता के बाद आता है, लेकिन उसके दिखने के क्रम से पहले आता है.

सीएसएस कैस्केड का विज़ुअलाइज़ेशन.

हर स्पेसिफ़िकेशन के हिसाब से:

स्टाइल के नियमों में दिखने वाले एलानों की तुलना, अलग-अलग स्कोप वाले रूट से की जाती है. इसके बाद, सबसे कम जनरेशन या सिबलिंग एलिमेंट वाला एलान, स्कोपिंग रूट और स्कोप वाली स्टाइल के नियम के विषय के बीच हो जाता है.

किसी कॉम्पोनेंट के कई वैरिएशन को नेस्ट करते समय, यह नया चरण काम आता है. इस उदाहरण को लें, जो अभी तक @scope का इस्तेमाल नहीं करता है:

<style>
    .light { background: #ccc; }
    .dark  { background: #333; }
    .light a { color: black; }
    .dark a { color: white; }
</style>
<div class="light">
    <p><a href="#">What color am I?</a></p>
    <div class="dark">
        <p><a href="#">What about me?</a></p>
        <div class="light">
            <p><a href="#">Am I the same as the first?</a></p>
        </div>
    </div>
</div>

उस छोटे से मार्कअप को देखते समय, black के बजाय तीसरा लिंक white होगा. हालांकि, यह उस div का चाइल्ड लिंक है जिस पर .light क्लास लागू है. ऐसा, 'दिखने का तरीका' मानदंड के क्रम की वजह से होता है, जिसका इस्तेमाल कैस्केड यहां विजेता तय करने के लिए करता है. ऐसा लगता है कि .dark a का एलान आखिरी बार किया गया था. इसलिए, इसे .light a नियम से जीत मिलेगी

स्कोपिंग निकटता मानदंड के साथ अब इसे हल किया गया है:

@scope (.light) {
    :scope { background: #ccc; }
    a { color: black;}
}

@scope (.dark) {
    :scope { background: #333; }
    a { color: white; }
}

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

आखिरी नोट: सिलेक्टर को अलग-अलग करें, न कि स्टाइल आइसोलेशन

ध्यान दें कि @scope से सिलेक्टर की पहुंच सीमित होती है और यह स्टाइल आइसोलेशन की सुविधा नहीं देती. @scope की निचली सीमा के पार, ऐसी प्रॉपर्टी जो बच्चों के लिए इनहेरिट की जाती हैं वे अब भी इनहेरिट की जाएंगी. color प्रॉपर्टी ऐसी ही एक प्रॉपर्टी है. यह एलान करते समय कि डोनट के दायरे में आने वाला एक color, डोनट के गड्ढे में मौजूद बच्चों को इनहेरिट करेगा.

@scope (.card) to (.card__content) {
  :scope {
    color: hotpink;
  }
}

ऊपर दिए गए उदाहरण में, .card__content एलिमेंट और उसके चाइल्ड एंट्री का रंग hotpink है, क्योंकि वे .card से वैल्यू इनहेरिट करते हैं.

(Unस्प्लैश पर रस्टम बुरखानोव की कवर फ़ोटो)