এই পর্বে যা শিখবেন
- দুটি নিয়মের লড়াইয়ে ব্রাউজার কোন ক্রমে বিচার করে — cascade-এর পুরো সিঁড়ি
- যেকোনো selector-এর specificity হাতে হিসাব করা, আর
:is()/:where()-এর বিশেষ নিয়ম - user-agent, user আর author stylesheet;
!importantকেন ক্রম উল্টে দেয়, আর কখন সেটা বৈধ - কোন property উত্তরাধিকারে নামে, কোনটি নয়;
inherit,initial,unset,revert,revert-layer-এর পার্থক্য - DevTools-এর Styles আর Computed ট্যাব দিয়ে “আমার CSS কাজ করছে না কেন” প্রশ্নের উত্তর খোঁজা
১ · দুই নিয়ম, এক element — কে জেতে?
আপনার অনলাইন দোকানের পাতায় একটি দাম লেখা আছে। আপনি CSS-এ লিখলেন দাম হবে সবুজ। কিছুক্ষণ পর একই ফাইলে, অন্য জায়গায়, আরেকজন সহকর্মী লিখলেন সব অনুচ্ছেদ হবে লাল। ব্রাউজার এখন কী করবে? একটি লেখা তো একসাথে সবুজ আর লাল হতে পারে না। একটিকে জিততেই হবে।
পর্ব ১৬-এ দেখেছেন, CSS-এর প্রতিটি rule-এর দুটি অংশ — একটি selector (কাকে সাজাব) আর কয়েকটি declaration (property আর মানের জোড়া, যেমন color: green). পর্ব ১৭-এ দেখেছেন selector কত রকমের হয়। বাস্তবের যেকোনো সাইটে একটি element-এর ওপর একসাথে দশ-বিশটি rule লাগে — ব্রাউজারের নিজের ডিফল্ট, আপনার ফাইল, কোনো library, কখনো HTML-এর ভেতরে লেখা style. এদের মধ্যে একই property নিয়ে বিরোধ হলে কে জিতবে, সেটা ঠিক করার পুরো নিয়মের নাম cascade.
একটি সরকারি অফিসের নোটিশ বোর্ড ভাবুন। ওপরে টাঙানো আছে মন্ত্রণালয়ের সাধারণ নির্দেশ: “অফিস খোলা সকাল ৯টায়।” তার নিচে বিভাগীয় প্রধানের নোটিশ: “হিসাব শাখা রমজানে খোলা সকাল ১০টায়।” আর একদম নিচে আজকের তারিখে একটি জরুরি নোটিশ। হিসাব শাখার একজন কর্মী কোনটি মানবেন? তিনি মনে মনে কয়েকটি প্রশ্ন করেন — কার কর্তৃত্ব বেশি, কোন নোটিশ ঠিক আমার শাখার কথা বলছে, কোনটি সবচেয়ে নতুন। CSS-এর cascade ঠিক এই প্রশ্নগুলোই, একটি নির্দিষ্ট ক্রমে, করে।
শুরু করা যাক একটি ছোট ধাঁধা দিয়ে। নিচের CSS-এ দুটি জোড়া নিয়ম আছে। প্রিভিউ দেখার আগে অনুমান করুন — লেখার রং কী হবে, আর পেছনের রং কী হবে?
/* জোড়া ১: একই selector, দুই রং */
p { color: green; }
p { color: crimson; }
/* জোড়া ২: আগে class, পরে type selector */
.notice { background: #fef3c7; }
p { background: #e0f2fe; }
p { padding: 8px; font-size: 18px; }দুটি অনুচ্ছেদই লাল (crimson) — কারণ দুটি p rule সমান ওজনের, তাই পরে যেটি লেখা সেটি জেতে। কিন্তু প্রথম অনুচ্ছেদের পেছনে হলুদ, যদিও নীল রংটি পরে লেখা! কারণ .notice একটি class selector, যা p-এর চেয়ে বেশি “নির্দিষ্ট” — এখানে লেখার ক্রম প্রশ্নই ওঠে না। দ্বিতীয় অনুচ্ছেদে .notice নেই, তাই সে নীল পায়। চেষ্টা করুন: প্রথম জোড়ার দুই লাইনের জায়গা বদলে দিন — রং সবুজ হয় কি না দেখুন। তারপর .notice-কে লিখুন p.notice — কিছু বদলায়? কেন বদলায় না, অংশ ৪-এ বুঝবেন।
এই ছোট উদাহরণেই দুটি আলাদা নিয়ম কাজ করল: লেখার ক্রম আর specificity. আরও কয়েকটি আছে। নামটির মানেও এখান থেকেই — cascade ইংরেজিতে ধাপে ধাপে নেমে আসা ঝরনা। নিয়মগুলো যেন ঝরনার এক একটি ধাপ: ওপরের ধাপে সিদ্ধান্ত হয়ে গেলে নিচে নামার দরকার পড়ে না।
১৯৯৪ সালের ১০ অক্টোবর CERN-এ কাজ করা নরওয়ের Håkon Wium Lie একটি প্রস্তাব প্রকাশ করেন — “Cascading HTML style sheets”. তাঁর মূল ভাবনা ছিল, পাতার চেহারা শুধু লেখক একা ঠিক করবেন না; পাঠকও নিজের পছন্দ (যেমন বড় অক্ষর) জানাতে পারবেন, আর দুই পক্ষের ইচ্ছা মিলিয়ে একটি ফল হবে। এই “মিলিয়ে নেওয়ার” নিয়মটাই cascade. পরে Bert Bos যোগ দেন, আর ১৯৯৬ সালের ডিসেম্বরে W3C প্রকাশ করে CSS level 1.
২ · Cascade-এর পুরো সিঁড়ি — ব্রাউজার কোন ক্রমে বিচার করে
প্রথমে একটি জরুরি কথা: cascade কাজ করে প্রতিটি property-র জন্য আলাদাভাবে। একটি rule পুরোটা জেতে বা হারে না। একটি rule-এর color হারতে পারে, অথচ একই rule-এর padding জিততে পারে। ব্রাউজার প্রতিটি element-এর প্রতিটি property-র জন্য সব প্রতিযোগী declaration জড়ো করে, তারপর নিচের প্রশ্নগুলো এই ক্রমে করে। কোনো প্রশ্নে একজন স্পষ্ট এগিয়ে থাকলে খেলা সেখানেই শেষ।
- উৎস ও গুরুত্ব
origin, !importantকে লিখেছে - Inline style
style="…"element-এর গায়ে - Layer
@layerকোন তাকে - Specificity
(a, b, c)কতটা নির্দিষ্ট - নৈকট্য
@scopeকতটা কাছে - লেখার ক্রম
শেষেরটিকে পরে
/* ব্রাউজারের নিজের stylesheet */ h1 { font-size: 2em; } /* আপনার style.css */ h1 { font-size: 28px; } ← জিতল: author > user-agent
/* style.css */ #buy.btn.primary { color: white; } <!-- HTML --> <button id="buy" class="btn primary" style="color: yellow"> ← জিতল
@layer base {
#buy { color: red; } (1,0,0) — তবু হারল
}
.btn { color: white; } ← জিতল: layer-এর বাইরে
#buy { color: red; } (1,0,0) ← জিতল .btn.primary { color: white; } (0,2,0)
@scope (.page) { p { color: gray; } }
@scope (.card) { p { color: navy; } } ← জিতল
<div class="page"><div class="card"><p>
p-এর সবচেয়ে কাছের root হলো .card
.price { color: green; }
.price { color: crimson; } ← জিতল: পরে লেখা
- ধাপ ১ — উৎস আর গুরুত্ব। declaration-টি কে লিখেছে — ব্রাউজার (user-agent), পাঠক (user), নাকি সাইটের লেখক (author)? আর তাতে
!importantআছে কি না? সাধারণ declaration-এ author সবার ওপরে, তাই আপনারh1ব্রাউজারের ডিফল্টকে হারায়। (অংশ ৩-এ বিস্তারিত।) - ধাপ ২ — element-এর গায়ে লেখা style. উৎস আর গুরুত্ব সমান হলে, HTML-এর
styleattribute-এ লেখা inline style যেকোনো stylesheet rule-কে হারায় — selector যত ভারীই হোক।#buy.btn.primary-এর মতো শক্ত selector-ও এখানে হেরে গেল। - ধাপ ৩ — layer. Cascade layer (
@layer) হলো নিয়ম রাখার আলাদা আলাদা তাক। সাধারণ declaration-এ পরে ঘোষিত layer আগেরটিকে হারায়, আর কোনো layer-এ না থাকা CSS সব layer-কে হারায়। খেয়াল করুন, এই ধাপ specificity-র আগে — তাই layer-এর ভেতরের id selector-ও বাইরের ছোট class-এর কাছে হারল। (অংশ ৫-এ।) - ধাপ ৪ — specificity. এবার selector-এর ওজন মাপা হয়: কয়টি id, কয়টি class-জাতীয়, কয়টি type.
(1,0,0)বনাম(0,2,0)— প্রথম ঘরেই id জিতে গেল, বাকি ঘর দেখারই দরকার নেই। (অংশ ৪-এ পুরো হিসাব।) - ধাপ ৫ — scope-এর নৈকট্য। দুটি
@scoperule-এর specificity সমান হলে, যার scope-এর মূল (root) element-টির সবচেয়ে কাছে, সে জেতে।p-এর কাছের root.card, তাই navy. এটি নতুন CSS — বিস্তারিত পর্ব ৩৭-এ। - ধাপ ৬ — লেখার ক্রম। সব সমান হলে যে declaration সবশেষে আসে, সে জেতে — একই ফাইলের নিচের দিকে, অথবা পরে যুক্ত হওয়া ফাইলে। এই শেষ ধাপে কখনো টাই থাকে না, তাই প্রতিটি লড়াইয়ের একজন বিজয়ী থাকেই।
ওপরের ধাপে ফয়সালা হলে নিচের ধাপ আর দেখা হয় না
নতুনরা প্রায়ই ভাবেন “specificity-ই সব”। আসলে specificity সিঁড়ির চতুর্থ ধাপ। !important, inline style আর layer — এই তিনটি specificity-র আগেই খেলা শেষ করে দিতে পারে। আর specificity সমান হলে তখন লেখার ক্রম। “আমার selector তো বেশি শক্ত, তবু হারছে কেন?” — এই প্রশ্নের উত্তর প্রায় সবসময় ওপরের তিন ধাপের কোনো একটিতে লুকিয়ে থাকে।
স্পেসিফিকেশনে (CSS Cascading and Inheritance) উৎস আর inline style-এর মাঝে আরও একটি ধাপ আছে — context. এটি শুধু Shadow DOM-এর জন্য, যেখানে একটি component-এর ভেতরের CSS আর বাইরের পাতার CSS আলাদা জগৎ। সাধারণ পাতায় এর প্রভাব নেই; Web Components-এর কথা আসবে পর্ব ৫২-এ। আর CSS animation ও transition-এর মানও cascade-এর অংশ — চলমান transition সবকিছুর ওপরে বসে। সেটি পর্ব ৩৮-৩৯-এ দেখবেন।
৩ · তিন উৎস আর !important — কর্তৃত্বের লড়াই
একটি পাতার CSS তিনটি জায়গা থেকে আসতে পারে। এই উৎসকে বলে cascade origin.
🌐 User-agent stylesheet
ব্রাউজারের নিজের ডিফল্ট CSS — h1 বড় আর মোটা, লিংক নীল আর নিচে দাগ, তালিকায় বুলেট। কোনো CSS না লিখলেও পাতা যে পড়া যায়, তা এর জন্যই।
🧑 User stylesheet
পাঠকের নিজের পছন্দ — যেমন দৃষ্টি দুর্বল কেউ সব লেখা বড় আর হলুদ-কালো করতে চান। ব্রাউজারের সেটিং, extension বা অপারেটিং সিস্টেমের high contrast মোড দিয়ে আসে।
মাঝখানে✍️ Author stylesheet
সাইটের লেখক, অর্থাৎ আপনার CSS — <link>, <style> আর style attribute সবই এর মধ্যে। কোনো library বা framework-এর CSS-ও author.
সাধারণ declaration-এর ক্ষেত্রে ক্রমটা সহজ: author > user > user-agent. কিন্তু declaration-এর শেষে !important লিখলে সেটি একটি আলাদা, উঁচু শ্রেণিতে উঠে যায় — আর সেই শ্রেণিতে উৎসের ক্রম উল্টে যায়:
| শক্তি (ওপরে সবচেয়ে বেশি) | কে | কেন এই জায়গায় |
|---|---|---|
| ১ | user-agent !important | ব্রাউজারের কিছু নিয়ম কেউ বদলাতে পারবে না, এমন নিশ্চয়তা |
| ২ | user !important | পাঠকের প্রয়োজন (যেমন বড় লেখা) সাইটের নকশার চেয়ে বড় |
| ৩ | author !important | লেখকের জরুরি নিয়ম |
| ৪ | author সাধারণ | আপনার প্রতিদিনের CSS |
| ৫ | user সাধারণ | পাঠকের সাধারণ পছন্দ — লেখক চাইলে বদলাতে পারেন |
| ৬ | user-agent সাধারণ | শুধু ডিফল্ট — যে কেউ বদলাতে পারে |
উল্টে যাওয়ার কারণটা মানবিক। পাঠক যখন !important দিয়ে বলছেন “আমার লেখা অন্তত 20px হতেই হবে”, তখন সেটা সাধারণত পছন্দ নয়, প্রয়োজন — চোখের সমস্যা, পড়ার অসুবিধা। লেখকের নকশা যত সুন্দরই হোক, সেই প্রয়োজনকে হারাতে দেওয়া যায় না। (CSS1-এ নিয়মটা উল্টো ছিল; ১৯৯৮ সালের CSS2-এ এই পরিবর্তন আসে — ভাবনার প্রশ্ন ৩-এ গল্পটা আছে।)
এবার author-এর ভেতরের লড়াই দেখুন। নিচের কোডে একটি id rule, !important-ওয়ালা একটি class rule আর একটি inline style আছে। তিনটি অনুচ্ছেদের রং কী হবে, আগে অনুমান করুন:
<style>
#offer { color: navy; }
.price { color: green !important; }
p { font-size: 20px; font-weight: bold; margin: 6px 0; }
</style>
<p id="offer" class="price" style="color: purple">১. ঈদ অফার: ৳ ৯৯৯</p>
<p class="price">২. শুধু class আছে</p>
<p id="offer2" style="color: purple">৩. শুধু inline style আছে</p>প্রথম দুটি সবুজ, তৃতীয়টি বেগুনি। প্রথমটিতে id-র navy আর inline-এর purple দুটোই হেরেছে, কারণ !important ধাপ ১-এই খেলা শেষ করেছে — specificity বা inline style বিবেচনাতেই আসেনি। চেষ্টা করুন: .price-এর !important মুছে দিন — এবার প্রথমটি বেগুনি (inline style ধাপ ২-এ জিতল), দ্বিতীয়টি সবুজই থাকল। তারপর !important ফিরিয়ে দিয়ে প্রথম অনুচ্ছেদের style-কে লিখুন style="color: purple !important" — দুই পক্ষই এখন important, তাই আবার inline style জেতে।
একটি সাধারণ ভুল: !important-কে ভাবা “specificity অনেক বাড়িয়ে দেওয়া”। না — এটি specificity-ই বদলায় না, declaration-টিকে একদম আলাদা শ্রেণিতে তোলে। দুটি important declaration লড়লে তাদের মধ্যে আবার specificity আর ক্রম দিয়ে বিচার হয়। তাই একবার !important লিখলে, সেটাকে হারাতে আরেকটি !important লাগে, তারপর আরেকটি… এভাবেই CSS ফাইল ভরে যায় “important-যুদ্ধে”।
৪ · Specificity — তিন ঘরের হিসাব, পয়েন্ট নয়
Specificity মানে selector-টি কতটা “নির্দিষ্ট” করে element-কে চিহ্নিত করছে। “সব অনুচ্ছেদ” (p) একটি ঢালাও কথা; “নোটিশ class-এর অনুচ্ছেদ” (.notice) আরও নির্দিষ্ট; “অফার নামের একটিমাত্র element” (#offer) সবচেয়ে নির্দিষ্ট। ব্রাউজার এই নির্দিষ্টতা মাপে তিনটি ঘরে গুনে, যাকে লেখা হয় (a, b, c):
| ঘর | কী গোনা হয় | উদাহরণ |
|---|---|---|
| a — id | id selector | #cart |
| b — class-জাতীয় | class, attribute selector, pseudo-class | .item, [type="email"], :hover |
| c — type-জাতীয় | type (ট্যাগের নাম), pseudo-element | li, ::before |
| শূন্য | universal selector *, combinator (>, +, ~, ফাঁকা জায়গা), :where() | ul > *-এর ওজন শুধু ul-এর |
তুলনার নিয়ম একটাই, আর এটাই সবচেয়ে গুরুত্বপূর্ণ: বাঁ দিক থেকে ঘর ধরে তুলনা করুন। যার a বেশি, সে জিতল — বাকি ঘর দেখার দরকার নেই। a সমান হলে b দেখুন, তারপর c. এটা ঠিক অভিধানে শব্দ সাজানোর মতো: “কলম” আর “কাগজ”-এর মধ্যে কোনটি আগে, তা ঠিক হয় প্রথম যে অক্ষরে পার্থক্য, সেখান থেকেই। পরের অক্ষর যতই হোক, কিছু যায় আসে না।
নিচের ডায়াগ্রামে আটটি selector-এর specificity এক এক করে গোনা হচ্ছে। “পরে” চাপুন, আর প্রতিটি ধাপে কোন অংশ কোন ঘরে যাচ্ছে খেয়াল করুন:
1p2.price3ul li.sale4#cart .item:hover5a[href^="https"]::after6:is(#main, .box) p7:where(#main, .box) p8.card:not(.sold, #x) > *
| a (id) | |
| b (class…) | |
| c (type…) |
p— একটি type selector.cঘরে ১, ফল(0,0,1). সবচেয়ে হালকা ওজনের selector-গুলোর একটি।.price— একটি class.bঘরে ১, ফল(0,1,0). তুলনা:(0,1,0)বনাম(0,0,1)—aসমান (০),b-তে ১ বনাম ০, তাই class জিতল।cঘর দেখাই হলো না।ul li.sale— দুটি type (ul,li) আর একটি class (.sale). মাঝের ফাঁকা জায়গাটি descendant combinator — তার কোনো ওজন নেই। ফল(0,1,2).#cart .item:hover— একটি id, একটি class, আর:hoverএকটি pseudo-class, যেটিওbঘরে যায়। ফল(1,2,0). শুধু একটি id থাকায় এটি আগের সবকটিকে হারায়।a[href^="https"]::after—atype (c), attribute selector[href^="https"]class-এর সমান (b), আর::afterpseudo-element, যা type-এর সমান (c). ফল(0,1,2)— ৩ নম্বরের সাথে সমান, তাই দুটি লড়লে লেখার ক্রম বিচার করবে।:is(#main, .box) p—:is()-এর নিজের কোনো ওজন নেই; সে নেয় তার তালিকার সবচেয়ে ভারী selector-এর ওজন। তালিকায়#main(1,0,0)আর.box(0,1,0)— ভারী হলো#main. সাথেp. ফল(1,0,1). চমকে দেওয়ার মতো ব্যাপার: element-টি আসলে.box-এর ভেতরে থাকলেও, পাতায়#mainনামে কিছু না থাকলেও, ওজন id-র!:where(#main, .box) p— একই তালিকা, কিন্তু:where()-এর ওজন সবসময় শূন্য, ভেতরে যা-ই থাকুক। শুধুpগোনা হয়, ফল(0,0,1). মিলবে একই element-এ, কিন্তু যেকোনো class দিয়ে সহজে বদলানো যাবে।.card:not(.sold, #x) > *—:not()-ও:is()-এর মতো তালিকার সবচেয়ে ভারী selector-এর ওজন নেয়, এখানে#x. সাথে.card. শেষের>আর*শূন্য। ফল(1,1,0). আটটির মধ্যে সবচেয়ে ভারী#cart .item:hover(1,2,0)—aসমান,b-তে ২ বনাম ১।
কেন “id = ১০০ পয়েন্ট, class = ১০ পয়েন্ট” ভুল
পুরোনো অনেক টিউটোরিয়াল (আর AI-ও প্রায়ই) শেখায়: id-এর জন্য ১০০, class-এর জন্য ১০, type-এর জন্য ১ পয়েন্ট যোগ করুন, যার মোট বেশি সে জেতে। ছোট উদাহরণে এটা মিলে যায় বলে ভুলটা ধরা পড়ে না। কিন্তু ঘরগুলো একটি থেকে আরেকটিতে “উপচে পড়ে” না — ১১টি class মিলে (0,11,0) হয়, ১১০ পয়েন্ট নয়, আর সেটি (1,0,0)-এর কাছে হারে। নিজেই পরীক্ষা করুন:
/* (1,0,0) — একটি মাত্র id */
#box { background: seagreen; }
/* (0,11,0) — এগারোটি class, আর পরে লেখা */
.a.b.c.d.e.f.g.h.i.j.k { background: tomato; }
div { color: white; padding: 16px; font-size: 20px; border-radius: 8px; }বাক্সটি সবুজ (seagreen). এগারোটি class, আবার পরে লেখা — তবু একটি id-র কাছে হারল, কারণ প্রথম ঘর a-তেই ১ বনাম ০. “পয়েন্ট” হিসাবে ১১০ বনাম ১০০ হলে টমেটো-লাল জিতত — বাস্তবে জেতেনি। চেষ্টা করুন: #box-কে লিখুন [id="box"]. একই element ধরে, কিন্তু এটি attribute selector, ওজন (0,1,0) — এবার লাল জিতবে। id-র ভারী ওজন এড়ানোর এটি একটি পরিচিত কৌশল।
:is() আর :where() — একই কাজ, উল্টো ওজন
:is() আর :where() দুটোই একটি selector-তালিকাকে এক জায়গায় গুছিয়ে লেখার উপায়: :is(h1, h2, h3) a মানে “h1, h2 বা h3-এর ভেতরের লিংক”। দুটোই Baseline Widely available — সব আধুনিক ব্রাউজারে বহু বছর ধরে চলে। :has()-ও (পর্ব ৩৪-এ বিস্তারিত) specificity-র হিসাবে :is()-এর মতো আচরণ করে। পার্থক্য শুধু ওজনে, আর সেই পার্থক্যই বড় প্রজেক্টে বিশাল প্রভাব ফেলে। ধরুন একটি library-র CSS আপনি নিজের সাইটে যোগ করেছেন:
/* library-র বেস স্টাইল */
:is(#site-header, .menu) a {
color: gray;
margin-right: 12px;
font-size: 18px;
}
/* আপনার নিয়ম: বর্তমান পাতার লিংক লাল আর মোটা */
.active { color: crimson; font-weight: bold; }“অফার” লিংকটি মোটা হয়েছে, কিন্তু লাল হয়নি, ধূসরই রয়ে গেছে! কারণ :is() তালিকার ভারী সদস্য #site-header-এর ওজন নিয়েছে: (1,0,1), আর আপনার .active মাত্র (0,1,0). পাতায় #site-header নামে কিছু নেই — তবু তার ওজন গোনা হয়। font-weight নিয়ে কোনো লড়াই ছিল না, তাই সেটি কাজ করেছে (মনে রাখুন, cascade প্রতিটি property-তে আলাদা)। চেষ্টা করুন: :is-কে :where করে দিন — সাথে সাথে “অফার” লাল। ভালো library এই কারণেই তাদের বেস স্টাইল :where()-এ লেখে।
CSS nesting-এ (পর্ব ৩৫) যে & চিহ্ন ব্যবহার হয়, সেটিও specificity-র হিসাবে :is()-এর মতো আচরণ করে — বাইরের selector-তালিকা কমা দিয়ে লেখা হলে তার সবচেয়ে ভারী সদস্যের ওজন নেয়। Nesting দিয়ে লেখা CSS-এ হঠাৎ “এটা কেন জিতল” ধরনের চমক এখান থেকেই আসে।
৫ · Layer, scope, লেখার ক্রম আর inline style
@layer — নিয়মের তাক
একটি বড় দোকানের গুদামের কথা ভাবুন। নিচের তাকে সাধারণ মাল, মাঝের তাকে বিশেষ মাল, ওপরের তাকে আজকের অফারের মাল। দোকানি ঠিক করে রেখেছেন, কাউন্টারে আগে ওপরের তাকের জিনিস যাবে — মাল কত দামি, তা বিবেচ্য নয়। @layer CSS-এ ঠিক এই কাজটি করে: কোন দল নিয়ম কোন দলের ওপরে থাকবে, সেটা আপনি আগেই ঘোষণা করেন, আর specificity-র হিসাব শুধু একই layer-এর ভেতরে চলে।
/* তাকের ক্রম ঘোষণা: আগে base, পরে components */
@layer base, components;
@layer components {
#buy.btn.primary { background: gray; } /* (1,2,0) */
}
@layer base {
button { background: orange; } /* (0,0,1) */
}
/* কোনো layer-এ নেই */
button { background: seagreen; }
button { color: white; padding: 10px 18px; border: 0; border-radius: 8px; font-size: 18px; }বোতামটি সবুজ (seagreen). layer-এর ভেতরে (1,2,0)-এর মতো ভারী selector থাকলেও, layer-এর বাইরের সাধারণ button জিতেছে — কারণ layer-এর ধাপ specificity-র আগে, আর layer-বিহীন CSS সব layer-এর ওপরে। চেষ্টা করুন: layer-বিহীন background: seagreen লাইনটি মুছুন — এবার ধূসর, কারণ components পরে ঘোষিত। তারপর প্রথম লাইনে ক্রম উল্টে লিখুন @layer components, base; — এবার কমলা, যদিও button সবচেয়ে হালকা selector.
সাধারণ declaration-এ নিয়ম: পরে ঘোষিত layer জেতে, আর layer-এর বাইরের CSS সবার ওপরে। !important-এ এটিও উল্টে যায় — আগে ঘোষিত layer-এর important জেতে, আর layer-এর ভেতরের important layer-বিহীন important-কে হারায়। উৎসের বেলায় যে যুক্তি ছিল, এখানেও তাই: যে নিচের স্তরে আছে, সে যদি “এটা জরুরি” বলে, তাকে রক্ষা করা হয়। @layer ২০২২ সালে প্রধান তিন ব্রাউজারে প্রায় একসাথে এসেছে, এখন Baseline Widely available. Reset, theme, component আর utility CSS গুছিয়ে রাখার পুরো কৌশল দেখবেন পর্ব ৩৫-এ।
@scope — কতটা কাছে (সংক্ষেপে)
@scope (.card) { … } লিখলে ভেতরের নিয়মগুলো শুধু .card-এর ভেতরে খাটে। দুটি scope-এর নিয়ম একই element-এ মিললে, আর specificity সমান হলে, যে scope-এর মূল element সবচেয়ে কাছে, সে জেতে — এটাই সিঁড়ির পঞ্চম ধাপ। একটি .dark থিমের ভেতরে .light কার্ড, তার ভেতরে আবার .dark বক্স — এমন জায়গায় “সবচেয়ে কাছের থিম জিতবে” স্বাভাবিকভাবেই কাজ করে। @scope নতুন: Chromium আর Safari-তে আগে এসেছে, Firefox-এ এসেছে সাম্প্রতিক সময়ে — পুরোনো ব্রাউজারে নেই, তাই ব্যবহারের আগে Can I use দেখে নিন। বিস্তারিত পর্ব ৩৭-এ।
লেখার ক্রম — শেষ বিচারক
সব সমান হলে পরে আসা declaration জেতে। “পরে” মানে ব্রাউজার যে ক্রমে CSS পড়ে: <head>-এ ওপর থেকে নিচে <link> আর <style>, প্রতিটির ভেতরে ওপর থেকে নিচে, @import করা ফাইল ঠিক সেই জায়গায়। তাই একটি library-র CSS ফাইল আপনার নিজের ফাইলের পরে link করলে, সমান specificity-র লড়াইয়ে library জিতবে — নতুনদের খুব পরিচিত বিভ্রান্তি। নিজের ফাইল সবসময় শেষে রাখুন।
Inline style — শক্ত, কিন্তু অভ্যাস নয়
style="…" attribute-এ লেখা declaration সিঁড়ির দ্বিতীয় ধাপে বসে, তাই সাধারণ stylesheet-এর কোনো selector তাকে হারাতে পারে না — শুধু stylesheet-এর !important পারে। পুরোনো বইয়ে একে বলা হতো “specificity (1,0,0,0)”, অর্থাৎ id-রও ওপরে একটি চতুর্থ ঘর। এখনকার স্পেসিফিকেশন একে আলাদা ধাপ হিসেবে বর্ণনা করে, তবে ফল একই। সমস্যা হলো, inline style পুনরায় ব্যবহার করা যায় না, media query (পর্ব ৩১) বা :hover লেখা যায় না, আর বদলাতে হলে প্রতিটি HTML পাতা খুঁজতে হয়। তাই এটি মূলত JavaScript দিয়ে চলমান মান বসানোর জন্য (যেমন একটি progress bar-এর প্রস্থ), বা ইমেইলের HTML-এর মতো বিশেষ জায়গার জন্য।
৬ · Inheritance — বাবা-মা থেকে সন্তানে
এতক্ষণ দেখেছি, একটি element-এ সরাসরি লাগা কয়েকটি নিয়মের লড়াই। কিন্তু যদি কোনো নিয়মই সরাসরি না লাগে? ধরুন আপনি শুধু body { color: navy; } লিখলেন। পাতার প্রতিটি p, li, strong নীল হয়ে যায় — অথচ তাদের কারও জন্য আপনি কিছু লেখেননি। এটাই inheritance: কিছু property-র মান parent element থেকে child-এ, সেখান থেকে তার child-এ, এভাবে নিচে নামতে থাকে।
পরিবারের ভাষা আর পদবির মতো। বাবা-মা বাংলায় কথা বললে সন্তানও সাধারণত বাংলাই শেখে — আলাদা করে শেখাতে হয় না। কিন্তু বাবার উচ্চতা, বাবার জামা, বাবার বাড়ির দেয়ালের রং সন্তান “উত্তরাধিকারে” পায় না। CSS-ও তাই: লেখার রং, ফন্ট, লাইনের উচ্চতা — যা লেখার “ভাষা” — নিচে নামে। বক্সের চারপাশের জিনিস — বর্ডার, margin, padding, ব্যাকগ্রাউন্ড — নামে না।
✅ সাধারণত উত্তরাধিকারী
color, font-family, font-size, font-weight, font-style, line-height, letter-spacing, text-align, text-transform, visibility, cursor, list-style, direction. আর সব CSS variable (পর্ব ৩৩)।
❌ উত্তরাধিকারী নয়
border, margin, padding, background, width, height, display, position, opacity, box-shadow, text-decoration.
কোন property উত্তরাধিকারী, তা মুখস্থ করার দরকার নেই — MDN-এ প্রতিটি property-র পাতার নিচে “Inherited: yes/no” লেখা থাকে। সাধারণ বুদ্ধিও কাজ করে: body-তে বর্ডার দিলে পাতার প্রতিটি অনুচ্ছেদ, প্রতিটি শব্দের চারপাশে বর্ডার এলে কী বিশৃঙ্খলা হতো, ভাবুন। এবার উত্তরাধিকার কীভাবে নিচে নামে, আর কোথায় থেমে যায়, ধাপে ধাপে দেখুন:
- body
color: navyশুরু - article
.cardনিজের rule নেই - p
.noteনিজের color - strong
—p থেকে পায় - a
hrefব্রাউজারের rule
body {
color: navy;
font-family: system-ui, sans-serif;
border: 2px solid navy;
}
color: navy ← body থেকে উত্তরাধিকার font-family: system-ui ← body থেকে উত্তরাধিকার border: none ← নামেনি; নিজের প্রাথমিক মান
.note { color: crimson; }
color: crimson ← নিজের rule উত্তরাধিকারকে হারায়
font-family: system-ui ← এখনো উত্তরাধিকার
color: crimson ← p থেকে, body থেকে নয় font-weight: bold ← ব্রাউজারের stylesheet: strong { font-weight: bold }
/* ব্রাউজারের user-agent stylesheet */ a:link { color: LinkText; } (সাধারণত নীল) color: LinkText ← সরাসরি লাগা rule, যত দুর্বলই হোক, উত্তরাধিকারকে হারায়
- শুরু body-তে। body-তে তিনটি declaration: রং, ফন্ট আর বর্ডার। এর মধ্যে
colorআরfont-familyউত্তরাধিকারী property,borderনয়। - article — কোনো নিজের rule নেই। রং আর ফন্টের জন্য কোনো declaration জেতেনি (কেউ প্রতিযোগিতাতেই নেই), তাই ব্রাউজার parent body-র চূড়ান্ত মান তুলে আনে। বর্ডার উত্তরাধিকারী নয়, তাই article পায় বর্ডারের initial value —
none. - p — নিজের rule আছে।
.note { color: crimson }সরাসরি এই element-এ লাগে। উত্তরাধিকারে পাওয়া মানের কোনো specificity নেই, এটি cascade-এ প্রতিযোগীই নয় — শুধু “কেউ কিছু না বললে” ব্যবহার হয়। তাই নিজের rule থাকলে সেটাই জেতে। ফন্ট নিয়ে p-এর নিজের কিছু নেই, তাই ফন্ট এখনো body থেকে আসা। - strong — সবচেয়ে কাছের parent থেকে। উত্তরাধিকার সবসময় ঠিক ওপরের parent থেকে আসে, দাদা-দাদির কাছ থেকে নয়। তাই strong লাল, নীল নয়। আর
font-weight: boldএসেছে ব্রাউজারের নিজের stylesheet থেকে। - a — উত্তরাধিকার থেমে যায়। ব্রাউজারের ডিফল্ট stylesheet লিংকের জন্য সরাসরি রং বসায়। সবচেয়ে দুর্বল উৎসের rule হলেও এটি সরাসরি লাগা rule, আর সরাসরি লাগা যেকোনো rule উত্তরাধিকারকে হারায় — এমনকি
* { color: … }-ও। এজন্যই “body-তে সাদা রং দিলাম, কিন্তু লিংক নীলই থাকল” — খুব পরিচিত অভিযোগ।
এবার নিজে দেখুন। নিচের কার্ডে রং, ফন্ট আর বর্ডার শুধু .card-এ দেওয়া আছে:
<style>
.card {
color: #1e3a8a;
font-family: Georgia, serif;
font-size: 18px;
border: 2px solid #1e3a8a;
padding: 12px;
}
</style>
<div class="card">
<p>এই লেখা রং আর ফন্ট পেয়েছে উত্তরাধিকারে — বর্ডার পায়নি।</p>
<a href="#more">লিংকের রং কিন্তু আলাদা</a>
<p><button type="button">বাটনের ফন্টও আলাদা</button></p>
</div>অনুচ্ছেদের লেখা গাঢ় নীল আর Georgia ফন্টে, কিন্তু অনুচ্ছেদের চারপাশে কোনো বর্ডার নেই — বর্ডার শুধু কার্ডের চারপাশে। লিংকটি ব্রাউজারের নিজের নীলে (আর সাধারণত Georgia-তেই, কারণ লিংকের ফন্ট ব্রাউজার বদলায় না)। বাটনের লেখা ছোট আর অন্য ফন্টে, কারণ ব্রাউজার ফর্ম কন্ট্রোলে নিজের ফন্ট বসায়। চেষ্টা করুন: <style>-এর ভেতরে যোগ করুন button { font: inherit; } আর a { color: inherit; } — দুটোই কার্ডের সাথে মিলে যাবে। পেশাদার CSS reset-এ প্রথম লাইনটি প্রায় সবসময় থাকে। তারপর p { border: inherit; } লিখে দেখুন — উত্তরাধিকারী না হলেও জোর করে আনা যায়।
text-decoration (নিচের দাগ) উত্তরাধিকারী নয়, তবু parent-এ দিলে child-এর লেখার নিচেও দাগ দেখা যায়। কারণ দাগটি parent-ই তার পুরো লেখার ওপর দিয়ে টানে — child-এর নিজের text-decoration তখনো none. তাই child-এ text-decoration: none লিখে সেই দাগ মোছা যায় না। নতুনদের কাছে এটা “CSS কাজ করছে না” বলে মনে হয়; আসলে দাগটা কার, সেটাই প্রশ্ন।
৭ · inherit, initial, unset, revert — নিয়ন্ত্রণ আপনার হাতে
CSS-এ কয়েকটি বিশেষ মান আছে যা যেকোনো property-তে লেখা যায়। এদের বলে CSS-wide keyword. এরা কোনো রং বা মাপ বলে না, বলে “মানটা কোথা থেকে আনব”:
| Keyword | মানে | কোথায় কাজের |
|---|---|---|
inherit | parent-এর চূড়ান্ত মানটাই নেওয়া — property উত্তরাধিকারী না হলেও | button { font: inherit; } |
initial | স্পেসিফিকেশনে লেখা property-র প্রাথমিক মান | সাবধানে! display-এর initial হলো inline, block নয় |
unset | উত্তরাধিকারী property হলে inherit, না হলে initial | all: unset দিয়ে একটি element থেকে সব স্টাইল তুলে ফেলা |
revert | author-এর সব নিয়ম বাদ দিয়ে ব্রাউজারের (বা user-এর) ডিফল্টে ফিরে যাওয়া | কোনো reset-এর পর একটি জায়গায় ব্রাউজারের আসল চেহারা ফেরানো |
revert-layer | এই layer-এর নিয়ম বাদ দিয়ে আগের layer-এর মানে ফিরে যাওয়া | layer দিয়ে গোছানো CSS-এ (পর্ব ৩৫) |
সবচেয়ে বেশি গুলিয়ে যায় initial আর revert. “Initial” শুনে মনে হয় “শুরুর অবস্থা, যেমন CSS ছাড়া দেখায়”। কিন্তু CSS ছাড়া পাতার যে চেহারা, সেটা আসে ব্রাউজারের stylesheet থেকে — আর initial সেটাকেও ফেলে দেয়, যায় স্পেসিফিকেশনের একদম কাঁচা মানে। revert ফেরে ব্রাউজারের ডিফল্টে। লিংকে প্রয়োগ করলে পার্থক্য চোখে পড়ে:
<style>
.box { color: crimson; border: 2px dashed crimson; padding: 8px; }
.box a { color: green; display: block; margin: 4px 0; }
.box .k1 { color: inherit; }
.box .k2 { color: initial; }
.box .k3 { color: unset; }
.box .k4 { color: revert; }
</style>
<div class="box">
<a href="#t0">কোনো keyword নেই — সবুজ</a>
<a href="#t1" class="k1">inherit — parent-এর লাল</a>
<a href="#t2" class="k2">initial — color-এর প্রাথমিক মান</a>
<a href="#t3" class="k3">unset — color উত্তরাধিকারী, তাই inherit</a>
<a href="#t4" class="k4">revert — ব্রাউজারের লিংকের রং</a>
</div>প্রথমটি সবুজ, দ্বিতীয়টি লাল, তৃতীয়টি কালো (color-এর প্রাথমিক মান CanvasText — সাদা পটভূমিতে সাধারণত কালো), চতুর্থটি লাল, আর শেষটি ব্রাউজারের লিংকের নীল। unset আর revert একই মনে হতে পারে, কিন্তু এখানে পার্থক্য স্পষ্ট: unset উত্তরাধিকার নিল, revert ফিরে গেল ব্রাউজারের লিংক-রঙে। খেয়াল করুন, selector-গুলো .box .k1 লেখা — শুধু .k1 (0,1,0) হলে .box a (0,1,1)-এর কাছে হেরে যেত। চেষ্টা করুন: .box .k2-এ display: initial; যোগ করুন — লিংকটি আর আলাদা লাইনে থাকবে না, কারণ display-এর initial হলো inline.
আরও গভীরে: স্পেসিফিকেশন একটি মানকে কয়েক ধাপে পাকা করে। Specified value হলো cascade-এ জেতা (বা উত্তরাধিকারে পাওয়া, বা initial) মান, যেমন 1.25em. Computed value-তে আপেক্ষিক মান যতটা সম্ভব পরম করা হয় — 1.25em হয়ে যায় 20px, আর উত্তরাধিকারে child পায় এই computed মান। Used value আসে লেআউটের পর — width: 50% তখনই আসল পিক্সেলে রূপ নেয়, যখন parent-এর চওড়া জানা যায়। শেষে actual value, যা পর্দার পিক্সেলের সাথে মিলিয়ে গোল করা। JavaScript-এর getComputedStyle() আসলে “resolved value” দেয় — রঙের মতো property-তে computed, আর width-এর মতো লেআউট-নির্ভর property-তে used মান।
৮ · !important-এর দুর্গন্ধ আর DevTools দিয়ে গোয়েন্দাগিরি
কেন !important একটি “smell”
প্রোগ্রামিংয়ে “code smell” বলে একটি কথা আছে — এমন চিহ্ন, যা নিজে ভুল নয়, কিন্তু দেখলেই সন্দেহ হয় গভীরে কোথাও সমস্যা আছে। রান্নাঘর থেকে পোড়া গন্ধ এলে আগুন নাও লাগতে পারে, কিন্তু উঠে দেখতে হয়। CSS-এ !important ঠিক তেমন। কেউ যখন লেখেন color: red !important, প্রায়ই আসল কথাটা হলো “কেন আমার নিয়ম হারছে, বুঝতে পারছি না, তাই জোর খাটালাম”। এতে এখনকার সমস্যা চাপা পড়ে, কিন্তু তিনটি নতুন সমস্যা তৈরি হয়:
- পরে বদলানো কঠিন: ওই রং কোনো এক পাতায় বদলাতে হলে আরেকটি
!importantলাগবে, আরও ভারী selector-সহ। - উদ্দেশ্য হারিয়ে যায়: ছয় মাস পর কেউ বুঝবে না কোনটি সত্যিই জরুরি ছিল, কোনটি তাড়াহুড়োর জোড়াতালি।
- পাঠকের ক্ষতি হতে পারে: লেখার মাপ, লাইনের ফাঁক বা রঙে author
!importantথাকলে, যাঁরা নিজের প্রয়োজনে extension বা user CSS দিয়ে এগুলো বদলান, তাঁদের সাধারণ নিয়ম হেরে যায়। WCAG 2.2-এর “Text Spacing” নিয়ম (১.৪.১২) চায় পাঠক লাইন আর অক্ষরের ফাঁক বাড়ালেও লেখা যেন ভেঙে না যায়।
তবে !important নিষিদ্ধ নয় — কয়েকটি জায়গায় এটি একদম সঠিক হাতিয়ার:
- Utility class:
.hidden { display: none !important; }— যে class-এর একমাত্র কাজ একটি জিনিস নিশ্চিত করা, সেখানে এটি উদ্দেশ্যই বলে দেয়। Bootstrap-এর মতো framework তাদের utility class-এ এভাবেই!importantব্যবহার করে (পর্ব ৪৬, ৫১)। - পাঠকের নিজের stylesheet: user stylesheet-এ
!importantলেখা পাঠকের অধিকার — এর জন্যই ক্রমটা উল্টানো। - যা বদলানোর উপায় নেই: কোনো third-party widget যদি HTML-এ inline style বসায়, আর সেটা আপনি বদলাতে না পারেন, stylesheet থেকে শুধু
!important-ই পারে। - Reduced motion-এর নিরাপত্তা জাল:
@media (prefers-reduced-motion: reduce)-এর ভেতরে সব animation প্রায় শূন্য করে দেওয়ার পরিচিত কোডে!importantথাকে, যাতে কোনো component-ই বাদ না পড়ে (পর্ব ৪৫)।
!important লেখার আগে নিজেকে জিজ্ঞেস করুন: “আমার নিয়ম কোন ধাপে হারছে?” উত্তর specificity হলে selector হালকা করুন বা প্রতিপক্ষকে :where()-এ নিন। উত্তর লেখার ক্রম হলে ফাইলের ক্রম ঠিক করুন। উত্তর layer হলে layer-এর ক্রম ঠিক করুন। এর কোনোটিই না হলে — এবং কারণটা নথিভুক্ত করে — তবেই !important.
DevTools-এর Styles আর Computed ট্যাব
“আমার CSS কাজ করছে না” — এই সমস্যার বেশিরভাগ উত্তর DevTools-এ এক মিনিটে পাওয়া যায় (পর্ব ২-এ DevTools খোলা শিখেছেন; পুরো debugging-এর পর্ব ৪৭)। element-এর ওপর ডান-ক্লিক করে Inspect চাপুন, তারপর Elements প্যানেলের পাশে দেখুন:
Styles
element.style { ← inline style, সবার ওপরে
}
#offer { style.css:12
color: navy;
}
.price { style.css:4
color: green; ← কাটা দাগ: হেরেছে
font-weight: bold;
}
p { user agent stylesheet
display: block;
margin-block-start: 1em;
}
Inherited from div.card
.card { style.css:1
font-family: Georgia, serif;
border: 2px solid; ← ফিকে: উত্তরাধিকারী নয়
}
- ক্রম: Styles প্যানেল rule-গুলো জয়ের ক্রমে সাজায় — ওপরেরটি সবচেয়ে শক্ত। একদম ওপরে
element.styleমানে inline style. - কাটা দাগ (strikethrough): যে declaration হেরেছে, তার ওপর দাগ। কেন হারল বুঝতে, একই property ওপরের কোন rule-এ আছে খুঁজুন। পাশে হলুদ সতর্ক চিহ্নসহ কাটা দাগ মানে ভিন্ন সমস্যা — property-র নাম বা মান ভুল, ব্রাউজার বুঝতেই পারেনি।
- “Inherited from …”: নিচের অংশে parent-দের rule, যেখান থেকে উত্তরাধিকার আসছে। উত্তরাধিকারী নয় এমন property সেখানে ফিকে দেখায়।
- Specificity দেখা: Chrome আর Edge-এর নতুন সংস্করণে selector-এর ওপর মাউস রাখলে তার specificity
(a, b, c)আকারে দেখায়; layer থাকলে rule-এর ওপরে layer-এর নামও দেখায়। - Computed ট্যাব: element-এর প্রতিটি property-র চূড়ান্ত মান। একটি property-র পাশের তীর খুললে দেখায় কোন কোন declaration লড়েছিল আর কে জিতল, কোন ফাইলের কোন লাইনে। “আসলে কী মান বসেছে” প্রশ্নের সরাসরি উত্তর এখানে।
DevTools যে হিসাব দেখায়, তার কিছুটা আমরা নিজেও করতে পারি। নিচের স্ক্রিপ্টে একটি ছোট specificity-গণক আছে — সাধারণ selector-এর জন্য (জটিল, নেস্টেড বন্ধনী সে বোঝে না)। আর শেষে getComputedStyle() দিয়ে ব্রাউজারের কাছ থেকে চূড়ান্ত মান পড়া হচ্ছে:
function cmp(p, q) { return p[0] - q[0] || p[1] - q[1] || p[2] - q[2]; }
function spec(sel) {
let a = 0, b = 0, c = 0;
let s = sel.replace(/:where\([^)]*\)/g, ' '); // ওজন শূন্য
s = s.replace(/:(?:is|not|has)\(([^)]*)\)/g, (m, inner) => {
const best = inner.split(',').map(x => spec(x.trim())).sort(cmp).pop();
a += best[0]; b += best[1]; c += best[2]; return ' '; // সবচেয়ে ভারীটি
});
s = s.replace(/\[[^\]]*\]/g, () => { b++; return ' '; }); // [attr]
s = s.replace(/::[\w-]+/g, () => { c++; return ' '; }); // ::before
s = s.replace(/#[\w-]+/g, () => { a++; return ' '; }); // #id
s = s.replace(/\.[\w-]+/g, () => { b++; return ' '; }); // .class
s = s.replace(/:[\w-]+(\([^)]*\))?/g, () => { b++; return ' '; }); // :hover
s.replace(/[a-z][\w-]*/gi, () => { c++; return ''; }); // type
return [a, b, c];
}
const sels = ['p', 'ul li.sale', '#cart .item:hover', 'li:nth-child(2n+1)',
':is(#main, .box) p', ':where(#main, .box) p', '.card:not(.sold, #x) > *'];
for (const x of sels) console.log(x, '->', '(' + spec(x).join(', ') + ')');
const cs = getComputedStyle(document.querySelector('#msg'));
console.log('color:', cs.color, '| font-size:', cs.fontSize);প্রথম সাতটি লাইনে প্রতিটি selector-এর পাশে তার specificity — যেমন #cart .item:hover -> (1, 2, 0), :where(#main, .box) p -> (0, 0, 1). শেষ লাইনে আসে color: rgb(128, 0, 128) | font-size: 20px. রং বেগুনি, কারণ #msg (1,0,0) জিতেছে .note-এর বিপক্ষে। আর font-size 1.25em লেখা থাকলেও ব্রাউজার দিয়েছে পরম মান 20px (16 × 1.25) — এটাই computed value. চেষ্টা করুন: sels তালিকায় নিজের একটি selector যোগ করুন, যেমন 'nav a[aria-current]::after', আগে হাতে হিসাব করে তারপর মিলিয়ে দেখুন। তারপর ভাবুন: পাতার CSS-এ #msg-এর rule না থাকলে রং কী হতো? (উত্তর: .note-এর teal, অর্থাৎ rgb(0, 128, 128))
৯ · AI-এর যুগে cascade বোঝার মূল্য
AI টুলকে “বাটনের রং বদলে দাও” বললে সে প্রায় সবসময়ই এমন CSS দেয়, যা তার কল্পনার একটি খালি পাতায় কাজ করে। কিন্তু আপনার আসল সাইটে আছে Bootstrap বা অন্য কোনো library, আগের ডেভেলপারের লেখা ফাইল, CMS-এর থিম। AI সেই cascade দেখতে পায় না। ফলে তার কোড “কাজ করছে না”, আর পরের প্রম্পটে সে সমাধান দেয় সবচেয়ে সহজটা — !important.
AI সাধারণত যেসব cascade-ভুল করে
| AI যা করে | সমস্যা | যা করা উচিত |
|---|---|---|
“কাজ না করলে” প্রতিটি লাইনে !important | important-যুদ্ধ শুরু, পরে বদলানো কঠিন | DevTools-এ দেখুন কোন ধাপে হারছে |
body div.container ul li a.link-এর মতো লম্বা selector | অকারণ ভারী specificity, HTML বদলালেই ভাঙে | একটি অর্থবহ class, যেমন .nav-link |
স্টাইলের জন্য #id selector | (1,0,0) — পরে class দিয়ে বদলানো যায় না | id রাখুন লিংক-লক্ষ্য আর JavaScript-এর জন্য |
| “id ১০০ পয়েন্ট, class ১০ পয়েন্ট” ব্যাখ্যা | ভুল ধারণা — ঘর উপচে পড়ে না | (a, b, c) বাঁ দিক থেকে তুলনা |
:where() আর :is()-কে একই বলা | ওজনের বিশাল পার্থক্য উপেক্ষা | বেস স্টাইলে :where() |
HTML-এ ঢালাও inline style="…" | পুনর্ব্যবহার, media query, hover — কিছুই হয় না | class আর stylesheet |
AI-কে সঠিক প্রশ্ন করতে হলে তাকে cascade-এর তথ্য দিন। DevTools-এর Styles প্যানেল থেকে element-টির সব rule কপি করে দিন, আর পরিষ্কার শর্ত দিন:
AI-এর দেওয়া CSS হাতে পেলে — যাচাইয়ের চেকলিস্ট
পরীক্ষা ও ইন্টারভিউতে — বিশ্ববিদ্যালয়, চাকরি বা ফ্রন্ট-এন্ড ইন্টারভিউর পরীক্ষায় এ ধরনের প্রশ্ন প্রায়ই আসে:
- CSS-এ “cascading” মানে কী? — একই element-এ বিরোধী declaration-এর মধ্যে উৎস ও গুরুত্ব, layer, specificity আর ক্রম দেখে একটি বিজয়ী বেছে নেওয়ার নিয়ম।
#nav .item a-এর specificity কত? —(1, 1, 1): একটি id, একটি class, একটি type.- Inline style, id আর
!important— কে কাকে হারায়? — stylesheet-এর!important> inline style > id selector > class > type. :is()আর:where()-এর পার্থক্য? — একই element মেলায়; :is() নেয় তালিকার সবচেয়ে ভারী selector-এর ওজন, :where()-এর ওজন সবসময় শূন্য।- Inheritance আর cascade কি একই? — না; cascade সরাসরি লাগা declaration-এর লড়াই মেটায়, কোনো declaration না থাকলে উত্তরাধিকারী property parent-এর computed মান নেয়।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলো আপনাকে নিয়ম-মুখস্থকারী থেকে cascade-চিন্তক বানাবে।
প্র ০১CSS-এর নামেই “Cascading” কেন? স্টাইলের এমন “মিলিয়ে নেওয়ার” নিয়ম না রেখে সহজ কিছু করা যেত না?
১৯৯০-এর দশকের শুরুতে ওয়েবে চেহারা ঠিক করার কোনো মান-নিয়ম ছিল না। কিছু ব্রাউজার পাঠককে নিজের ফন্ট আর রং বেছে নিতে দিত, আর লেখকেরা চাইতেন পত্রিকার মতো নিখুঁত নিয়ন্ত্রণ। Netscape নিজের মতো করে নতুন ট্যাগ বানাচ্ছিল (<font>, <center>) — চেহারা মিশে যাচ্ছিল HTML-এর অর্থের সাথে।
১৯৯৪ সালে Håkon Wium Lie-র প্রস্তাবের সবচেয়ে মৌলিক ভাবনা ছিল: পাতার চেহারা একজনের একক সিদ্ধান্ত নয়, একটি দর-কষাকষি। লেখক চান তাঁর নকশা, পাঠক চান নিজের পড়ার সুবিধা, ব্রাউজার দেয় একটি যুক্তিসঙ্গত ডিফল্ট। এই তিন পক্ষের ইচ্ছা ধাপে ধাপে মিলিয়ে একটি ফল দেওয়ার নিয়মই cascade. সেই সময়ের অন্য প্রস্তাবগুলোর বেশিরভাগ ধরে নিত লেখকের কথাই শেষ কথা।
প্রতিযোগীও ছিল। ১৯৯৬ সালে Netscape প্রস্তাব করে JavaScript Style Sheets (JSSS), যেখানে স্টাইল লেখা হতো JavaScript-এর মতো করে; Netscape 4 সেটা চালুও করেছিল। কিন্তু W3C এগিয়ে নেয় CSS-কে, আর ১৯৯৬ সালের ডিসেম্বরে CSS1 মান-নিয়ম হয়। JSSS হারিয়ে যায়। CSS-এর ঘোষণামূলক (declarative) ধরন — “এটা কী রকম দেখাবে” বলা, “কীভাবে আঁকবে” নয় — ব্রাউজারকে নিজের মতো করে দ্রুত আঁকার স্বাধীনতা দিয়েছিল।
“সহজ” বিকল্প, যেমন “সবসময় শেষ নিয়মটাই জিতবে”, বড় সাইটে অচল হতো: একটি নতুন ফাইল যোগ করলেই আগের সব নকশা ওলটপালট। আবার “শুধু লেখকের কথা” মানলে চোখে কম দেখেন এমন পাঠক কখনো লেখা বড় করতে পারতেন না। Specificity এল একটি সহজ স্বজ্ঞা থেকে — যে নিয়ম যত নির্দিষ্টভাবে একটি element-এর কথা বলে, সে সাধারণত তত বেশি ইচ্ছাকৃত।
তিরিশ বছর পরেও মূল কাঠামো একই, শুধু নতুন ধাপ যোগ হয়েছে — layer, scope. এই নকশা আজও টিকে আছে, কারণ এটি একটি প্রকৃত সমস্যা সমাধান করে: অনেক উৎস, অনেক মানুষ, একটি পর্দা।
মূল উপলব্ধি: cascade কোনো দুর্ঘটনা বা জটিলতার জন্য জটিলতা নয় — এটি লেখক, পাঠক আর ব্রাউজারের মধ্যে ক্ষমতা ভাগাভাগির একটি ইচ্ছাকৃত চুক্তি। চুক্তিটা বুঝলে নিয়মগুলো আর মুখস্থ করতে হয় না।
প্র ০২Specificity কেন পয়েন্ট যোগ করার হিসাব নয়? ঘরগুলো “উপচে” পড়লে কী সমস্যা হতো — এর কোনো বাস্তব নজির আছে?
পয়েন্ট-পদ্ধতিতে (id ১০০, class ১০, type ১) একটি গোপন অনুমান আছে: কোনো selector-এ ১০টির বেশি class বা type থাকবে না। দশের বেশি হলেই এক ঘর পরের ঘরে “উপচে” পড়ে, আর হিসাব ভুল হয়। ১১টি class = ১১০ পয়েন্ট, যা একটি id-র ১০০ পয়েন্টকে হারাত। স্পেসিফিকেশন শুরু থেকেই এটা নিষেধ করে: CSS2-এর ভাষায় সংখ্যাগুলো এমন একটি সংখ্যা-পদ্ধতিতে জোড়া হয় যার “ভিত্তি অনেক বড়” — অর্থাৎ ঘর কখনো উপচে পড়ে না।
কেন এটা জরুরি? একটি id মানে “পাতায় একটিমাত্র element”. এর চেয়ে নির্দিষ্ট কিছু হয় না। যতগুলো class-ই জুড়ুন, তারা একটি দলকে বর্ণনা করে; একটি নির্দিষ্ট element-এর সমান হয় না। তাই তুলনাটা অভিধানের মতো — প্রথম ঘরেই ফয়সালা।
মজার ব্যাপার হলো, একসময় কিছু ব্রাউজার নিজেই এই নিয়ম ভেঙেছিল। ২০১২ সালের দিকে ডেভেলপাররা আবিষ্কার করেন, তখনকার Firefox (এবং আরও কিছু ব্রাউজার) প্রতিটি ঘর একটি মাত্র byte-এ (৮ bit) রাখত। ফলে একটি selector-এ ২৫৬টি class জুড়লে ঘরটি উপচে গিয়ে id-এর ঘরে গড়িয়ে পড়ত — আর ২৫৬টি class একটি id-কে হারিয়ে দিত! বাস্তবে কেউ ২৫৬টি class লেখে না, কিন্তু ঘটনাটি দেখায় যে ঘরগুলো আসলে আলাদা কাউন্টার, আর মেমরি বাঁচাতে গিয়ে ইঞ্জিনিয়ারদের একটি সীমা মানতে হয়েছিল। পরে ব্রাউজারগুলো বড় কাউন্টার ব্যবহার করে সমস্যাটি দূর করে।
আরও একটি গভীর কারণ আছে। পয়েন্ট-পদ্ধতি শেখায় “আরও class জুড়ে জিতে যাও” — যা ঠিক সেই অভ্যাস, যা বড় প্রজেক্টে specificity-যুদ্ধ শুরু করে। (a, b, c) পদ্ধতি সৎভাবে দেখায়, id একবার ঢুকলে class দিয়ে আর ফেরা যায় না। এজন্য আধুনিক CSS architecture-এ (পর্ব ৪৬) স্টাইলের জন্য id এড়ানো হয়, আর বেশিরভাগ selector এক class-এর, (0,1,0).
মূল উপলব্ধি: একটি ভুল মানসিক মডেল ছোট উদাহরণে ঠিক উত্তর দিয়ে নিজেকে লুকিয়ে রাখে। specificity-কে তিনটি আলাদা ঘর হিসেবে দেখুন — তাহলে সীমার কাছে গিয়েও ভুল করবেন না।
প্র ০৩!important-এ উৎসের ক্রম উল্টে যায় কেন? CSS1 থেকে CSS2-তে এই নিয়ম বদলানোর পেছনে কী ভাবনা ছিল?
১৯৯৬ সালের CSS1-এ !important ছিল, কিন্তু নিয়মটা ছিল সোজা: author-এর important user-এর important-কে হারাত। অর্থাৎ শেষ কথা লেখকের। কয়েক বছরের মধ্যেই স্পষ্ট হলো, এতে একদল মানুষ বিপদে পড়েন — যাঁরা চোখে কম দেখেন, রং আলাদা করতে পারেন না, বা ডিসলেক্সিয়ার কারণে নির্দিষ্ট ফন্ট আর ফাঁক ছাড়া পড়তে পারেন না। তাঁরা নিজের user stylesheet-এ যা-ই লিখুন, লেখকের একটি important সব বাতিল করে দিত।
১৯৯৮ সালের CSS2 নিয়মটি উল্টে দেয়: user-এর important এখন author-এর important-এর ওপরে। যুক্তিটা হলো, সাধারণ পছন্দে লেখক জিতবেন — সাইটটা তাঁর, নকশা তাঁর। কিন্তু পাঠক যখন “important” বলেন, তখন সেটা সাধারণত প্রয়োজন, শখ নয়, আর প্রয়োজন নকশার চেয়ে বড়। ব্রাউজারের নিজের important সবার ওপরে, কারণ কিছু জিনিস (যেমন কিছু নিরাপত্তা-সংক্রান্ত চেহারা) কাউকেই বদলাতে দেওয়া চলে না।
একই যুক্তি পরে layer-এও এসেছে: আগে ঘোষিত (নিচের) layer-এর important পরের layer-এর important-কে হারায়। একটি reset বা base layer যদি বলে “এটা জরুরি”, পরের component layer তা ভাঙতে পারবে না। নিচের স্তরকে “জরুরি” বলার অধিকার দিয়ে রক্ষা করা — পুরো নকশায় একটি সামঞ্জস্যপূর্ণ নীতি।
আজকের দুনিয়ায় user stylesheet শুধু ব্রাউজার সেটিংয়ে সীমাবদ্ধ নয়। Windows-এর contrast theme চালু করলে ব্রাউজার forced colors মোডে যায় — পাতার রং বাদ দিয়ে ব্যবহারকারীর বেছে নেওয়া অল্প কয়েকটি রং বসায়, author-এর CSS যা-ই বলুক। অনেক পাঠক extension দিয়ে লাইনের ফাঁক বা ফন্ট বদলান। WCAG-এর Text Spacing নিয়ম (১.৪.১২) ঠিক এই পাঠকদের কথা ভেবে লেখা।
মূল উপলব্ধি: cascade-এ ক্ষমতার ক্রম আসলে নৈতিক একটি সিদ্ধান্ত — সাধারণ অবস্থায় নির্মাতা, প্রয়োজনের মুহূর্তে ব্যবহারকারী। ভালো ওয়েব ডেভেলপার তাই নিজের !important কম রাখেন, যাতে পাঠকের নিয়ন্ত্রণ সহজে কাজ করে।
প্র ০৪Specificity তো ছিলই — তাহলে @layer আনার দরকার পড়ল কেন? বড় প্রজেক্টে কী সমস্যা হচ্ছিল?
Specificity ছোট সাইটে চমৎকার, কিন্তু বড় প্রজেক্টে এর একটি মৌলিক দুর্বলতা আছে: selector-এর ওজন দুটি আলাদা প্রশ্নের উত্তর একসাথে দেয়। একটি প্রশ্ন “কোন element-কে ধরব?”, আরেকটি “এই নিয়ম কতটা গুরুত্বপূর্ণ?” কোনো কম্পোনেন্টের ভেতরের element ঠিকভাবে ধরতে একটু লম্বা selector লাগল — আর অনিচ্ছায় সেটি ভারীও হয়ে গেল। পরে একটি সাধারণ utility class দিয়ে সেটা বদলাতে গেলেন, পারলেন না।
বছরের পর বছর মানুষ নানা কৌশলে এই সমস্যা সামলেছেন। BEM-এর মতো নামকরণ-পদ্ধতি (পর্ব ৪৬) প্রায় সব selector-কে এক class-এ, (0,1,0)-এ নামিয়ে আনে, যাতে শুধু লেখার ক্রম দিয়ে বিচার হয়। কেউ ফাইলের ক্রম কঠোরভাবে বেঁধে দিতেন — settings, reset, elements, components, utilities. Utility framework-গুলো ক্রম ঠিক রাখতে ভরসা করত !important বা সাবধানে সাজানো ফাইলে। কিন্তু সবকিছুই ছিল মানুষের শৃঙ্খলার ওপর নির্ভরশীল। একটি third-party ফাইল ভুল জায়গায় link হলেই সব ভেঙে যেত।
Cascade Layers এই দুই প্রশ্নকে আলাদা করে দিল। “কতটা গুরুত্বপূর্ণ” এখন বলা হয় layer-এর ক্রম দিয়ে, স্পষ্টভাবে, এক লাইনে: @layer reset, base, components, utilities;. “কাকে ধরব” বলা হয় selector দিয়ে, আর তার specificity শুধু নিজের layer-এর ভেতরে গোনা হয়। একটি library-র পুরো CSS এক লাইনে নিচের তাকে রাখা যায়: @import url(lib.css) layer(lib); — এরপর আপনার একটি সাধারণ class-ও তাকে হারাবে। CSS Cascade Level 5 স্পেসিফিকেশনে এর নকশায় বড় ভূমিকা রাখেন Miriam Suzanne সহ সম্পাদকেরা, আর ২০২২ সালে প্রধান ব্রাউজারগুলো প্রায় একসাথে এটি চালু করে।
এর প্রভাব এখন বড় framework-এও স্পষ্ট: Tailwind CSS-এর version 4 নিজের ভেতরের CSS সাজায় আসল cascade layer দিয়ে। নতুন সাইট শুরু করলে প্রথম দিন থেকেই layer-এর একটি ক্রম ঠিক করে রাখা এখন ভালো অভ্যাস।
মূল উপলব্ধি: ভালো নকশায় একটি যন্ত্র একটি কাজ করে। specificity-কে “কাকে ধরব” আর layer-কে “কে আগে” — এভাবে আলাদা করলে CSS বড় হলেও অনুমানযোগ্য থাকে।
প্র ০৫সব property কেন উত্তরাধিকারী নয়? আর উত্তরাধিকারে child আসলে কোন মানটা পায় — লেখা মান, না হিসাব করা মান?
CSS-এর প্রতিটি property-র স্পেসিফিকেশনে একটি ঘর আছে: “Inherited: yes” বা “no”. এই সিদ্ধান্ত নেওয়া হয়েছে একটি সহজ প্রশ্ন দিয়ে — এই property কি লেখার বৈশিষ্ট্য, না বক্সের? লেখার রং, ফন্ট, ভাষার দিক, লাইনের উচ্চতা একটি অনুচ্ছেদের ভেতরের প্রতিটি শব্দের জন্য একই হওয়াই স্বাভাবিক, তাই নিচে নামে। বর্ডার, margin, ব্যাকগ্রাউন্ড একটি বক্সের নিজস্ব; নিচে নামলে প্রতিটি নেস্টেড বক্সে বর্ডারের পর বর্ডার, margin-এর ওপর margin জমত — পাতা অচল হয়ে যেত।
দ্বিতীয় প্রশ্নটি আরও সূক্ষ্ম, আর বাস্তবে অনেক বাগের উৎস। child পায় parent-এর computed value, লেখা মান নয়। একটি ক্লাসিক উদাহরণ line-height:
body { font-size: 16px; line-height: 1.5em; }— computed মান হয়24px. এখন একটিh1-এর font-size 40px হলেও সে উত্তরাধিকারে পায় 24px লাইন-উচ্চতা — বড় শিরোনামের লাইনগুলো একটির ওপর আরেকটি চেপে বসে।body { line-height: 1.5; }— একক ছাড়া সংখ্যা। এর computed মান সংখ্যাটিই, তাই প্রতিটি child নিজের font-size দিয়ে নতুন করে গুণ করে: h1-এ 60px, ছোট লেখায় 21px.
এজন্যই অভিজ্ঞ ডেভেলপাররা line-height-এ একক ছাড়া সংখ্যা লেখেন (পর্ব ১৪-এ বাংলা লেখার জন্য যেটা দেখেছেন)। একই কারণে font-size: 1.2em নেস্টেড তালিকায় স্তরে স্তরে বড় হতে থাকে — প্রতিটি স্তর আগের স্তরের computed মানকে আবার গুণ করে। এর সমাধান rem, যা সবসময় মূল element-এর মাপ ধরে (পর্ব ২০)।
আধুনিক CSS-এ উত্তরাধিকার আরও শক্তিশালী হয়েছে। CSS variable (custom property) ডিফল্টভাবে উত্তরাধিকারী — একটি .dark বক্সে --bg বদলালে তার ভেতরের সব কিছু নতুন মান পায়, পুরো থিম ব্যবস্থা এর ওপর দাঁড়িয়ে (পর্ব ৩৩, ৩৬)। আর @property দিয়ে চাইলে একটি variable-কে উত্তরাধিকারী নয় বলেও ঘোষণা করা যায় (পর্ব ৩৭)।
মূল উপলব্ধি: উত্তরাধিকার “নাম” নয়, “হিসাব করা মান” পাঠায়। কোনো মান অদ্ভুতভাবে বাড়ছে বা কমছে দেখলে প্রশ্ন করুন — parent-এ এর computed মান কী ছিল?
অনুশীলন
বেশিরভাগ কাজে কোড লেখার দরকার নেই — হিসাব করা, পর্যবেক্ষণ আর ভাবাই আসল কাজ।
-
Specificity র্যাঙ্কিং: নিচের চারটি selector একই
<a>-কে ধরে। প্রতিটির (a, b, c) বের করুন আর শক্তির ক্রমে সাজান — (ক)nav a(খ).menu .link(গ)#top a:hover(ঘ):where(#top) .menu a(ক)
(0,0,2)— দুটি type. (খ)(0,2,0)— দুটি class. (গ)(1,1,1)— id, pseudo-class, type. (ঘ)(0,1,1)—:where(#top)শূন্য, বাকি একটি class আর একটি type.ক্রম, শক্ত থেকে দুর্বল: গ > খ > ঘ > ক. খেয়াল করুন, (ঘ)-তে id লেখা থাকলেও সে (খ)-এর কাছে হারে। আর (গ) শুধু মাউস রাখার সময় মেলে — অন্য সময় সে প্রতিযোগিতাতেই থাকে না, তখন বিজয়ী (খ)।
-
DevTools-এ কাটা দাগ খুঁজুন: যেকোনো একটি সংবাদ বা কেনাকাটার সাইট খুলে একটি বাটন বা শিরোনাম Inspect করুন। Styles প্যানেলে অন্তত একটি কাটা দাগ দেওয়া declaration খুঁজে বের করুন, আর বলুন সেটি cascade-এর কোন ধাপে হেরেছে।
সাধারণত যা দেখবেন: ব্রাউজারের user agent stylesheet-এর
marginবাfont-sizeকাটা — হেরেছে ধাপ ১-এ (author > user-agent). কোনো framework-এর.btn-এর রং কাটা, কারণ সাইটের নিজের.btn-primaryপরে লেখা — ধাপ ৬, লেখার ক্রম। কখনো.card a-এর রং কাটা, কারণ ওপরে.card .title aআছে — ধাপ ৪, specificity. Selector-এর ওপর মাউস রেখে specificity মিলিয়ে নিন। কোনো declaration-এর পাশে হলুদ সতর্ক চিহ্ন পেলে বুঝবেন, সেটি হারেনি — ব্রাউজার বুঝতেই পারেনি (ভুল বানান বা ভুল মান)। -
!important ছাড়া মেরামত: একটি library-র CSS-এ আছে
:is(#app, .ui) .btn { background: gray; }. আপনার.btn-buy { background: seagreen; }কাজ করছে না। library-র selector না বদলে, আর!importantছাড়া, কীভাবে আপনার রং জেতাবেন?library-র selector-এর ওজন
(1,1,0)—:is()তালিকার#app-এর ওজন নিয়েছে। selector না বদলে সবচেয়ে পরিষ্কার সমাধান: library-কে একটি layer-এ রাখুন। layer-এর ধাপ specificity-র আগে, আর layer-এর বাইরের আপনার CSS সব layer-কে হারায়। বাস্তবে ফাইল আনার সময়ই লেখা যায়:@import url(library.css) layer(library);. নিচে সরাসরি দেখুন:@layer library { :is(#app, .ui) .btn { background: gray; color: white; padding: 10px 18px; border: 0; border-radius: 8px; font-size: 18px; } } /* আপনার CSS — কোনো layer-এ নেই */ .btn-buy { background: seagreen; }বাটনটি সবুজ, আর library-র বাকি স্টাইল (সাদা লেখা, padding, গোল কোণা) ঠিকই আছে।
@layer library {আর শেষের}মুছে দিন — বাটন ধূসর হয়ে যাবে, কারণ তখন আবার specificity(1,1,0)বনাম(0,1,0). -
AI অডিট: যেকোনো AI-কে বলুন: “আমার সাইটে Bootstrap আছে। .btn-primary বাটনের রং কমলা করার CSS দাও।” উত্তরে কয়টি
!importantআছে, কয়টি selector-এ id আছে, আর CSS ফাইলটি কোথায় link করতে বলেছে — খেয়াল করুন। তারপর AI-কে জিজ্ঞেস করুন, “!important ছাড়া কীভাবে করা যায়?”প্রায়ই প্রথম উত্তরে প্রতিটি লাইনে
!importantথাকে, বাbody .btn.btn-primary-এর মতো কৃত্রিমভাবে ভারী selector. ভালো উত্তর হবে: আপনার CSS ফাইল Bootstrap-এর পরে link করুন, আর একই specificity-র selector (.btn-primary) ব্যবহার করুন — লেখার ক্রমেই জিতবেন। Bootstrap 5-এর মতো সংস্করণে আরও পরিষ্কার পথ আছে: তাদের CSS variable (যেমন বাটনের রঙের variable) বদলানো। AI যদি বলে “id-এর ১০০ পয়েন্ট”, বুঝবেন ব্যাখ্যাটা পুরোনো মডেলের। তার কোড DevTools-এ যাচাই করুন — আসলে কোন declaration জিতল।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমCSS cascade দুটি declaration-এর বিচারে যে প্রশ্নগুলো করে, সেগুলো আগে থেকে পরে সাজান (▲▼ চেপে সরান)
- 🏛️ উৎস আর গুরুত্ব — user-agent, user, author;
!importantআছে কি না - 📌 Inline style —
styleattribute-এ লেখা কি না - 🗂️ Cascade layer — কোন
@layer-এ, বা layer-এর বাইরে - 🎯 Specificity — (a, b, c)
- 📍 Scope-এর নৈকট্য — কোন
@scope-এর মূল কাছে - ⏱️ লেখার ক্রম — কে পরে এসেছে
CSS selector #nav .item a-এর specificity কত?
- 111 পয়েন্ট
- (1, 1, 1)
- (1, 1, 0)
- (2, 1, 0)
একই element-এ দুটি নিয়ম: #box { color: green } আর তার পরে লেখা .a.b.c.d.e.f.g.h.i.j.k { color: red }. কোন রং দেখাবে?
- লাল — কারণ পরে লেখা
- লাল — কারণ ১১টি class মিলে ১১০ পয়েন্ট, id-র ১০০-র বেশি
- সবুজ — কারণ প্রথম ঘরে id এগিয়ে
- দুটি রং মিশে বাদামি
CSS-এ :where(#main, .box) p selector-এর specificity কত?
- (1, 0, 1)
- (0, 1, 1)
- (0, 0, 0)
- (0, 0, 1)
parent element-এ নিচের কোন CSS property দিলে সেটি ডিফল্টভাবে child element-এ উত্তরাধিকারে নামে?
colorborderpaddingbackground-color
একটি সাধারণ (important নয়) declaration @layer components { #buy { color: gray } }-এর ভেতরে, আর আরেকটি .btn { color: white } কোনো layer-এর বাইরে। দুটিই একই বাটনে লাগে। কে জিতবে?
- #buy — কারণ id selector ভারী
- .btn — কারণ layer-এর বাইরের CSS সব layer-এর ওপরে
- কোনোটি নয় — ব্রাউজার ডিফল্ট রং দেখাবে
- যেটি ফাইলে পরে লেখা, সেটি
পাঠকের user stylesheet-এ p { font-size: 22px !important }, আর সাইটের CSS-এ p { font-size: 14px !important }. কোন মাপ দেখাবে?
- 14px — কারণ author সবসময় user-এর ওপরে
- যেটি পরে লোড হয়েছে
- 22px — কারণ important-এ user author-কে হারায়
- ব্রাউজারের ডিফল্ট 16px — কারণ দুটি important বাতিল হয়ে যায়
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- Cascade প্রতিটি property-র জন্য আলাদাভাবে বিচার করে, এই ক্রমে: উৎস ও !important → inline style → layer → specificity → নৈকট্য → লেখার ক্রম.
- Specificity (a, b, c) — id, class-জাতীয়, type-জাতীয়; বাঁ দিক থেকে তুলনা। কোনো ঘর উপচে পড়ে না।
:is()/:not()/:has()নেয় তালিকার সবচেয়ে ভারী selector-এর ওজন;:where()সবসময় শূন্য।- লেখার বৈশিষ্ট্য (color, font, line-height) উত্তরাধিকারী, বক্সের বৈশিষ্ট্য (border, margin, padding, background) নয়। সরাসরি লাগা যেকোনো rule উত্তরাধিকারকে হারায়।
!importantশেষ অস্ত্র; আগে DevTools-এ কাটা দাগ দেখে বুঝুন কে কোন ধাপে হারল।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ১৯ · Box model — content, padding, border, margin আর box-sizingপরবর্তী পর্বপ্রতিটি element-এর চারপাশের জায়গার হিসাব।
- HTML ও CSS · কোর্স হোম৫৯টি পর্বপুরো কোর্সের রোডম্যাপ — প্রথম পেজ থেকে আধুনিক রেসপন্সিভ ডিজাইন।
- JavaScript · DOM-এর ভিত্তিগভীরে যানJavaScript দিয়ে element খোঁজা, class বদলানো আর
getComputedStyle()-এর মতো মান পড়া। - কম্পিউটার ও ICT · প্রথম HTML পেজপাশের ট্র্যাকICT পরীক্ষার দৃষ্টিকোণ থেকে HTML আর CSS-এর সংক্ষিপ্ত পরিচয়।