কন্টেন্ট ভিত্তিক স্টাইলিং

ওয়েব ফিচার: :has() :not()

আগে, কোনও কম্পোনেন্টের কন্টেন্টের উপর ভিত্তি করে সেটিতে আলাদা লেআউট প্রয়োগ করতে হলে, মডিফায়ার ক্লাস (যেমন .card--has-image বা .card--text-only) ইনজেক্ট করার জন্য আপনার HTML টেমপ্লেটিং ভাষায় JavaScript বা কন্ডিশনাল লজিক প্রয়োজন হত।

:has() সিউডো-ক্লাস পেরেন্ট সিলেক্টর হিসেবে কাজ করে এই প্রয়োজনীয়তা দূর করে। নির্দিষ্ট ডিসেন্ডেন্ট এলিমেন্টের উপস্থিতি বা অনুপস্থিতির উপর ভিত্তি করে এটি আপনাকে শর্তসাপেক্ষে কন্টেনার এলিমেন্ট স্টাইল করার অনুমতি দেয়।

:has() ব্যবহার করে, আপনি কোনও কম্পোনেন্টের আসল DOM কন্টেন্টের উপর ভিত্তি করে CSS-এ সম্পূর্ণ আলাদা লেআউট ভেরিয়েশন সহজেই নির্ধারণ করতে পারবেন। এছাড়াও, ডিফল্ট লেআউট নির্ধারণ করার জন্য কন্টেন্টের অনুপস্থিতি স্পষ্টভাবে টার্গেট করতে, আপনি ঐচ্ছিকভাবে এটি :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() ফলব্যাক ছাড়াই প্রোগ্রেসিভ এনহ্যান্সমেন্ট হিসেবে ব্যবহার করা যেতে পারে।

বাধ্যতামূলক: গুরুত্বপূর্ণ লেআউটের জন্য ফলব্যাক প্রয়োগ করার সময়, আপনাকে অবশ্যই আপনার CSS-এ @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');
    }
  });
}