CSS @scope at-rule দিয়ে আপনার নির্বাচকদের নাগাল সীমিত করুন, CSS @scope at-রুল দিয়ে আপনার নির্বাচকদের নাগাল সীমিত করুন

আপনার DOM-এর সীমিত সাবট্রির মধ্যে থাকা উপাদানগুলি নির্বাচন করতে @scope ব্যবহার করতে শিখুন।

প্রকাশিত: ৪ অক্টোবর, ২০২৩

Browser Support

  • ক্রোম: ১১৮।
  • প্রান্ত: ১১৮।
  • ফায়ারফক্স: ১৪৬।
  • সাফারি: ১৭.৪।

Source

নির্বাচক লেখার সময় আপনি নিজেকে দুটি জগতের মধ্যে আটকে থাকতে পারেন। একদিকে আপনি কোন উপাদানগুলি নির্বাচন করবেন সে সম্পর্কে বেশ সুনির্দিষ্ট হতে চান। অন্যদিকে, আপনি চান আপনার নির্বাচকগুলি যাতে ওভাররাইড করা সহজ হয় এবং DOM কাঠামোর সাথে শক্তভাবে সংযুক্ত না হয়।

উদাহরণস্বরূপ, যখন আপনি "কার্ড কম্পোনেন্টের কন্টেন্ট এরিয়ায় হিরো ইমেজ" নির্বাচন করতে চান - যা বেশ নির্দিষ্ট একটি উপাদান নির্বাচন - তখন আপনি সম্ভবত .card > .content > img.hero মতো একটি নির্বাচক লিখতে চান না।

  • এই নির্বাচকটির (0,3,1) স্পেসিফিসিটি বেশ উচ্চ, যা আপনার কোড বাড়ার সাথে সাথে ওভাররাইড করা কঠিন করে তোলে।
  • ডাইরেক্ট চাইল্ড কম্বিনেটরের উপর নির্ভর করে এটি DOM স্ট্রাকচারের সাথে শক্তভাবে সংযুক্ত। যদি মার্কআপ কখনও পরিবর্তিত হয়, তাহলে আপনার CSSও পরিবর্তন করতে হবে।

কিন্তু, আপনি সেই উপাদানটির জন্য কেবল img নির্বাচক হিসেবে লিখতে চাইবেন না, কারণ এটি আপনার পৃষ্ঠা জুড়ে সমস্ত চিত্র উপাদান নির্বাচন করবে।

এই পরিস্থিতিতে সঠিক ভারসাম্য খুঁজে বের করা প্রায়শই বেশ চ্যালেঞ্জিং। বছরের পর বছর ধরে, কিছু ডেভেলপার এই ধরনের পরিস্থিতিতে আপনাকে সাহায্য করার জন্য সমাধান এবং সমাধান নিয়ে এসেছেন। উদাহরণস্বরূপ:

  • BEM-এর মতো পদ্ধতিতে সেই উপাদানটিকে card__img card__img--hero এর একটি শ্রেণী দেওয়া হয় যাতে নির্দিষ্টতা কম থাকে এবং আপনি যা নির্বাচন করেন তাতে সুনির্দিষ্ট থাকতে পারেন।
  • জাভাস্ক্রিপ্ট-ভিত্তিক সমাধান যেমন স্কোপড সিএসএস বা স্টাইলড কম্পোনেন্টস আপনার সিলেক্টরগুলিতে এলোমেলোভাবে তৈরি স্ট্রিং - যেমন sc-596d7e0e-4 - যোগ করে আপনার সমস্ত সিলেক্টর পুনর্লিখন করে যাতে তারা আপনার পৃষ্ঠার অন্য দিকে থাকা উপাদানগুলিকে লক্ষ্যবস্তু করতে না পারে।
  • কিছু লাইব্রেরি এমনকি নির্বাচকদের সম্পূর্ণরূপে বাতিল করে দেয় এবং আপনাকে স্টাইলিং ট্রিগারগুলি সরাসরি মার্কআপের মধ্যেই রাখতে বাধ্য করে।

কিন্তু যদি আপনার এগুলোর কোনটিরই প্রয়োজন না থাকতো? যদি CSS আপনাকে কোন উপাদানগুলো নির্বাচন করবেন সে সম্পর্কে বেশ সুনির্দিষ্টভাবে বলতে পারতো, তাহলে আপনাকে উচ্চ নির্দিষ্টতার নির্বাচক লিখতে হবে না অথবা আপনার DOM-এর সাথে শক্তভাবে সংযুক্ত নির্বাচক লিখতে হবে না? আচ্ছা, এখানেই @scope কার্যকর হয়, যা আপনাকে শুধুমাত্র আপনার DOM-এর একটি সাবট্রির মধ্যে উপাদান নির্বাচন করার একটি উপায় প্রদান করে।

@scope-এর সাথে পরিচয় করিয়ে দিচ্ছি

@scope দিয়ে আপনি আপনার নির্বাচকদের নাগাল সীমিত করতে পারেন। আপনি স্কোপিং রুট সেট করে এটি করতে পারেন যা আপনি যে সাবট্রিকে টার্গেট করতে চান তার উপরের সীমানা নির্ধারণ করে। একটি স্কোপিং রুট সেটের সাহায্যে, অন্তর্ভুক্ত স্টাইল নিয়ম - যার নাম স্কোপড স্টাইল নিয়ম - শুধুমাত্র DOM এর সীমিত সাবট্রি থেকে নির্বাচন করতে পারে।

উদাহরণস্বরূপ, .card কম্পোনেন্টের শুধুমাত্র <img> এলিমেন্টগুলিকে টার্গেট করার জন্য, আপনি @scope at-rule-এর স্কোপিং রুট হিসেবে .card সেট করবেন।

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

স্কোপড স্টাইল নিয়ম img { … } কার্যকরভাবে শুধুমাত্র <img> উপাদান নির্বাচন করতে পারে যা মিলিত .card উপাদানের সুযোগে রয়েছে।

কার্ডের কন্টেন্ট এরিয়া ( .card__content ) এর ভিতরে থাকা <img> এলিমেন্টগুলিকে নির্বাচন করা থেকে বিরত রাখতে আপনি img সিলেক্টরটিকে আরও সুনির্দিষ্ট করতে পারেন। এটি করার আরেকটি উপায় হল @scope at-rule একটি স্কোপিং লিমিট গ্রহণ করে যা নিম্ন সীমানা নির্ধারণ করে।

@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 prepended পায়। আপনি যদি চান, তাহলে আপনি নিজে :scope prepending করে এটি সম্পর্কে স্পষ্টভাবে বলতে পারেন। বিকল্পভাবে, আপনি CSS Nesting থেকে & selector প্রিপেন্ড করতে পারেন।

@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 সিউডো-ক্লাস ব্যবহার করতে পারে:

/* .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)

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

নিম্নলিখিত উদাহরণে, অভ্যন্তরীণভাবে, & স্কোপিং রুটের জন্য ব্যবহৃত নির্বাচকের সাথে পুনরায় লেখা হয়, একটি :is() নির্বাচকের ভিতরে মোড়ানো হয়। শেষে, ব্রাউজারটি ম্যাচিং করার জন্য নির্বাচক হিসাবে :is(#sidebar, .card) img ব্যবহার করবে। এই প্রক্রিয়াটিকে desugaring বলা হয়।

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

যেহেতু & ব্যবহার করে বিকৃত করা হয় :is() & এর নির্দিষ্টতা :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>

উপরের উদাহরণে, স্কোপড নিয়মগুলি শুধুমাত্র ক্লাসের নাম card__header সহ div এর ভিতরের উপাদানগুলিকে লক্ষ্য করে, কারণ সেই div হল <style> উপাদানের মূল উপাদান।

ক্যাসকেডে @স্কোপ

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 এ দুটি হপ। অতএব, .lighta সিলেক্টর জিতবে।

স্টাইল আইসোলেশন নয়, নির্বাচক আইসোলেশন

জেনে রাখুন যে @scope নির্বাচকদের নাগালের মধ্যে সীমাবদ্ধ। এটি স্টাইল আইসোলেশন অফার করে না। যেসব বৈশিষ্ট্য শিশুদের কাছে উত্তরাধিকারসূত্রে আসে তারা @scope এর নিম্ন সীমানার বাইরেও উত্তরাধিকারসূত্রে পায়। এরকম একটি বৈশিষ্ট্য হল color । ডোনাট স্কোপের ভিতরে সেই বৈশিষ্ট্যটি ঘোষণা করার সময়, color এখনও ডোনাটের গর্তের ভিতরে শিশুদের কাছে উত্তরাধিকারসূত্রে পায়।

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

উদাহরণে, .card__content উপাদান এবং এর সন্তানদের রঙ hotpink কারণ তারা .card থেকে মান উত্তরাধিকার সূত্রে পেয়েছে।