:has(): পারিবারিক নির্বাচক

সময় শুরু হওয়ার পর থেকে (সিএসএস পদে), আমরা বিভিন্ন অর্থে একটি ক্যাসকেডের সাথে কাজ করেছি। আমাদের শৈলীগুলি একটি "ক্যাসকেডিং স্টাইল শীট" রচনা করে। এবং আমাদের নির্বাচকরাও ক্যাসকেড। তারা পাশ দিয়ে যেতে পারে। বেশিরভাগ ক্ষেত্রে তারা নীচের দিকে যায়। কিন্তু কখনই উপরের দিকে নয়। বছরের পর বছর ধরে, আমরা একজন "অভিভাবক নির্বাচক" সম্পর্কে কল্পনা করেছি। এবং এখন এটি অবশেষে আসছে! একটি :has() ছদ্ম নির্বাচক আকারে।

:has() সিএসএস সিউডো-ক্লাস একটি উপাদানের প্রতিনিধিত্ব করে যদি পরামিতি হিসাবে পাস করা কোনো নির্বাচক কমপক্ষে একটি উপাদানের সাথে মেলে।

কিন্তু, এটি একটি "অভিভাবক" নির্বাচকের চেয়ে বেশি। এটি বাজারজাত করার একটি চমৎকার উপায়। অতটা আবেদনময়ী উপায় হতে পারে "শর্তাধীন পরিবেশ" নির্বাচক। কিন্তু যে এটা বেশ একই রিং আছে না. কিভাবে "পরিবার" নির্বাচক সম্পর্কে?

ব্রাউজার সমর্থন

আমরা আরও এগিয়ে যাওয়ার আগে, ব্রাউজার সমর্থন উল্লেখ করার মতো। এটা এখনও পুরোপুরি সেখানে না. কিন্তু, এটা কাছাকাছি হচ্ছে. এখনও ফায়ারফক্স সমর্থন নেই, এটি রোডম্যাপে রয়েছে৷ কিন্তু এটি ইতিমধ্যেই Safari-এ রয়েছে এবং Chromium 105-এ মুক্তির জন্য রয়েছে৷ এই নিবন্ধের সমস্ত ডেমোগুলি আপনাকে বলবে যে সেগুলি ব্যবহৃত ব্রাউজারে সমর্থিত না হলে৷

কিভাবে ব্যবহার করবেন :has

তাই এটা কি মত দেখায়? ক্লাস everybody সাথে দুটি ভাইবোন উপাদান সহ নিম্নলিখিত HTML বিবেচনা করুন। আপনি কিভাবে ক্লাস a-good-time সহ একটি বংশধর আছে তাকে নির্বাচন করবেন?

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

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

:has() দিয়ে, আপনি নিম্নলিখিত CSS এর সাথে এটি করতে পারেন।

.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)) { ... } সরাসরি input আছে এমন label নির্বাচন করুন ভাইবোন পাশ দিয়ে যাচ্ছে! css label:has(+ input) { … } article নির্বাচন করুন যেখানে একটি বংশধর img alt টেক্সট নেই 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>

এবং আপনি এটি সেখানে ছেড়ে যেতে হবে না. আপনি এটা দিয়ে সৃজনশীল পেতে পারে. "বৈশিষ্ট্যযুক্ত" সামগ্রী দেখানো একটি কার্ড কীভাবে একটি বিন্যাসের মধ্যে মানিয়ে নিতে পারে? এই CSS লেআউটের সম্পূর্ণ প্রস্থের একটি বৈশিষ্ট্যযুক্ত কার্ড তৈরি করবে এবং এটি একটি গ্রিডের শুরুতে স্থাপন করবে।

.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() দিয়ে, এটি অনেক সহজ হয়ে যায়। আমরা প্রাসঙ্গিক ফর্ম সিউডো-ক্লাসে হুক করতে পারি, উদাহরণস্বরূপ :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 বৈশিষ্ট্য ব্যবহার করতে পারে। জাভাস্ক্রিপ্ট উপযুক্ত বৈশিষ্ট্য আপডেট করতে ব্যবহার করা যেতে পারে। aria-expanded true হলে, এটি সনাক্ত করতে :has() ব্যবহার করুন এবং স্লাইডিং এনএভি-র শৈলী আপডেট করুন। JavaScript তার অংশটি করে এবং CSS সেই তথ্য দিয়ে যা চায় তা করতে পারে। চারপাশে মার্কআপ এলোমেলো করার বা অতিরিক্ত শ্রেণির নাম যোগ করার দরকার নেই, ইত্যাদি (দ্রষ্টব্য: এটি একটি উত্পাদন প্রস্তুত উদাহরণ নয়)।

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

পারেন: ব্যবহারকারীর ত্রুটি এড়াতে সাহায্য করতে পারে?

এই সব উদাহরণ কি মিল আছে? তারা :has() ব্যবহার করার উপায় দেখায়, তাদের কোনোটিরই ক্লাসের নাম পরিবর্তন করার প্রয়োজন নেই। তারা প্রত্যেকে নতুন বিষয়বস্তু সন্নিবেশিত করেছে এবং একটি বৈশিষ্ট্য আপডেট করেছে। এটি :has() এর একটি বড় সুবিধা, এটি ব্যবহারকারীর ত্রুটি কমাতে সাহায্য করতে পারে। :has() দিয়ে CSS DOM-এ পরিবর্তনগুলি সামঞ্জস্য করার দায়িত্ব নিতে সক্ষম। আপনাকে জাভাস্ক্রিপ্টে ক্লাসের নাম ঠকাতে হবে না, যা ডেভেলপারের ত্রুটির জন্য কম সম্ভাবনা তৈরি করে। যখন আমরা একটি ক্লাসের নাম টাইপ করি তখন আমরা সবাই সেখানে থাকি এবং সেগুলিকে Object লুকআপে রাখার অবলম্বন করতে হয়।

এটি একটি আকর্ষণীয় চিন্তা এবং এটি কি আমাদের ক্লিনার মার্কআপ এবং কম কোডের দিকে নিয়ে যায়? কম জাভাস্ক্রিপ্ট যেহেতু আমরা অনেক জাভাস্ক্রিপ্ট সামঞ্জস্য করছি না। কম HTML যেহেতু আপনার আর card card--has-media ইত্যাদি ক্লাসের প্রয়োজন নেই।

বাক্সের বাইরে চিন্তা

উপরে উল্লিখিত হিসাবে, :has() আপনাকে মানসিক মডেল ভাঙতে উত্সাহিত করে। এটি বিভিন্ন জিনিস চেষ্টা করার একটি সুযোগ. সীমানাগুলিকে ঠেলে দেওয়ার মতো একটি উপায় হল একা সিএসএস দিয়ে গেম মেকানিক্স তৈরি করা। আপনি উদাহরণস্বরূপ ফর্ম এবং CSS সহ একটি ধাপ ভিত্তিক মেকানিক তৈরি করতে পারেন।

<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() a :has() পারবেন না। কিন্তু আপনি একটি চেইন করতে পারেন :has()css :has(.a:has(.b)) { … }
  • :has() css :has(::after) { … } :has(::first-letter) { … } মধ্যে কোনও ছদ্ম উপাদান ব্যবহার নেই
  • শুধুমাত্র যৌগ নির্বাচক css ::slotted(:has(.a)) { … } :host(:has(.a)) { … } :host-context(:has(.a)) { … } ::cue(:has(.a)) { … } গ্রহণ করে সিউডোর ভিতরে :has() ব্যবহার সীমাবদ্ধ করুন। css ::slotted(:has(.a)) { … } :host(:has(.a)) { … } :host-context(:has(.a)) { … } ::cue(:has(.a)) { … }
  • সিউডো এলিমেন্ট css ::part(foo):has(:focus) { … } এর পরে :has() এর ব্যবহার সীমাবদ্ধ করুন
  • :visited এর ব্যবহার সর্বদা মিথ্যা css :has(:visited) { … }

:has() এর সাথে সম্পর্কিত প্রকৃত কর্মক্ষমতা মেট্রিক্সের জন্য, এই সমস্যাটি দেখুন। এই অন্তর্দৃষ্টি এবং বাস্তবায়নের চারপাশে বিশদ ভাগ করার জন্য Byungwoo কে ক্রেডিট।

তাই তো!

এর জন্য প্রস্তুত হন :has() । এটি সম্পর্কে আপনার বন্ধুদের বলুন এবং এই পোস্টটি শেয়ার করুন, এটি একটি গেম চেঞ্জার হতে চলেছে যেভাবে আমরা CSS এর সাথে যোগাযোগ করি৷

সমস্ত ডেমো এই কোডপেন সংগ্রহে উপলব্ধ।