कॉन्टेंट के हिसाब से स्टाइलिंग

वेब की सुविधाएं: :has() :not()

पहले, किसी कॉम्पोनेंट के कॉन्टेंट के आधार पर अलग-अलग लेआउट लागू करने के लिए, JavaScript या एचटीएमएल टेंप्लेटिंग भाषा में कंडिशनल लॉजिक का इस्तेमाल करना पड़ता था. इससे, .card--has-image या .card--text-only जैसी मॉडिफ़ायर क्लास को इंजेक्ट किया जाता था.

:has() स्यूडो-क्लास, पैरंट सिलेक्टर के तौर पर काम करके इस ज़रूरत को खत्म कर देती है. इसकी मदद से, किसी कंटेनर एलिमेंट को उसके अंदर मौजूद या मौजूद न होने वाले खास एलिमेंट के आधार पर, कंडिशनल स्टाइलिंग दी जा सकती है.

:has() का इस्तेमाल करके, किसी कॉम्पोनेंट के असल डीओएम कॉन्टेंट के आधार पर, सीएसएस में अलग-अलग लेआउट वैरिएशन को आसानी से तय किया जा सकता है. आपके पास इसे :not() के साथ जोड़ने का विकल्प भी है. इससे, डिफ़ॉल्ट लेआउट तय करने के लिए, कॉन्टेंट की अनुपस्थिति को साफ़ तौर पर टारगेट किया जा सकता है.

कॉन्टेंट के हिसाब से कंटेनर की स्टाइलिंग लागू करना

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

कॉन्टेंट के हिसाब से लेआउट बदलने वाला कॉम्पोनेंट बनाने के लिए:

  1. डिफ़ॉल्ट स्टाइल तय करें: कंटेनर एलिमेंट पर बेस लेआउट स्टाइल लागू करें. जैसे, एक कॉलम वाला आसान स्टैक.
  2. कॉन्टेंट के आधार पर स्टाइल को बदलना: :has([child-selector]) का इस्तेमाल करके कंटेनर को टारगेट करें और उस कॉन्टेंट के मौजूद होने पर, नई लेआउट स्टाइल लागू करें. उदाहरण के लिए, मल्टी-कॉलम ग्रिड.

उदाहरण: कार्ड कॉम्पोनेंट, जिसमें इमेज मौजूद होने पर वह साइड-बाय-साइड लेआउट पर स्विच हो जाता है.

/* 1. Define the default state on the component container */
/* This applies when there is NO image */
.article-card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.5rem;
  border: 1px solid #ccc;
  border-radius: 8px;
}

/* 2. Apply styles when a specific child element is present */
/* MANDATORY: Target the container and use :has() to check for the descendant */
.article-card:has(img) {
  /* Change the layout to a row if an image exists */
  flex-direction: row;
  align-items: center;
}

/* Optional: Style the image itself (no :has() needed here) */
.article-card img {
  width: 150px;
  height: auto;
  border-radius: 4px;
}

/* You can also combine :has() and :not() to explicitly target the ABSENCE of content */
/* This selects a card that DOES NOT have an image */
.article-card:not(:has(img)) {
  /* E.g., apply a different background color for text-only cards */
  background-color: #f9f9f9;
}
<!-- Assume an <h1> precedes these components in the document layout -->
<!-- A card WITH an image (will use row layout) -->
<article class="article-card">
  <img src="thumbnail.jpg" alt="Article thumbnail" />
  <div class="content">
    <h2>Card With Image</h2>
    <p>This card lays out its content horizontally.</p>
  </div>
</article>

<!-- A card WITHOUT an image (will use default column layout) -->
<article class="article-card">
  <div class="content">
    <h2>Text-Only Card</h2>
    <p>This card lays out its content vertically, and gets its background color from the :not(:has()) rule.</p>
  </div>
</article>

परफ़ॉर्मेंस से जुड़ी सलाह: :has() का इस्तेमाल करते समय, सिलेक्टर को ज़्यादा से ज़्यादा खास कॉम्पोनेंट कंटेनर (जैसे, .article-card) तक सीमित रखें. अगर स्टाइल में किए गए बदलाव बहुत ज़्यादा स्थानीय हैं, तो इसे body:has(img) जैसे बहुत हाई-लेवल एलिमेंट पर ऐंकर करने से बचें. ऐसा इसलिए, क्योंकि ब्रॉड :has() क्वेरी, लेआउट को फिर से कैलकुलेट करने की प्रोसेस को ट्रिगर कर सकती हैं.

फ़ॉलबैक रणनीतियां

अगर कॉन्टेंट के हिसाब से लेआउट की स्टाइलिंग, उपयोगकर्ता अनुभव या पेज डिज़ाइन के लिए ज़रूरी है, तो आपको उन ब्राउज़र के लिए फ़ॉलबैक उपलब्ध कराना होगा जो :has() सिलेक्टर के साथ काम नहीं करते. सिर्फ़ सजावटी इफ़ेक्ट के लिए, :has() का इस्तेमाल फ़ॉलबैक के बिना, प्रोग्रेसिव एन्हांसमेंट के तौर पर किया जा सकता है.

ज़रूरी: ज़रूरी लेआउट के लिए फ़ॉलबैक लागू करते समय, आपको अपनी सीएसएस में @supports not selector(:has(*)) का इस्तेमाल करना होगा. इससे क्लास पर आधारित ट्रेडिशनल फ़ॉलबैक (जैसे, .has-image) को तय किया जा सकेगा.

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

अगर सर्वर-साइड रेंडरिंग का विकल्प नहीं है, तो आपको CSS.supports() के साथ एक छोटी स्क्रिप्ट का इस्तेमाल करना होगा. इससे कॉन्टेंट का पता लगाया जा सकता है और लोड होने पर या डाइनैमिक कॉन्टेंट इंजेक्शन के बाद क्लास को जोड़ा जा सकता है.

/* Fallback CSS for older browsers */
/* We check if the browser DOES NOT support the :has() selector */
@supports not selector(:has(*)) {
  /* Define a traditional modifier class that applies the exact same layout overrides */
  .article-card.has-image {
    flex-direction: row;
    align-items: center;
  }
  
  .article-card:not(.has-image) {
    background-color: #f9f9f9;
  }
}
/* Fallback JavaScript for older browsers (if not using SSR to add the class) */
/* Check for support before running the script to avoid unnecessary work in modern browsers */
if (!CSS.supports('selector(:has(*))')) {
  // Find all components that need checking
  const cards = document.querySelectorAll('.article-card');
  
  cards.forEach(card => {
    // If the critical content exists, manually add the fallback class
    if (card.querySelector('img')) {
      card.classList.add('has-image');
    }
  });
}