:has(): फ़ैमिली सिलेक्टर

सीएसएस की भाषा में, हमने एक कैस्केड के साथ अलग-अलग स्तर पर काम किया है. हमारी शैलियां "कैस्केडिंग स्टाइल शीट" बनाती हैं. साथ ही, हमारे सिलेक्टर भी चैलेंज में शामिल होते हैं. वे तिरछा जा सकते हैं. ज़्यादातर मामलों में, वे नीचे की ओर जाती हैं. लेकिन उससे ऊपर कभी नहीं. कई सालों से, हम "माता-पिता चुनने वाले" की कल्पना करते आ रहे हैं. और अब यह आखिरकार आने ही वाला है! :has() स्यूडो सिलेक्टर के आकार में.

अगर पैरामीटर के तौर पर पास किया गया कोई भी सिलेक्टर कम से कम एक एलिमेंट से मैच करता है, तो :has() सीएसएस pseudo-class एलिमेंट को दिखाती है.

हालांकि, यह "माता-पिता" से कहीं बढ़कर है सिलेक्टर. यह इसकी मार्केटिंग करने का एक अच्छा तरीका है. नहीं लगता कि वह "सशर्त वातावरण" हो सकता है सिलेक्टर. हालांकि, उसमें पहले से मौजूद अंगूठी नहीं है. "परिवार" कैसा लगा सिलेक्टर?

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

इससे पहले कि हम आगे बढ़ें, ब्राउज़र सहायता के बारे में ज़रूर जान लें. फ़िलहाल, कोई ऐसी गड़बड़ी नहीं है. हालांकि, यह करीब-करीब बढ़ता हुआ है. अभी तक Firefox की कोई सुविधा मौजूद नहीं है, यह रोडमैप पर है. हालांकि, यह पहले से ही Safari में उपलब्ध है और इसे Chromium 105 में रिलीज़ किया जाना है. इस लेख में दिए गए सभी डेमो आपको बताएंगे कि क्या वे इस्तेमाल किए गए ब्राउज़र में काम नहीं करते हैं.

इस्तेमाल करने का तरीका :इसमें शामिल है

यह कैसा दिखता है? यहां दिए गए एचटीएमएल में, everybody क्लास वाले दो सिबलिंग एलिमेंट शामिल हैं. आपको उस विकल्प को कैसे चुनना होगा जिसमें a-good-time क्लास वाला डिसेंडेंट है?

<div class="everybody">
  <div>
    <div class="a-good-time"></div>
  </div>
</div>

<div class="everybody"></div>

:has() के साथ, इस सीएसएस का इस्तेमाल करके ऐसा किया जा सकता है.

.everybody:has(.a-good-time) {
  animation: party 21600s forwards;
}

इससे .everybody का पहला इंस्टेंस चुना जाता है और animation लागू होता है.

इस उदाहरण में, everybody क्लास वाला एलिमेंट टारगेट है. शर्त में, क्लास a-good-time के साथ डिसेंडेंट है.

<target>:has(<condition>) { <styles> }

हालांकि, इसे आगे ले जाया जा सकता है, क्योंकि :has() से आपको कई मौके मिलते हैं. उन्हें भी शायद अभी तक नहीं खोजा गया है. इनमें से कुछ का इस्तेमाल करें.

ऐसे figure एलिमेंट चुनें जिनमें डायरेक्ट figcaption हो. css figure:has(> figcaption) { ... } अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है ऐसे anchor चुनें जिनमें डायरेक्ट SVG डिसेंडेंट नहीं है css a:not(:has(> svg)) { ... } ऐसे label चुनें जिनमें सीधे तौर पर input सिबलिंग हों. तिरछा जा रहा है! css label:has(+ input) { … } अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है जब डिसेंडेंट img में alt टेक्स्ट न हो, article चुनें css article:has(img:not([alt])) { … } वह documentElement चुनें जहां DOM में कुछ स्थिति मौजूद है css :root:has(.menu-toggle[aria-pressed=”true”]) { … } बच्चों की विषम संख्या वाला लेआउट कंटेनर चुनें css .container:has(> .container__item:last-of-type:nth-of-type(odd)) { ... } ग्रिड में मौजूद वे सभी आइटम चुनें जिन पर कर्सर नहीं घुमाया गया है css .grid:has(.grid__item:hover) .grid__item:not(:hover) { ... } वह कंटेनर चुनें जिसमें कस्टम एलिमेंट शामिल है <todo-list> css main:has(todo-list) { ... } किसी पैराग्राफ़ में हर एक a को चुनें जिसमें सीधा सिबलिंग hr एलिमेंट हो css p:has(+ hr) a:only-child { … } कोई article चुनें, जो कई शर्तें पूरी करती हो css article:has(>h1):has(>h2) { … } मिलाओ. ऐसा article चुनें जहां टाइटल के बाद सबटाइटल आता हो css article:has(> h1 + h2) { … } इंटरैक्टिव स्टेट ट्रिगर होने पर :root चुनें css :root:has(a:hover) { … } वह पैराग्राफ़ चुनें जो figure के बाद आता हो और जिसमें figcaption न हो css figure:not(:has(figcaption)) + p { … }

आपके हिसाब से, :has() के इस्तेमाल के कौनसे दिलचस्प उदाहरण हैं? यहां की सबसे दिलचस्प बात यह है कि यह आपको अपने मानसिक मॉडल को बदलने के लिए प्रेरित करती है. इस वीडियो को देखकर आपको लगता है कि "क्या मैं इन स्टाइल का इस्तेमाल अलग तरीके से कर सकता हूं?".

उदाहरण

आइए, कुछ उदाहरणों में देखते हैं कि हम इसका इस्तेमाल कैसे कर सकते हैं.

कार्ड

क्लासिक कार्ड का डेमो लें. हम अपने कार्ड में कोई भी जानकारी दिखा सकते हैं, जैसे कि टाइटल, सबटाइटल या कुछ मीडिया. यह रहा बेसिक कार्ड.

<li class="card">
  <h2 class="card__title">
      <a href="#">Some Awesome Article</a>
  </h2>
  <p class="card__blurb">Here's a description for this awesome article.</p>
  <small class="card__author">Chrome DevRel</small>
</li>

मीडिया के बारे में जानकारी देने पर क्या होता है? इस डिज़ाइन के लिए कार्ड को दो कॉलम में बांटा जा सकता है. आप इस व्यवहार को दिखाने के लिए एक नई क्लास बना सकते हैं, जैसे कि card--with-media या card--two-columns. इन क्लास के नामों को जोड़ना मुश्किल होने के साथ-साथ, इन्हें बनाए रखना और याद रखना भी मुश्किल हो जाता है.

:has() की मदद से, यह पता लगाया जा सकता है कि कार्ड में मीडिया मौजूद है या नहीं. साथ ही, इससे आपको ज़रूरी काम करने में मदद मिलती है. मॉडिफ़ायर क्लास के नामों की कोई ज़रूरत नहीं है.

<li class="card">
  <h2 class="card__title">
    <a href="/article.html">Some Awesome Article</a>
  </h2>
  <p class="card__blurb">Here's a description for this awesome article.</p>
  <small class="card__author">Chrome DevRel</small>
  <img
    class="card__media"
    alt=""
    width="400"
    height="400"
    src="./team-awesome.png"
  />
</li>

और आपको उसे वहां छोड़ने की ज़रूरत नहीं है. इसके साथ क्रिएटिविटी दिखाई जा सकती है. “चुनिंदा” कॉन्टेंट दिखाने वाला कार्ड, लेआउट के हिसाब से किस तरह बदल सकता है? यह सीएसएस, फ़ीचर किए गए कार्ड को लेआउट की पूरी चौड़ाई में बदल देगी और उसे ग्रिड की शुरुआत में लगा देगी.

.card:has(.card__banner) {
  grid-row: 1;
  grid-column: 1 / -1;
  max-inline-size: 100%;
  grid-template-columns: 1fr 1fr;
  border-left-width: var(--size-4);
}

क्या होगा अगर बैनर वाला एक चुनिंदा कार्ड ध्यान खींचने में हिले?

<li class="card">
  <h2 class="card__title">
    <a href="#">Some Awesome Article</a>
  </h2>
  <p class="card__blurb">Here's a description for this awesome article.</p>
  <small class="card__author">Chrome DevRel</small>
  <img
    class="card__media"
    alt=""
    width="400"
    height="400"
    src="./team-awesome.png"
  />
  <div class="card__banner"></div>
</li>
.card:has(.card__banner) {
  --color: var(--green-3-hsl);
  animation: wiggle 6s infinite;
}

बहुत सारी संभावनाएँ.

फ़ॉर्म

फ़ॉर्म कैसा रहेगा? उन्हें स्टाइल के लिए ज़्यादा पेचीदा तकनीक के लिए जाना जाता है. इनपुट और उनके लेबल को स्टाइल करना, इसका एक उदाहरण है. उदाहरण के लिए, हम यह कैसे सिग्नल देते हैं कि फ़ील्ड मान्य है? :has() के साथ, यह करना ज़्यादा आसान हो जाता है. हम इससे जुड़ी pseudo-classes को जोड़ सकते हैं. जैसे, :valid और :invalid.

<div class="form-group">
  <label for="email" class="form-label">Email</label>
  <input
    required
    type="email"
    id="email"
    class="form-input"
    title="Enter valid email address"
    placeholder="Enter valid email address"
  />   
</div>
label {
  color: var(--color);
}
input {
  border: 4px solid var(--color);
}

.form-group:has(:invalid) {
  --color: var(--invalid);
}

.form-group:has(:focus) {
  --color: var(--focus);
}

.form-group:has(:valid) {
  --color: var(--valid);
}

.form-group:has(:placeholder-shown) {
  --color: var(--blur);
}

इस उदाहरण में इसे आज़माएं: मान्य और अमान्य वैल्यू डालकर देखें और ध्यान चालू और बंद करें.

किसी फ़ील्ड के गड़बड़ी के मैसेज को दिखाने और छिपाने के लिए, :has() का इस्तेमाल भी किया जा सकता है. हमारे “ईमेल” फ़ील्ड ग्रुप में, गड़बड़ी का मैसेज जोड़ें.

<div class="form-group">
  <label for="email" class="form-label">
    Email
  </label>
  <div class="form-group__input">
    <input
      required
      type="email"
      id="email"
      class="form-input"
      title="Enter valid email address"
      placeholder="Enter valid email address"
    />   
    <div class="form-group__error">Enter a valid email address</div>
  </div>
</div>

डिफ़ॉल्ट रूप से, गड़बड़ी का मैसेज छिपा दिया जाता है.

.form-group__error {
  display: none;
}

हालांकि, जब फ़ील्ड :invalid हो जाता है और फ़ोकस नहीं होता, तो आपके पास अतिरिक्त क्लास नेम के बिना मैसेज दिखाने का विकल्प होता है.

.form-group:has(:invalid:not(:focus)) .form-group__error {
  display: block;
}

जब आपके उपयोगकर्ता आपके फ़ॉर्म के साथ इंटरैक्ट करते हैं, तब आपके लिए इन्हें मज़ेदार बनाने की कोई वजह नहीं है. इस उदाहरण पर गौर करें. माइक्रो-इंटरैक्शन के लिए मान्य वैल्यू डालने के बाद, यह वीडियो देखें. :invalid वैल्यू की वजह से फ़ॉर्म ग्रुप हिल जाएगा. लेकिन, सिर्फ़ तभी, जब उपयोगकर्ता की मोशन प्राथमिकता न हो.

सामग्री

हमने कोड के उदाहरणों में इसके बारे में चर्चा की है. हालांकि, दस्तावेज़ के फ़्लो में :has() का इस्तेमाल कैसे किया जा सकता है? इससे यह पता चलता है कि हम मीडिया के आस-पास, टाइपोग्राफ़ी को कैसे स्टाइल कर सकते हैं.

figure:not(:has(figcaption)) {
  float: left;
  margin: var(--size-fluid-2) var(--size-fluid-2) var(--size-fluid-2) 0;
}

figure:has(figcaption) {
  width: 100%;
  margin: var(--size-fluid-4) 0;
}

figure:has(figcaption) img {
  width: 100%;
}

इस उदाहरण में आंकड़े शामिल हैं. जब उनके पास कोई figcaption नहीं होता, तब वे कॉन्टेंट में फ़्लोट करते हैं. जब figcaption मौजूद होता है, तो वह पूरी चौड़ाई लेता है और ज़्यादा मार्जिन मिलता है.

राज्य के प्रति प्रतिक्रिया

क्या आप हमारे मार्कअप में मौजूद अपनी स्टाइल को कुछ स्थितियों के लिए तैयार कर सकते हैं. "क्लासिक" के साथ एक उदाहरण पर विचार करें स्लाइड करने वाला नेविगेशन बार. अगर आपके पास ऐसा बटन है जो नेविगेशन को खोलने के लिए टॉगल करता है, तो वह aria-expanded एट्रिब्यूट का इस्तेमाल कर सकता है. JavaScript का इस्तेमाल सही एट्रिब्यूट को अपडेट करने के लिए किया जा सकता है. जब aria-expanded true हो, तो इसका पता लगाने के लिए :has() का इस्तेमाल करें. साथ ही, स्लाइड करने वाले नेविगेशन के लिए स्टाइल अपडेट करें. JavaScript अपना काम करता है और सीएसएस उस जानकारी के साथ जो चाहे वह कर सकता है. मार्कअप को शफ़ल करने या क्लास के अतिरिक्त नाम वगैरह जोड़ने की ज़रूरत नहीं है. (ध्यान दें: यह प्रोडक्शन के लिए तैयार उदाहरण नहीं है).

:root:has([aria-expanded="true"]) {
    --open: 1;
}
body {
    transform: translateX(calc(var(--open, 0) * -200px));
}

उपयोगकर्ता गड़बड़ी से बचने के लिए क्या :क्या मदद मिल सकती है?

इन सभी उदाहरणों में क्या समानता है? भले ही, इनमें :has() को इस्तेमाल करने के तरीके बताए गए हों, लेकिन इनमें से किसी को भी क्लास के नामों में बदलाव करने की ज़रूरत नहीं है. हर उसने नया कॉन्टेंट डाला और एक एट्रिब्यूट अपडेट किया. यह :has() का एक सबसे बड़ा फ़ायदा है. इससे उपयोगकर्ता की गड़बड़ी को कम करने में मदद मिल सकती है. :has() का इस्तेमाल करके, सीएसएस, डीओएम में किए गए बदलावों को अडजस्ट करने की ज़िम्मेदारी उठा सकती है. आपको JavaScript में क्लास के नामों को उलझाने की ज़रूरत नहीं है. इससे डेवलपर की गड़बड़ी होने की संभावना कम हो जाती है. क्लास का नाम टाइप करने के दौरान, हम सभी ऐसी समस्याओं का सामना करते हैं. उन्हें Object लुकअप में लिखना पड़ता है.

यह एक दिलचस्प विचार है और क्या यह हमें साफ़ मार्कअप और कम कोड की तरफ़ ले जाता है? कम JavaScript क्योंकि हम उतने JavaScript समायोजन नहीं कर रहे हैं. कम एचटीएमएल, क्योंकि अब आपको card card--has-media जैसी क्लास की ज़रूरत नहीं है.

कुछ अलग सोचकर

जैसा कि ऊपर बताया गया है, :has() आपको मानसिक मॉडल को तोड़ने का बढ़ावा देता है. यह अलग-अलग चीज़ें आज़माने का मौका है. सीएसएस का इस्तेमाल करके गेम में महारत हासिल करने का एक तरीका, गेम को बेहतर बनाने का एक तरीका है. उदाहरण के लिए, फ़ॉर्म और सीएसएस का इस्तेमाल करके, सिलसिलेवार तरीके से काम करने वाला मकैनिक बनाया जा सकता है.

<div class="step">
  <label for="step--1">1</label>
  <input id="step--1" type="checkbox" />
</div>
<div class="step">
  <label for="step--2">2</label>
  <input id="step--2" type="checkbox" />
</div>
.step:has(:checked), .step:first-of-type:has(:checked) {
  --hue: 10;
  opacity: 0.2;
}


.step:has(:checked) + .step:not(.step:has(:checked)) {
  --hue: 210;
  opacity: 1;
}

और इससे दिलचस्प संभावनाओं के बारे में पता चलता है. इसका इस्तेमाल किसी ऐसे फ़ॉर्म को ट्रांसफ़ॉर्म करने के लिए किया जा सकता है. ध्यान दें, यह डेमो एक अलग ब्राउज़र टैब में सबसे अच्छा दिखाई देता है.

मनोरंजन के लिए, क्लासिक बज़ वायर गेम कैसा रहेगा? :has() की मदद से मैकेनिक को आसानी से बनाया जा सकता है. अगर तार पर मंडराया जाता है, तो गेम खत्म हो जाता है. हां, हम सिबलिंग कॉम्बिनेटर (+ और ~) जैसी चीज़ों का इस्तेमाल करके, इनमें से कुछ गेम मैकेनिक्स बना सकते हैं. हालांकि, :has() उन नतीजों को पाने का एक तरीका है. इसके लिए, दिलचस्प मार्कअप "ट्रिक" का इस्तेमाल करने की ज़रूरत नहीं पड़ती. ध्यान दें, यह डेमो एक अलग ब्राउज़र टैब में सबसे अच्छा दिखाई देता है.

हालांकि, जल्द ही इन्हें प्रोडक्शन में शामिल नहीं किया जाएगा, लेकिन इनसे आपको प्रिमिटिव के इस्तेमाल के तरीकों की जानकारी मिलती है. जैसे, :has() की चेन बना पाना.

:root:has(#start:checked):has(.game__success:hover, .screen--win:hover)
.screen--win {
  --display-win: 1;
}

परफ़ॉर्मेंस और सीमाएं

हमारे जाने से पहले, आप :has() से क्या-क्या नहीं कर सकते? :has() की वजह से कुछ पाबंदियां लगी हैं. इनमें मुख्य समस्याएं, परफ़ॉर्मेंस को मिले हिट की वजह से पैदा होती हैं.

  • :has() को :has() नहीं किया जा सकता. हालांकि, आपके पास :has() की चेन बनाने का विकल्प है. css :has(.a:has(.b)) { … }
  • :has() में कोई सूडो एलिमेंट इस्तेमाल नहीं किया गया है css :has(::after) { … } :has(::first-letter) { … }
  • सिर्फ़ कंपाउंड सिलेक्टर को स्वीकार करने वाले स्यूडो में :has() के इस्तेमाल पर पाबंदी लगाएं css ::slotted(:has(.a)) { … } :host(:has(.a)) { … } :host-context(:has(.a)) { … } ::cue(:has(.a)) { … }
  • सूडो एलिमेंट के बाद, :has() के इस्तेमाल पर पाबंदी लगाएं css ::part(foo):has(:focus) { … }
  • :visited का इस्तेमाल हमेशा गलत होगा css :has(:visited) { … }

:has() से जुड़ी असल परफ़ॉर्मेंस मेट्रिक के लिए, यह Glitch देखें. लागू करने से जुड़ी यह अहम जानकारी और जानकारी शेयर करने के लिए, Beungwoo को क्रेडिट दें.

बस इतना ही!

:has() के लिए तैयार हो जाएं. अपने दोस्तों को इसके बारे में बताएं और यह पोस्ट शेयर करें. यह सीएसएस के लिए हमारे काम करने का तरीका बदलने में मदद करेगी.

सभी डेमो इस CodePen संग्रह में उपलब्ध हैं.