এই পর্বে যা পাবেন
- ব্রাউজারের মতো করে ভাবার একটি পাঁচ ধাপের চেকলিস্ট — কোন ধাপে কোন প্রশ্ন করতে হয়, আর কোন ধাপে সাধারণত ফাঁদ থাকে
- HTML parser-এর ভুল-সংশোধন, cascade, box model, flow ও position, flexbox, grid, রেসপন্সিভ ও আধুনিক CSS, আর মোশন ও ইফেক্ট — আট ভাগে সহজ থেকে কঠিন প্রশ্ন
- প্রতিটি অপশনের ব্যাখ্যা — ঠিকটি কেন ঠিক, আর ভুলগুলো কোন ভুল ধারণা থেকে আসে
- ১৫টি লাইভ এডিটর — কোড বদলে নিজের অনুমান নিজেই পরীক্ষা করার সুযোগ
- AI-এর দেওয়া “এটা এভাবে দেখাবে” দাবি DevTools আর ছোট পরীক্ষা দিয়ে যাচাইয়ের নিয়ম
১ · মডিউল ৮ শুরু — ব্রাউজারের মতো করে ভাবার পদ্ধতি
অভিনন্দন! ৫৪টি পর্বে আপনি প্রথম HTML পেজ থেকে শুরু করে ফর্ম, অ্যাক্সেসিবিলিটি, cascade, box model, flexbox, grid, container query, animation, পারফরম্যান্স আর একটি পূর্ণ পোর্টফোলিও সাইট প্রকাশ পর্যন্ত এসেছেন। এই শেষ মডিউলে নতুন বিষয় নেই — আছে পাঁচটি অনুশীলনের পর্ব, যাতে পরীক্ষার হলে, ক্লায়েন্টের টেস্টে বা ইন্টারভিউর টেবিলে চাপের মধ্যেও ঠিক উত্তর মাথায় আসে।
পর্ব ৫৫ · কী দেখাবে?
এই পর্ব। ছোট HTML-CSS দেখে বলতে হবে ব্রাউজার কী আঁকবে — রং, মাপ, অবস্থান, DOM.
কৌশল: পাঁচ ধাপে ভাবাপর্ব ৫৬ · MCQ প্রশ্নব্যাংক
ধারণা, সংজ্ঞা আর তথ্যের দ্রুত প্রশ্ন — চাকরির বাছাই পরীক্ষায় এ ধরনের প্রশ্ন প্রায়ই আসে।
কৌশল: সময় ধরে চর্চাপর্ব ৫৭ · লিখিত ও ভাইভা
“পার্থক্য লিখুন”, “উদাহরণসহ ব্যাখ্যা করুন” আর মুখোমুখি প্রশ্নের উত্তর সাজানো।
কৌশল: উত্তরের কাঠামোপর্ব ৫৮–৫৯ · ইন্টারভিউ
ফ্রন্ট-এন্ড ইন্টারভিউর প্রশ্ন আর লাইভ কোডিংয়ে UI বানানোর চ্যালেঞ্জ।
কৌশল: জোরে ভাবা“কী দেখাবে?” প্রশ্ন এত বেশি আসে কেন
প্রশ্নকর্তা আসলে জানতে চান: আপনি কি rendering engine-এর মতো করে কোড পড়তে পারেন? CSS-এ কোনো error message নেই — ভুল declaration চুপচাপ বাদ পড়ে, হেরে যাওয়া rule কিছু বলে না, আর ভাঙা HTML-ও ব্রাউজার নিজের মতো “ঠিক” করে নেয়। ফলে যে মানুষ মাথার ভেতরে রেন্ডার করতে পারেন না, তিনি বাগ খুঁজতে ঘণ্টার পর ঘণ্টা !important লাগান। আর যিনি পারেন, তিনি DevTools খোলার আগেই সন্দেহটা বলে দেন: “এখানে margin collapse হচ্ছে” বা “এই z-index একটি আলাদা stacking context-এ আটকা”।
| আপনার লক্ষ্য | শুরু করুন | তারপর |
|---|---|---|
| বিশ্ববিদ্যালয়ের ওয়েব টেকনোলজির লিখিত পরীক্ষা | এই পর্বের ২–৫ নম্বর ভাগ | পর্ব ৫৭ (লিখিত ও ভাইভা) |
| সরকারি বা ব্যাংকের IT পদের পরীক্ষা (ওয়েব অংশ) | পর্ব ৫৬ (MCQ) | এই পর্বের ২ ও ৩ নম্বর ভাগ |
| ফ্রন্ট-এন্ড ইন্টারভিউ বা ফ্রিল্যান্স ক্লায়েন্টের টেস্ট | এই পর্বের ৩, ৫, ৬, ৭ নম্বর ভাগ | পর্ব ৫৮ ও ৫৯ |
| শুধু নিজের শেখা যাচাই | এই পর্ব, প্রথম থেকে শেষ | যে ভাগে বেশি ভুল, সেই পর্বে ফিরে যান |
ব্রাউজারের মতো ভাবার পাঁচ ধাপ
প্রতিটি রেন্ডার-প্রশ্নের উত্তর বের করার একটাই নির্ভরযোগ্য উপায়: ব্রাউজার যে ক্রমে কাজ করে, ঠিক সেই ক্রমে ভাবা। পর্ব ১-এ যে পাইপলাইন দেখেছিলেন, সেটিকেই এখানে প্রশ্নের চেকলিস্ট বানানো হলো।
একটি দর্জির দোকানের কথা ভাবুন। প্রথমে অর্ডারের কাগজ পড়া হয় — কাগজে ভুল থাকলে কারিগর নিজের মতো করে বুঝে নেন (parse). তারপর ঠিক হয় কোন নির্দেশ মানা হবে — দোকানের নিয়ম, ক্রেতার বিশেষ অনুরোধ, শেষ মুহূর্তের ফোন (cascade). তারপর প্রতিটি অংশের মাপ — কাপড়, সেলাইয়ের জায়গা, পাড় (box). তারপর টেবিলে কোন টুকরো কোথায় বসবে (layout). সবশেষে রং আর কোনটা কোনটার ওপরে সেলাই হবে (paint). কোনো ধাপ বাদ দিলে জামা ভুল হয়।
- Parse — কোন DOM তৈরি হলো? লেখা HTML আর তৈরি হওয়া DOM এক নয়। বন্ধ না করা
<p>, টেবিলের ভেতরে ভুল জায়গার element, ভুল ক্রমে বন্ধ করা ট্যাগ — HTML parser এগুলো নির্দিষ্ট নিয়মে ঠিক করে। CSS-এর ক্ষেত্রে: ভুল declaration বা অচেনা selector বাদ পড়ে। - Cascade — প্রতিটি property-র জয়ী মান কোনটি? উৎস ও
!important→ inline style → layer → specificity → লেখার ক্রম। কোনো declaration না থাকলে উত্তরাধিকারী property parent থেকে আসে, বাকিরা initial value পায়। ফল: computed value. - Box — প্রতিটি বাক্সের মাপ কত?
displayঠিক করে বাক্সের ধরন (block, inline, flex item…)। তারপর box model: content + padding + border,box-sizingঅনুযায়ী। em, rem, %, vw-কে px-এ বদলান — % কোন বাক্সের সাপেক্ষে, সেটা আলাদা করে লিখুন। - Layout — কোথায় বসল? normal flow-তে block ওপর-নিচে, inline পাশাপাশি; উল্লম্ব margin মিশে যায় (margin collapse). flex আর grid-এ free space-এর ভাগ, positioned element-এর containing block.
- Paint — কী দেখা যায়, কোনটি ওপরে? stacking context, z-index, opacity, transform, clip-path. মনে রাখুন: transform আর opacity চেহারা বদলায়, layout বদলায় না।
নিচের ডায়াগ্রামে এই পাঁচ ধাপ একটি ছোট কোডে চালানো হয়েছে। প্রতিটি ধাপে “পরে” চাপার আগে নিজে উত্তর লিখুন: কয়টি <p> তৈরি হবে, লেখার রং কী, বাক্সের মোট চওড়া কত, দুই অনুচ্ছেদের মাঝে ফাঁক কত?
- Parse
HTML → DOMকোন গাছ হলো - Cascade
computedকোন মান জিতল - Box
box modelকত বড় - Layout
flowকোথায় বসল - Paint
pixelকী দেখা গেল
<!-- লেখা হয়েছে --> <div class="box" id="main"> <p class="note">দাম <span>৳৫০০</span> <p>স্টকে আছে </div> <!-- parser যা বানাল --> div#main.box ├─ p.note "দাম " + span "৳৫০০" ← নতুন <p> আসতেই আগেরটি বন্ধ └─ p "স্টকে আছে" ← </div> আসতেই বন্ধ
#main p { color: navy; } (1, 0, 1) ← জিতল
p.note { color: crimson; } (0, 1, 1)
p.note → navy (পরে লেখা crimson হারল — id-এর ঘর আগে তুলনা হয়)
দ্বিতীয় p → navy (p.note মেলেই না)
box-sizing: content-box (ডিফল্ট) width 200 → শুধু content 5 + 20 + 200 + 20 + 5 = 250px border padding content padding border span-এর margin: 10px → inline box, তাই শুধু ডানে-বাঁয়ে জায়গা নেয়; ওপর-নিচে লাইন সরায় না
p (UA stylesheet): margin: 1em 0 → 16px ওপরে, 16px নিচে
p.note-এর নিচের 16px ┐
├─ মিশে গিয়ে 16px, 32px নয়
দ্বিতীয় p-এর ওপরের 16px ┘
.box-এ padding আছে, তাই p-এর margin বাক্সের
বাইরে “গলে” যায় না — বাক্সের ভেতরেই থাকে
┌───────────── 250px ─────────────┐ teal border │ দাম [৳৫০০] │ navy লেখা, span-এ হলুদ │ │ ← 16px ফাঁক │ স্টকে আছে │ navy লেখা └─────────────────────────────────┘
- Parse. HTML-এ দুটি
<p>বন্ধ করা হয়নি, তবু DOM-এ ঠিক দুটি অনুচ্ছেদ। নতুন<p>শুরু হলে খোলা<p>নিজে থেকে বন্ধ হয়, আর</div>এলে ভেতরের সব খোলা element বন্ধ হয়। এটা “ভুল” নয় —</p>ঐচ্ছিক ট্যাগ (পর্ব ৩)। span প্রথম অনুচ্ছেদের ভেতরেই। - Cascade. দুই অনুচ্ছেদই navy. ফাঁদ:
p.noteপরে লেখা আর “বেশি নির্দিষ্ট মনে হয়”, কিন্তু#main p-এ একটি id আছে — specificity(1,0,1)বনাম(0,1,1), প্রথম ঘরেই ফয়সালা। লেখার ক্রম দেখা হয় শুধু specificity সমান হলে। - Box. ডিফল্ট
box-sizing: content-box, তাইwidth: 200pxশুধু content-এর। মোট = 5 + 20 + 200 + 20 + 5 = 250px. span-এরmargin: 10pxinline বাক্সে শুধু আনুভূমিক দিকে কাজ করে। - Layout. দুই অনুচ্ছেদের মাঝে 16px — 16 + 16 = 32 নয়। দুটি block-এর পাশাপাশি উল্লম্ব margin মিশে যায়, বড়টি থাকে। .box-এর padding থাকায় অনুচ্ছেদের margin বাক্সের বাইরে যায় না।
- Paint. teal border-এর 250px চওড়া বাক্স, ভেতরে navy লেখা, দামের পেছনে হলুদ। এই উত্তরগুলো আন্দাজে নয়: নিচের লাইভ এডিটরে আর এই পাতার যাচাই-স্ক্রিপ্টে
getComputedStyle()দিয়ে রং, আরgetBoundingClientRect()দিয়ে 250 ও 16 মেপে মিলিয়ে নেওয়া হয়েছে।
নিচের কোডটি হুবহু ডায়াগ্রামের snippet, সাথে একটি ছোট মাপার স্ক্রিপ্ট। প্রিভিউ আর তার নিচের লেখা দেখার আগে দুটি পরিবর্তনের ফল অনুমান করুন: (ক) p.note-কে #main p.note করলে রং কী হবে? (খ) .box-এ box-sizing: border-box যোগ করলে চওড়া কত হবে?
<style>
.box { width: 200px; padding: 20px; border: 5px solid teal; }
#main p { color: navy; }
p.note { color: crimson; }
span { margin: 10px; background: #fde68a; }
</style>
<div class="box" id="main">
<p class="note">দাম <span>৳৫০০</span>
<p>স্টকে আছে
</div>
<script>
(function m() {
if (!document.body.offsetWidth) return setTimeout(m, 50);
const [a, b] = document.querySelectorAll("p");
console.log("p:", document.querySelectorAll("p").length,
"| রং:", getComputedStyle(a).color,
"| চওড়া:", document.querySelector(".box").getBoundingClientRect().width,
"| ফাঁক:", b.getBoundingClientRect().top - a.getBoundingClientRect().bottom);
})();
</script>প্রিভিউতে teal বাক্সে দুটি navy লাইন, আর নিচের লেখায়: p: 2 | রং: rgb(0, 0, 128) | চওড়া: 250 | ফাঁক: 16. নিজের অনুমান মিলিয়ে তারপর উত্তর খুলুন।
(ক) #main p.note-এর specificity (1,1,1), যা #main p-এর (1,0,1)-কে হারায় — প্রথম লাইন crimson হবে, দ্বিতীয়টি navy-ই থাকবে। (খ) border-box-এ 200px মানে border পর্যন্ত মোট মাপ — চওড়া 200, content নেমে আসে 150-এ। চেষ্টা করুন: <div>-এর padding মুছে দিন — ফাঁক 16-ই থাকে, কিন্তু প্রথম অনুচ্ছেদের ওপরের margin তখন বাক্সের বাইরে চলে যায় (৪ নম্বর ভাগে এর প্রশ্ন আছে)।
উত্তর কয়েক রকম হতে পারে
“কী দেখাবে?” প্রশ্নের উত্তর সবসময় একটি রং বা একটি সংখ্যা নয়। ভালো প্রশ্নকর্তা ঠিক এখানেই পার্থক্য করেন:
✅ নির্দিষ্ট মান
স্পেসিফিকেশন ফল পুরোপুরি ঠিক করে — যেকোনো আধুনিক ব্রাউজারে একই রং, একই px. এই পাতার বেশিরভাগ প্রশ্ন এমন।
যেমন: 1fr 2fr → 200px 400px🚫 কিছুই বদলায় না
declaration-টি অবৈধ বলে বাদ পড়েছে, selector অচেনা বলে পুরো rule বাদ, অথবা property এই বাক্সে কাজই করে না (inline-এ width, static-এ z-index).
যেমন: span-এ width🌳 DOM-ই বদলে যায়
HTML parser লেখা কোড “মেরামত” করে — element সরে যায়, নতুন element তৈরি হয়, ভাঙা নেস্টিং দুই ভাগ হয়।
যেমন: table-এ tbody📏 পরিবেশ-নির্ভর
viewport-এর চওড়া, ব্যবহারকারীর পছন্দ (dark mode, reduced motion), ফন্ট, ভাষা। এমন প্রশ্নে শর্ত লেখা থাকবে; না থাকলে “নির্ভর করে, কারণ…” লেখাই পূর্ণ উত্তর।
যেমন: 4vw কত pxআলাদা কিছু বলা না থাকলে: প্রতিটি snippet একটি <!doctype html>-ওয়ালা পাতার <body>-এ বসানো (standards mode), কোনো CSS reset নেই — অর্থাৎ ব্রাউজারের ডিফল্ট স্টাইল চালু: body-র margin 8px, মূল font-size 16px, <p>-এর margin 1em 0, <h1> 2em. box-sizing ডিফল্ট content-box. viewport-নির্ভর প্রশ্নে চওড়া প্রশ্নেই লেখা থাকবে, আর ধরে নেওয়া হবে কোনো স্ক্রলবার জায়গা নিচ্ছে না। রং লেখা হয়েছে getComputedStyle() যেভাবে দেয়: rgb(255, 0, 0). একাধিক মান অপশনে “ · ” দিয়ে আলাদা।
(সহজ) ব্রাউজার একটি পাতা দেখানোর সময় নিচের কাজগুলোর কোন ক্রম ঠিক?
- Paint → Layout → Cascade → Parse
- Parse → Cascade → Layout → Paint
- Parse → Layout → Cascade → Paint
- Cascade → Parse → Paint → Layout
(মাঝারি) একটি rule-এ p { color: red; color: blu; } লেখা — দ্বিতীয় মানে বানান ভুল। অন্য কোনো CSS নেই। অনুচ্ছেদের রং কী হবে?
- লাল — অবৈধ declaration-টি শুধু বাদ পড়ে
- নীল — ব্রাউজার কাছাকাছি নাম ধরে নেয়
- পাতা দেখাবে না — CSS error
- কালো — ভুল থাকায় পুরো rule বাদ
২ · HTML-এর গঠন আর parser — লেখা কোড বনাম আসল DOM
এই ভাগের প্রশ্নে CSS প্রায় নেই; প্রশ্ন একটাই — ব্রাউজার আসলে কোন গাছ (DOM) বানাল? HTML-এর parser কখনো “error” দিয়ে থামে না। স্পেসিফিকেশন (WHATWG HTML Living Standard) প্রতিটি ভুলের জন্য ঠিক করে দিয়েছে কী করতে হবে, তাই সব আধুনিক ব্রাউজার একই ভাঙা HTML থেকে একই DOM বানায়। DevTools-এর Elements প্যানেল দেখায় এই তৈরি DOM, View Source দেখায় আপনার লেখা কোড — দুটি মেলালেই parser-এর কাজ চোখে পড়ে।
ঝালিয়ে নিন: পর্ব ০৩ · প্রথম HTML পেজ, পর্ব ০৪ · লেখা ও অর্থবহ ট্যাগ, পর্ব ০৭ · তালিকা আর টেবিল, পর্ব ০৮ · ফর্মের ভিত্তি, পর্ব ১১ · details, dialog আর popover, পর্ব ১২ · অ্যাক্সেসিবিলিটি, পর্ব ৫২ · DOM, template আর Web Components.
(সহজ) <body>-এ শুধু এটুকু লেখা। DOM-এ কী তৈরি হবে?
<p>এক<p>দুই
- একটি
<p>, ভেতরে লেখা “একদুই” - একটি
<p>-এর ভেতরে আরেকটি<p> - দুটি পাশাপাশি
<p>— দুটিই body-র সরাসরি সন্তান - কিছুই দেখাবে না — বন্ধ ট্যাগ নেই বলে parse error
(মাঝারি) এই কোড থেকে DOM-এ মোট কয়টি <p> element তৈরি হবে?
<p>ক <div>খ</div> গ</p>
- ১টি — ভেতরে div আর “গ”-সহ
- ১টি — div বাদ পড়ে যায়
- ৩টি
- ২টি — দ্বিতীয়টি খালি
(মাঝারি) CSS-এ table > tr { color: red; }, আর HTML-এ <table><tr><td>১</td></tr></table>. ঘরের লেখা কোন রঙের হবে?
- লাল — tr টেবিলের সরাসরি সন্তান
- টেবিলই দেখাবে না — tbody ছাড়া টেবিল অবৈধ
- লাল — td রং উত্তরাধিকারে পায়
- কালো — DOM-এ tr আছে একটি অদৃশ্য
<tbody>-এর ভেতরে
(কঠিন) ভুল ক্রমে বন্ধ করা ট্যাগ। “৩” লেখাটি কেমন দেখাবে?
<b>১<i>২</b>৩</i>
- মোটা আর বাঁকা — দুটোই
- সাধারণ — কোনোটিই নয়
- শুধু বাঁকা — parser একটি নতুন
<i>তৈরি করে - শুধু মোটা
(সহজ) অনুচ্ছেদে অনেক space আর দুটি Enter আছে। পাতায় কীভাবে দেখাবে?
<p>ঢাকা থেকে
চট্টগ্রাম</p>
- তিন লাইনে, ফাঁকা লাইনসহ
- ঢাকাথেকেচট্টগ্রাম
- হুবহু যেমন লেখা
- ঢাকা থেকে চট্টগ্রাম — এক লাইনে, এক space করে
(মাঝারি) CSS-এ .show { display: block; }. HTML-এ <p hidden class="show">ক</p><p hidden>খ</p>. কোনটি দেখা যাবে?
- শুধু “খ”
- কোনোটিই না —
hiddenসবসময় জেতে - দুটিই
- শুধু “ক”
(মাঝারি) এই কোডের পরে document.querySelectorAll("p").length কত?
<template><p>লুকানো</p></template>
<p>দৃশ্যমান</p>
- 1
- 0
- 2
- error — template-এর ভেতরে p নিষেধ
(কঠিন) কেউ ভুল করে বন্ধ-ট্যাগের মতো লিখেছেন। ব্রাউজারে কী দেখাবে?
<div>এক</br>দুই</div>
- দুই লাইনে —
</br>একটি<br>হয়ে যায় - “একদুই” — অচেনা বন্ধ-ট্যাগ উপেক্ষা হয়
- কিছুই দেখাবে না
- “এক</br>দুই” — ট্যাগটি লেখা হিসেবে
(কঠিন) React বা XML-এর অভ্যাসে লেখা “self-closing” div. <p>-টির parent কে হবে?
<div/>এক
<p>দুই</p>
- body — div নিজেই বন্ধ হয়ে গেছে
- div —
/উপেক্ষা হয়, div খোলাই থাকে - “এক” লেখাটি
- একটি নতুন খালি div
(কঠিন) <button title="শেয়ার">↗</button> — screen reader এই বাটনের নাম (accessible name) কী শোনাবে?
- “শেয়ার ↗”
- “শেয়ার”
- “↗” — ভেতরের লেখা title-এর আগে
- কোনো নাম নেই
লিখিত ১(মাঝারি) DOM-টি গাছের আকারে লিখুন — <table><p>নোট</p><tr><td>১</td></tr></table>. “নোট” লেখাটি পাতায় কোথায় দেখাবে?
DOM হবে এমন (body-র সন্তান দুটি, এই ক্রমে):
body
├─ p "নোট"
└─ table
└─ tbody
└─ tr
└─ td "১"
দুটি মেরামত একসাথে ঘটেছে। প্রথমটি foster parenting: টেবিলের ভেতরে (কিন্তু কোনো ঘরের বাইরে) এমন element এলে, যা সেখানে থাকতে পারে না, parser সেটিকে তুলে টেবিলের ঠিক আগে বসিয়ে দেয়। তাই “নোট” টেবিলের ওপরে দেখায়, যদিও কোডে টেবিলের ভেতরে লেখা। দ্বিতীয়টি <tbody>: <tr> সরাসরি table-এ এলে parser একটি tbody তৈরি করে। যাচাই: [...document.body.children].map(e => e.tagName) দেয় P,TABLE, আর table.firstElementChild.tagName দেয় TBODY. টেবিলের ওপরে নোট দরকার হলে লিখুন <caption> — সেটাই টেবিলের বৈধ শিরোনাম (পর্ব ৭)।
লিখিত ২(কঠিন) নিচের সাতটি control-এর প্রতিটির accessible name কী, আর কোনটির নামই নেই? <button aria-label="বন্ধ করুন">✕</button> · <label for="ph">মোবাইল নম্বর</label><input id="ph" placeholder="01XXXXXXXXX"> · <button><img src="…" alt="খুঁজুন"></button> · <span id="t">ডেলিভারি চার্জ</span><button aria-labelledby="t" aria-label="অন্য নাম">ⓘ</button> · <a href="#"><svg aria-hidden="true">…</svg></a> · <input placeholder="নাম লিখুন"> · <button title="শেয়ার">↗</button>
| control | নাম | কোথা থেকে এল |
|---|---|---|
| ✕ বাটন | বন্ধ করুন | aria-label ভেতরের লেখাকে হারায় |
| মোবাইলের input | মোবাইল নম্বর | <label for>; placeholder নাম নয় |
| ছবির বাটন | খুঁজুন | ভেতরের ছবির alt |
| ⓘ বাটন | ডেলিভারি চার্জ | aria-labelledby সবার আগে — aria-label-কেও হারায় |
| আইকনের লিংক | নাম নেই | svg লুকানো, লেখা নেই — screen reader শুধু “link” বলবে। এটাই সবচেয়ে বড় বাগ |
| নামের input | নাম লিখুন | আর কিছু না থাকায় শেষ ভরসা placeholder — লেখা শুরু করলেই চোখে মুছে যায়, তাই label দিন |
| ↗ বাটন | ↗ | ভেতরের লেখা; title শুধু তখন, যখন কিছুই নেই |
যাচাই: পাতাটি Edge-এ খুলে Playwright-এর aria_snapshot() (ব্রাউজারের accessibility tree) থেকে পড়া হয়েছে; DevTools-এর Accessibility প্যানেলেও “Computed Properties → Name”-এ একই নাম দেখায়। মনে রাখার ক্রম: aria-labelledby → aria-label → label/alt/caption → ভেতরের লেখা → title/placeholder. আর ARIA-র প্রথম নিয়ম: নিজস্ব HTML (label, alt, লেখা) দিয়ে নাম দেওয়া গেলে ARIA লাগবেই না (পর্ব ১২)।
নিজে অনুমান করে দেখুন — parser-এর তিনটি মেরামত একসাথে
নিচের কোডে তিনটি “ভুল” আছে। প্রিভিউ দেখার আগে খাতায় লিখুন: body-র সরাসরি সন্তান কোন কোন element, কোন ক্রমে? কোন লেখা মোটা, কোনটি বাঁকা? স্ক্রিপ্টটি তৈরি হওয়া DOM-এর একটি সারাংশ ছাপবে।
<p>অর্ডার: <div>শাড়ি</div></p>
<b>জরুরি <i>আজই</b> পাঠান</i>
<table border="1">
<p>মোট দাম নিচে:</p>
<tr><td>৳ ২,৫০০</td></tr>
</table>
<script>
const kids = [...document.body.children]
.filter(e => e.tagName !== "SCRIPT").map(e => e.tagName);
console.log("body-র সন্তান:", kids.join(", "));
console.log("i element:", document.querySelectorAll("i").length,
"| table-এর প্রথম সন্তান:", document.querySelector("table").firstElementChild.tagName);
</script>প্রিভিউর নিচে দুই লাইন ছাপা হয়। আগে নিজের তালিকা লিখুন, তারপর মেলান ও উত্তর খুলুন।
ছাপা হয়: body-র সন্তান: P, DIV, P, B, I, P, TABLE আর i element: 2 | table-এর প্রথম সন্তান: TBODY. প্রথম লাইনে: div আসতেই p বন্ধ, তারপর বাড়তি </p> থেকে একটি খালি p. দ্বিতীয় লাইনে adoption agency: “আজই” মোটা ও বাঁকা, “ পাঠান” শুধু বাঁকা (নতুন i). তৃতীয় অংশে foster parenting: “মোট দাম নিচে:” টেবিলের ওপরে চলে এসেছে, আর tr গেছে একটি তৈরি-করা tbody-তে। চেষ্টা করুন: টেবিলের p-কে <caption> বানিয়ে দিন — এবার লেখাটি টেবিলের অংশ হয়ে যায়, body-র সন্তানের তালিকা থেকে শেষ P সরে যায়।
নিজে অনুমান করে দেখুন — তালিকার নম্বর
দুটি ক্রমিক তালিকা। প্রিভিউ দেখার আগে লিখুন, ছয়টি আইটেমের পাশে কোন কোন নম্বর বসবে।
<p>কাউন্টডাউন:</p>
<ol reversed start="5">
<li>প্রস্তুতি</li>
<li>মহড়া</li>
<li>উদ্বোধন</li>
</ol>
<p>ক্রমিক নম্বর:</p>
<ol start="3">
<li>রহিম</li>
<li value="10">করিম</li>
<li>সালমা</li>
</ol>প্রিভিউতে দুটি নম্বরযুক্ত তালিকা দেখা যায়। নিজের ছয়টি নম্বর মিলিয়ে উত্তর খুলুন।
প্রথম তালিকা: 5, 4, 3 — reversed গোনে উল্টো দিকে, আর start প্রথম আইটেমের নম্বর ঠিক করে। দ্বিতীয়: 3, 10, 11 — value একটি আইটেমের নম্বর বদলায়, আর পরের আইটেম সেখান থেকে গোনা চালিয়ে যায়। চেষ্টা করুন: প্রথম তালিকা থেকে start="5" মুছে দিন — reversed তালিকা তখন আইটেমের সংখ্যা থেকে শুরু করে: 3, 2, 1. দ্বিতীয় তালিকায় type="a" যোগ করুন — c, j, k.
৩ · Cascade, specificity আর inheritance — কোন রং জেতে
এই ভাগের প্রতিটি প্রশ্নে একটি element, একটি property, আর কয়েকটি প্রতিযোগী declaration. উত্তর বের করতে সিঁড়ির ধাপগুলো ক্রমে জিজ্ঞেস করুন: উৎস ও !important → inline style → layer → specificity → লেখার ক্রম। কোনো ধাপে একজন এগিয়ে থাকলে খেলা শেষ। আর কোনো declaration সরাসরি না লাগলে তবেই inheritance-এর প্রশ্ন: property-টি কি উত্তরাধিকারী? হলে parent-এর computed মান, না হলে initial value.
ঝালিয়ে নিন: পর্ব ১৬ · CSS-এর সাথে পরিচয়, পর্ব ১৭ · Selector, পর্ব ১৮ · Cascade, specificity আর inheritance, পর্ব ৪৬ · CSS architecture, পর্ব ৫১ · Bootstrap আর Tailwind.
(সহজ) element-টি <p id="box" class="a b c d e f g h i j k">. কোন rule জেতে?
#box { color: red; }
.a.b.c.d.e.f.g.h.i.j.k { color: blue; }
- নীল — ১১ × ১০ = ১১০ পয়েন্ট, id-র ১০০-এর বেশি
- লাল — id-এর ঘর আগে তুলনা হয়
- কালো — দুটিই বাদ
- নীল — পরে লেখা
(মাঝারি) দুটি অনুচ্ছেদ: <p id="offer" class="price" style="color: purple"> আর <p id="o2" style="color: purple">. কোনটির রং কী?
.price { color: green !important; }
#offer { color: navy; }
- দুটিই সবুজ
- #offer বেগুনি · #o2 বেগুনি
- #offer নীল · #o2 বেগুনি
- #offer সবুজ · #o2 বেগুনি
(মাঝারি) <div id="main"><p>…</p></div>-এ নিচের দুই rule. রং কী?
:where(#main) p { color: red; }
p { color: blue; }
- লাল — ভেতরে id আছে
- কালো —
:where()অবৈধ - নীল — দুটির specificity সমান, পরেরটি জেতে
- নীল — প্রথম rule মেলেই না
(কঠিন) HTML: <p><span class="x">নতুন</span></p> — পাতায় কোনো #main নেই। span-এর রং কী?
:is(#main, p) span { color: red; }
.x { color: blue; }
- লাল —
:is()নেয় তালিকার সবচেয়ে ভারী selector-এর ওজন - নীল — span মিলেছে p দিয়ে, তাই ওজন (0,0,2)
- নীল —
#mainনেই, তাই প্রথম rule বাতিল - কালো
(সহজ) <div id="parent"><p>লেখা</p></div>. অনুচ্ছেদের রং কী?
#parent { color: red; }
p { color: blue; }
- লাল — id বেশি ভারী
- বেগুনি — দুটি মিশে
- নীল — সরাসরি লাগা rule উত্তরাধিকারকে হারায়
- লাল — p উত্তরাধিকারে পায়
(মাঝারি) <button id="btn" class="btn">. বাটনের লেখার রং কী?
@layer base {
#btn { color: red; }
}
.btn { color: blue; }
- লাল — id ভারী
- বাটনের ডিফল্ট রং
- নীল — layer-এর বাইরের CSS সব layer-এর ওপরে
- নীল — শুধু পরে লেখা বলে
(কঠিন) সবগুলোতেই !important. অনুচ্ছেদের রং কী?
@layer a, b;
@layer a { p { color: red !important; } }
@layer b { p { color: blue !important; } }
p { color: green !important; }
- কালো — তিনটি important বাতিল
- সবুজ — layer-এর বাইরের CSS সবার ওপরে
- নীল — পরের layer জেতে
- লাল — important-এ আগের layer জেতে
(কঠিন) HTML-এ <p>ক</p><span>খ</span>. কোনটি লাল হবে?
p, p:unknown { color: red; }
:is(span, :unknown) { color: red; }
- দুটিই
- কোনোটিই না
- শুধু “খ” (span)
- শুধু “ক” (p)
(মাঝারি) Tailwind-ধাঁচের দুটি utility class. দুটি অনুচ্ছেদের রং কী?
/* CSS ফাইলে এই ক্রমে */
.text-blue { color: blue; }
.text-red { color: red; }
<p class="text-red text-blue">প্রথম</p>
<p class="text-blue text-red">দ্বিতীয়</p>
- প্রথম নীল · দ্বিতীয় লাল — class attribute-এ শেষেরটি জেতে
- প্রথম লাল · দ্বিতীয় নীল
- দুটিই লাল — stylesheet-এর ক্রম জেতে
- দুটিই নীল
(মাঝারি) body { color: green; } — আর কোনো CSS নেই। পাতার একটি <a href="#x">লিংক</a> কোন রঙে দেখাবে?
- ব্রাউজারের ডিফল্ট লিংকের নীল
- কালো
- সবুজ — color উত্তরাধিকারী
- সবুজ আর নীলের মাঝামাঝি
(মাঝারি) shorthand-এর ফাঁদ। p-এর background-color আর div-এর margin-top কত?
p { background-color: yellow; background: url(none.png); }
div { margin-top: 30px; margin: 10px; }
- হলুদ · 30px
- স্বচ্ছ · 30px
- স্বচ্ছ (transparent) · 10px
- হলুদ · 10px
লিখিত ৩(মাঝারি) body { color: green }, p { color: initial }, a { color: inherit }. পাতায় একটি <p> আর একটি <div>-এর ভেতরে লিংক আছে। দুটির রং কী, আর কেন?
p কালো, লিংক সবুজ। initial মানে “property-র স্পেসিফিকেশনে লেখা প্রাথমিক মান” — color-এর ক্ষেত্রে CanvasText, সাদা পটভূমির পাতায় কালো rgb(0, 0, 0). এটি body-র সবুজ উত্তরাধিকারকেও কেটে দেয়। অনেকে ভাবেন initial মানে “ব্রাউজারের ডিফল্ট” — না, সেটি revert. আর inherit লিংককে বাধ্য করে parent div-এর computed রং নিতে, যা body থেকে আসা সবুজ; ব্রাউজারের নীল :link rule এখানে হারে, কারণ author-এর a rule তার চেয়ে এগিয়ে। যাচাই: getComputedStyle দেয় rgb(0, 0, 0) আর rgb(0, 128, 0).
নিজে অনুমান করে দেখুন — তিন ফাঁদ এক কোডে
তিনটি লেখা — “শিরোনাম”, “শার্ট” আর “নতুন”। প্রিভিউ দেখার আগে তিনটির রং খাতায় লিখুন। সতর্কতা: এখানে *, :is() আর উত্তরাধিকার — তিনটিই খেলছে।
* { color: black; }
body { color: crimson; font-size: 20px; }
#shop { color: green; }
.item { color: blue; }
:is(#shop, ul) .item { color: orange; }
.tag { font-weight: bold; }প্রিভিউতে তিনটি লেখা তিন রঙের নয় — দুটি একই রঙের। নিজের অনুমান মিলিয়ে উত্তর খুলুন।
শিরোনাম কালো, শার্ট কমলা, নতুন কালো। p আর span-এ * সরাসরি লাগে, তাই #shop বা li থেকে উত্তরাধিকার আসেই না। li-তে :is(#shop, ul) .item-এর ওজন (1,1,0) — .item-এর (0,1,0)-কে হারায়। চেষ্টা করুন: প্রথম লাইন * { color: black; } মুছে দিন — এবার শিরোনাম সবুজ (#shop থেকে), “নতুন” কমলা (li থেকে)। তারপর :is(#shop, ul)-কে :where(#shop, ul) করুন — li তবু কমলা থাকে: এবার দুই selector-ই (0,1,0), আর :where()-এর rule পরে লেখা। এখন .item { color: blue; } লাইনটি সবার নিচে সরিয়ে দিন — li নীল হয়ে যায়, কারণ ওজন সমান হলে শেষ বিচারক লেখার ক্রম।
নিজে অনুমান করে দেখুন — layer আর !important
দুটি বাটন। প্রতিটির পটভূমি আর লেখার রং কী হবে? মনে রাখুন, সাধারণ declaration-এ পরের layer জেতে, কিন্তু !important-এ ক্রম উল্টো।
@layer reset, theme;
@layer theme {
.btn { background: teal; color: white; }
#buy { color: red; }
}
@layer reset {
button { background: gray !important; color: black; }
}
button { padding: 8px 16px; font-size: 18px; border: 0; }
#buy { color: yellow; }প্রিভিউতে দুটি বাটন। পটভূমি দুটিরই এক, লেখার রং আলাদা। অনুমান মিলিয়ে উত্তর খুলুন।
দুটির পটভূমি ধূসর; “কিনুন”-এর লেখা হলুদ, “কার্টে রাখুন”-এর সাদা। পটভূমি: reset layer-এর !important সব সাধারণ declaration-কে হারায়, আর important-এ আগের layer সবচেয়ে শক্ত — theme-এর teal কোনো সুযোগই পায় না। লেখা: #buy { color: yellow } কোনো layer-এ নেই, তাই layer-এর ভেতরের লাল আর কালোকে হারায়। দ্বিতীয় বাটনে theme (পরের layer) reset-কে হারায় — সাদা। চেষ্টা করুন: gray !important থেকে !important মুছে দিন — দুটি বাটনই teal হবে। তারপর প্রথম লাইনে ক্রম উল্টে @layer theme, reset; লিখুন — দ্বিতীয় বাটনের লেখা কালো হয়ে যায়।
৪ · Box model, একক আর টাইপোগ্রাফি — চূড়ান্ত মাপ কত px
এই ভাগের প্রতিটি প্রশ্ন একটি হিসাব। খাতায় তিনটি জিনিস আলাদা করে লিখুন: (১) box-sizing কী — width কোন পর্যন্ত মাপে? (২) প্রতিটি আপেক্ষিক একক কার সাপেক্ষে? em → নিজের font-size (font-size-এ লিখলে parent-এর), rem → root-এর, % width/padding/margin → containing block-এর চওড়ার, % height → containing block-এর উচ্চতার (যদি সেটি নির্দিষ্ট থাকে)। (৩) উল্লম্ব margin কি পাশাপাশি দুটি block-এর মাঝে? তাহলে মিশে যাবে।
ঝালিয়ে নিন: পর্ব ১৯ · Box model, পর্ব ২০ · একক আর রং, পর্ব ২১ · টাইপোগ্রাফি আর ওয়েব ফন্ট, পর্ব ২২ · ব্যাকগ্রাউন্ড, বর্ডার আর ছায়া.
(সহজ) ওপরের div-এ margin-bottom: 30px, ঠিক নিচের div-এ margin-top: 20px. দুটির মাঝে ফাঁক কত?
- 30px
- 20px
- 25px
- 50px
(মাঝারি) ওপরের div-এ margin-bottom: 30px, নিচের div-এ margin-top: -10px. মাঝে ফাঁক কত?
- 40px
- 30px
- 20px
- −10px
(মাঝারি) display: flex; flex-direction: column-এর ভেতরে দুটি div, প্রতিটিতে margin: 20px 0. দুটির মাঝে ফাঁক কত?
- 20px
- 0px
- 40px
- 80px
(মাঝারি) parent-এর width: 400px; height: 100px; child-এ padding-top: 50%. child-এর padding-top কত?
- 50px — parent-এর উচ্চতার অর্ধেক
- child-এর লেখার উচ্চতার অর্ধেক
- 0 — % padding অবৈধ
- 200px — parent-এর চওড়ার অর্ধেক
(সহজ) 300px চওড়া parent-এর ভেতরে child: width: 100%; padding: 0 20px; (box-sizing ডিফল্ট)। child কত চওড়া?
- 300px
- 260px
- 320px
- 340px — parent থেকে বেরিয়ে যায়
(মাঝারি) .a { font-size: 20px } → ভেতরে .b { font-size: 1.5em } → ভেতরে .c { font-size: 1.5em }, আর .c-এর ভেতরে .r { font-size: 1.5rem }. .c আর .r-এর font-size কত? (root 16px)
- 30px · 24px
- 45px · 24px
- 45px · 67.5px
- 24px · 24px
(কঠিন) parent-এর font-size 16px. child: font-size: 2em; padding: 1em;. child-এর padding কত?
- 16px — parent-এর font-size
- 64px
- 0 — padding-এ em চলে না
- 32px — element-এর নিজের font-size
(মাঝারি) parent-এ কোনো height লেখা নেই। child-এ height: 50%, ভেতরে এক লাইন লেখা। child কত উঁচু হবে?
- parent-এর অর্ধেক
- লেখার সমান — 50% উপেক্ষিত হয়ে auto
- viewport-এর অর্ধেক
- 0px
(মাঝারি) span { width: 200px; height: 80px; background: gold; }, আর <p><span>৳</span></p>. হলুদ অংশ কত বড় দেখাবে?
- শুধু “৳”-এর চারপাশে — width/height উপেক্ষিত
- 200px × 80px
- 200px চওড়া, লেখার সমান উঁচু
- কিছুই দেখাবে না
(কঠিন) দুটি div-এ font-size 16px. একটিতে line-height: 1.5, অন্যটিতে line-height: 1.5em. দুটির ভেতরে p { font-size: 32px }. দুই p-এর line-height কত?
- এককহীন 48px · em 24px
- দুটিই 24px
- দুটিই 48px
- এককহীন 24px · em 48px
(মাঝারি) width: 500px; max-width: 300px; min-width: 400px; — তিনটিই একসাথে। বাক্সটি কত চওড়া?
- 300px
- 400px
- 500px
- auto — বিরোধে তিনটিই বাতিল
লিখিত ৪(মাঝারি) viewport 1000px চওড়া (স্ক্রলবার নেই), body { margin: 0 }. একটি div-এ width: 50vw; padding: 0 2%;, আর তার ভেতরে একটি child-এ width: 50%. div-এর মোট চওড়া আর child-এর চওড়া কত?
div 540px, child 250px. vw সবসময় viewport-এর সাপেক্ষে: 50vw = 500px — এটা content-এর চওড়া (content-box). padding-এর % containing block-এর চওড়ার সাপেক্ষে; div-এর containing block হলো body, যার চওড়া 1000px, তাই প্রতি দিকে 2% = 20px, মোট 500 + 40 = 540px. child-এর 50% আবার তার নিজের containing block — div-এর content box — এর সাপেক্ষে: 500 × 50% = 250px. ফাঁদ দুটি: padding-এর % নিজের চওড়ার নয়, আর child-এর % padding বাদ দিয়ে content-এর। আরেকটি সূক্ষ্মতা: পাতায় স্ক্রলবার জায়গা নিলে 100vw তার চেয়ে চওড়া হয়, তাই width: 100vw অনেক সময় পাশে স্ক্রল তৈরি করে — পুরো চওড়ার জন্য width: 100% নিরাপদ। (যাচাই: Edge-এ 1000px viewport-এ 50vw মাপা হয়েছে 500px.)
নিজে অনুমান করে দেখুন — তিন বাক্সের চওড়া
তিনটি div, সবার width: 200px; padding: 20px; border: 5px. পার্থক্য শুধু box-sizing আর তৃতীয়টির বড় padding. প্রিভিউ দেখার আগে তিনটি চওড়া লিখুন — স্ক্রিপ্ট নিচে মাপ ছাপবে।
<style>
div { width: 200px; padding: 20px; border: 5px solid #0f766e;
margin: 10px 0; background: #ccfbf1; }
.b { box-sizing: border-box; }
.c { box-sizing: border-box; width: 100px; padding: 60px; }
</style>
<div class="a">content-box</div>
<div class="b">border-box</div>
<div class="c">?</div>
<script>
(function m() {
if (!document.body.offsetWidth) return setTimeout(m, 50);
for (const d of document.querySelectorAll("div"))
console.log("." + d.className, "→", d.getBoundingClientRect().width + "px");
})();
</script>প্রিভিউতে তিনটি সবুজাভ বাক্স, নিচে তিনটি মাপ। নিজের তিনটি সংখ্যা মিলিয়ে উত্তর খুলুন।
.a → 250px (200 + 40 + 10), .b → 200px, .c → 130px. তৃতীয়টিতে padding আর border মিলে 120 + 10 = 130, যা width-এর 100-এর বেশি; content 0-তে নেমে যায়, আর “?” চিহ্নটি padding-এর ভেতরে বেরিয়ে আসে। চেষ্টা করুন: .c-এর padding 30px করুন — এবার 100px (content 30). তারপর প্রথম rule-এ margin: 10px 0-কে margin: 10px করুন — চওড়া বদলায় না, কারণ getBoundingClientRect margin ধরে না।
নিজে অনুমান করে দেখুন — margin যখন বাক্সের বাইরে “গলে” যায়
হলুদ কার্ডের ভেতরে একটি শিরোনাম, তাতে margin-top: 40px. কার্ডের নিজের কোনো margin নেই। প্রিভিউ দেখার আগে ভাবুন: হলুদ রং পাতার একদম ওপর থেকে শুরু হবে, নাকি 40px নিচ থেকে? শিরোনাম কার্ডের ওপরের কিনারা থেকে কত দূরে?
<style>
body { margin: 0; }
.card { background: #fde68a; }
.card h2 { margin-top: 40px; }
</style>
<div class="card">
<h2>ঈদের অফার</h2>
</div>
<script>
(function m() {
if (!document.body.offsetWidth) return setTimeout(m, 50);
const c = document.querySelector(".card").getBoundingClientRect();
const h = document.querySelector("h2").getBoundingClientRect();
console.log("কার্ডের top:", c.top, "| h2-এর top:", h.top);
})();
</script>প্রিভিউর ওপরে একটি সাদা ফাঁক, তারপর হলুদ কার্ড। নিচের লাইনে দুটি সংখ্যা। অনুমান মিলিয়ে উত্তর খুলুন।
ছাপা হয় কার্ডের top: 40 | h2-এর top: 40. কার্ডের ওপরে padding বা border নেই, তাই প্রথম সন্তানের ওপরের margin parent-এর margin-এর সাথে মিশে কার্ডের বাইরে চলে যায় — পুরো কার্ড 40px নিচে নামে, আর শিরোনাম কার্ডের ঠিক কিনারায় বসে। চেষ্টা করুন: .card-এ display: flow-root; যোগ করুন — নতুন block formatting context margin আটকে দেয়: এবার কার্ডের top: 0 | h2-এর top: 40, হলুদ রং ওপর থেকে শুরু। padding-top: 1px বা border-top দিয়েও একই কাজ হয়, আর কার্ডটি flex বা grid container হলেও মেশে না।
৫ · Normal flow, position আর z-index — কোথায় বসে, কে ওপরে
অবস্থানের প্রশ্নে দুটি কথা আলাদা করে লিখুন। প্রথম: বাক্সটি কি flow-তে জায়গা নেয়? display: none, position: absolute/fixed আর float flow থেকে বেরিয়ে যায়; visibility: hidden, position: relative আর transform জায়গা ধরে রাখে। দ্বিতীয়: কার সাপেক্ষে? absolute-এর containing block হলো সবচেয়ে কাছের positioned ancestor (position static নয় এমন), না থাকলে initial containing block; fixed-এর viewport — যদি না কোনো ancestor-এ transform, filter বা এমন কিছু থাকে। ওপরে-নিচের প্রশ্নে আগে খুঁজুন: কোন কোন element নতুন stacking context তৈরি করেছে? z-index তুলনা হয় শুধু একই context-এর ভাইবোনদের মধ্যে।
ঝালিয়ে নিন: পর্ব ২৩ · Normal flow, display আর overflow, পর্ব ২৪ · position আর z-index, পর্ব ৪৭ · DevTools দিয়ে debugging (Edge-এর 3D View).
(সহজ) তিনটি div, প্রতিটি 30px উঁচু। প্রথমটিতে display: none, দ্বিতীয়টিতে visibility: hidden. তৃতীয় div-এর ওপরে কতটা খালি জায়গা থাকবে (body-র margin বাদে)?
- 0px — দুটিই লুকানো, কোনো জায়গা নেই
- 30px — শুধু
visibility: hidden-এর জায়গা - 60px — দুটিই জায়গা রাখে
- 30px — শুধু
display: none-এর জায়গা
(মাঝারি) 300px চওড়া div-এ তিনটি span { display: inline-block; width: 100px; }, HTML-এ প্রতিটি span আলাদা লাইনে লেখা। কী দেখাবে?
- তিনটি এক লাইনে, গায়ে গায়ে লাগানো
- তিনটি তিন লাইনে
- তিনটি এক লাইনে, প্রতিটি একটু ছোট হয়ে
- প্রথম দুটি এক লাইনে, তৃতীয়টি নিচের লাইনে
(সহজ) দুটি 30px উঁচু div. প্রথমটিতে position: relative; top: 20px;. দ্বিতীয়টি কী করবে?
- ওপরে উঠে প্রথমটির জায়গা নেবে
- 20px নিচে নামবে
- নড়বে না — প্রথমটি তার ওপর 10px চেপে বসবে
- কিছুই হবে না — top কাজ করে না
(মাঝারি) body { margin: 0 }. গঠন: .outer (position: relative; margin: 50px; padding: 20px) → .mid (margin: 30px, position নেই) → .k (position: absolute; top: 0; left: 0). .k পাতার কোন বিন্দুতে বসবে?
- (0, 0) — পাতার কোণে
- (100, 100) — .mid-এর কোণে
- (70, 70) — .outer-এর content-এর কোণে
- (50, 50) — .outer-এর padding box-এর কোণে
(মাঝারি) দুটি 100px বর্গ। লাল .a-তে z-index: 999 (position নেই)। নীল .b-তে position: relative; margin-top: -50px, z-index নেই। জোড়া অংশে কোন রং দেখা যাবে?
- নীল — positioned element non-positioned-এর ওপরে আঁকা হয়
- বেগুনি — দুটি মিশে
- নীল — শুধু DOM-এ পরে আছে বলে
- লাল — z-index 999
(কঠিন) ধূসর parent position: relative (z-index নেই), তার ভেতরে লাল child position: absolute; z-index: -1. (ক) লাল কি দেখা যাবে? (খ) parent-এ z-index: 0 যোগ করলে?
- (ক) দেখা যাবে না — parent-এর পটভূমির নিচে · (খ) দেখা যাবে
- (ক) দেখা যাবে · (খ) দেখা যাবে
- (ক) দেখা যাবে · (খ) দেখা যাবে না
- দুই ক্ষেত্রেই দেখা যাবে না — ঋণাত্মক z-index অবৈধ
(কঠিন) body { margin: 0 }. .p { transform: translateX(0); margin: 100px; }-এর ভেতরে .k { position: fixed; top: 0; left: 0; }. .k কোথায় বসবে, স্ক্রল করলে কী হবে?
- (0, 0) — viewport-এর কোণে, স্ক্রলে স্থির
- fixed বাতিল, .k static হয়ে যায়
- (100, 100) — .p-এর কোণে, .p-এর সাথে স্ক্রল হয়
- (0, 0), কিন্তু স্ক্রলে সরে যায়
(সহজ) body { margin: 0 }. 600 × 300px parent-এর ভেতরে 200 × 50px child, margin: auto. child-এর বাঁ আর ওপরের দূরত্ব কত?
- বাঁয়ে 200 · ওপরে 125 — দুই দিকেই মাঝখানে
- বাঁয়ে 0 · ওপরে 0
- বাঁয়ে 200 · ওপরে 0
- বাঁয়ে 33% · ওপরে 0
(মাঝারি) 100px উঁচু স্ক্রল-বাক্সে প্রথম সন্তান position: sticky, কিন্তু top লেখা নেই। বাক্স 50px স্ক্রল করলে sticky element কী করবে?
- অন্য লেখার সাথে স্ক্রল হয়ে ওপরে উঠে যাবে
- স্ক্রল বাক্স ছেড়ে viewport-এ আটকে যাবে
- লুকিয়ে যাবে
- ওপরে আটকে থাকবে
(কঠিন) 100 × 100px parent-এ overflow: hidden (position নেই)। ভেতরে position: absolute; top: 150px child. child কি দেখা যাবে?
- না — overflow: hidden সবকিছু কেটে দেয়
- হ্যাঁ — parent-এর বাইরে, কারণ parent তার containing block নয়
- না — top: 150px অবৈধ
- হ্যাঁ — কিন্তু parent-এর ভেতরে, ওপরে
নিজে অনুমান করে দেখুন — 9999 তবু নিচে কেন
একটি গোলাপি মডাল, z-index 9999. একটি নীল হেডার, z-index 2. দুটির একটি অংশ ওপর-নিচ। প্রিভিউ দেখার আগে লিখুন: জোড়া অংশে কোন রং? স্ক্রিপ্ট সেই বিন্দুতে সবার ওপরের element-এর নাম ছাপবে (elementFromPoint())।
<style>
body { margin: 0; }
.page { position: relative; z-index: 1; }
.modal { position: absolute; top: 20px; left: 20px; z-index: 9999;
width: 220px; height: 120px; background: #fecaca; }
.header { position: relative; z-index: 2; height: 80px;
background: #bfdbfe; }
</style>
<div class="page">
<div class="modal">মডাল (9999)</div>
</div>
<div class="header">হেডার (2)</div>
<script>
(function m() {
if (!document.body.offsetWidth) return setTimeout(m, 50);
console.log("বিন্দু (60, 50)-এ ওপরে:", document.elementFromPoint(60, 50).className);
})();
</script>প্রিভিউতে একটি নীল পট্টি আর একটি গোলাপি বাক্স, যার ওপরের অংশ ঢাকা পড়েছে বা পড়েনি — আর নিচে একটি নাম। অনুমান মিলিয়ে উত্তর খুলুন।
ছাপা হয় header — নীল হেডার মডালের ওপরে। .page-এর z-index: 1 একটি stacking context বানিয়েছে; মডালের 9999 তার ভেতরেই বন্দি, বাইরে পুরো .page-এর ওজন 1 < 2. চেষ্টা করুন: .page থেকে z-index: 1; মুছে দিন — এখন .page আর context নয়, মডাল root context-এ 9999 নিয়ে লড়ে আর জেতে: ছাপা হয় modal. তারপর .page-এ শুধু opacity: .99 লিখুন — আবার header! কারণ 1-এর কম opacity-ও নতুন stacking context বানায় (transform, filter, isolation: isolate-ও)।
৬ · Flexbox — free space কে কতটা পায়
Flexbox-এর প্রায় সব “কত চওড়া?” প্রশ্ন একটি হিসাব: free space = container-এর চওড়া − সব item-এর flex-basis − gap. free space ধনাত্মক হলে flex-grow-এর অনুপাতে ভাগ হয়; ঋণাত্মক হলে flex-shrink × basis-এর অনুপাতে কাটা হয়। flex-basis auto হলে basis = width (না থাকলে content-এর মাপ)। আর একটি অদৃশ্য নিয়ম সবকিছু ছাপিয়ে যায়: flex item-এর min-width: auto — item তার content-এর সবচেয়ে ছোট মাপের (min-content) নিচে নামে না।
ঝালিয়ে নিন: পর্ব ২৫ · Flexbox, পর্ব ২৬ · Flexbox দিয়ে বাস্তব নকশা.
grow: অনুপাতে যোগ · shrink: (shrink × basis)-এর অনুপাতে বিয়োগ · min-width: auto সবার ওপরে
(সহজ) .f { display: flex; width: 400px }-এ তিনটি item, প্রতিটি width: 200px. প্রতিটি item কত চওড়া হবে?
- 200px — তৃতীয়টি নিচের লাইনে
- 200px — container থেকে বেরিয়ে যায়
- 133.33px — তিনটিই সমান ছোট হয়
- প্রথম দুটি 200px, তৃতীয়টি 0px
(মাঝারি) 600px flex container-এ তিনটি item, সবার flex: 1. প্রথমটিতে “ক”, দ্বিতীয়টিতে এক লাইনের লম্বা লেখা, তৃতীয়টিতে “খ”. প্রথম item কত চওড়া?
- 200px — তিনটিই সমান
- লম্বা লেখার item-এর চেয়ে কম
- 600px — একাই সব জায়গা
- শুধু “ক”-এর সমান — content অনুযায়ী
(মাঝারি) body { margin: 0 }. 500px container-এ justify-content: space-between, তিনটি 100px item. তিনটির বাঁ কিনারা কোথায়?
- 33.33 · 200 · 366.67
- 0 · 100 · 200
- 0 · 200 · 400
- 50 · 200 · 350 (space-evenly-র মতো)
(মাঝারি) 500px container, দুটি 100px item. (ক) space-evenly আর (খ) space-around-এ প্রথম item-এর বাঁ কিনারা কোথায়? (body { margin: 0 })
- (ক) 75 · (খ) 100
- (ক) 100 · (খ) 75
- দুটিতেই 100
- দুটিতেই 0
(সহজ) display: flex; height: 200px container-এ একটি item, যার height লেখা নেই, ভেতরে এক লাইন লেখা। item কত উঁচু?
- 200px — ডিফল্ট
stretch - 0px
- এক লাইনের লেখার সমান
- 100px — অর্ধেক
(সহজ) navbar: body { margin: 0 }, 600px flex container-এ তিনটি 100px item, শেষটিতে margin-left: auto. শেষ item-এর বাঁ কিনারা কোথায়?
- 500px
- 200px
- 350px — মাঝখানে
- নতুন লাইনে, 0px
(মাঝারি) flex container-এ তিনটি item “১, ২, ৩”, তৃতীয়টিতে order: -1. পর্দায় ক্রম কী, আর Tab চাপলে (বা screen reader পড়লে) ক্রম কী?
- পর্দা ৩, ১, ২ · Tab ৩, ১, ২
- পর্দা ১, ২, ৩ · Tab ১, ২, ৩ — ঋণাত্মক order অবৈধ
- পর্দা ১, ২, ৩ · Tab ৩, ১, ২
- পর্দা ৩, ১, ২ · Tab ১, ২, ৩
(মাঝারি) display: flex container-এর ভেতরে একটি <span>, তাতে width: 100px; height: 40px. span কত বড় দেখাবে?
- 100px × 40px — flex item হয়ে span block হয়ে যায়
- 100px × container-এর পুরো উচ্চতা
- শুধু লেখার সমান — span inline
- কিছুই দেখাবে না
(মাঝারি) 800px flex container-এ একটি item: width: 100px; flex-basis: 200px; flex-shrink: 0;. item কত চওড়া?
- 100px — width জেতে
- 300px
- 800px
- 200px — flex-basis জেতে
(কঠিন) flex container-এ তিনটি item “ক”, “খ”, “গ” — কিন্তু “খ” আর “গ” আছে একটি <div class="w">-এর ভেতরে, যাতে display: contents. পর্দায় কী দেখাবে?
- দুটি item: “ক” আর একটি বাক্সে “খগ”
- তিনটি পাশাপাশি — খ আর গ সরাসরি flex item
- শুধু “ক” — .w-এর ভেতরটা লুকানো
- ক ওপরে, খ আর গ নিচে
লিখিত ৫(মাঝারি) 600px flex container-এ দুটি item, প্রথমটির width: 200px, দ্বিতীয়টি খালি। (ক) দুটিতেই flex: 1, (খ) দুটিতেই flex: auto. প্রতিটি ক্ষেত্রে চওড়া কত? flex: 1 আর flex: auto-এর পার্থক্য এক লাইনে লিখুন।
(ক) 300 · 300. (খ) 400 · 200. flex: 1 = 1 1 0% — basis 0, তাই width উপেক্ষিত, পুরো 600 সমান ভাগ। flex: auto = 1 1 auto — basis = width (200) আর খালি item-এর content (0). free space 600 − 200 = 400, সমান ভাগ +200 করে: 400 আর 200. এক লাইনে: flex: 1 সবাইকে সমান করে; flex: auto আগে প্রত্যেককে নিজের মাপ দেয়, তারপর বাকিটা সমান ভাগ করে। সমান কলাম চাইলে flex: 1 (সাথে min-width: 0), content অনুযায়ী ছড়ানো ট্যাব-বার চাইলে flex: auto. যাচাই: Edge-এ দুটি ক্ষেত্রই মেপে 300/300 আর 400/200 পাওয়া গেছে।
নিজে অনুমান করে দেখুন — তিন সারির flex হিসাব
তিনটি flex সারি: grow-এর অনুপাত, flex: 1/2-এর ভাগ, আর shrink-এর অনুপাত। প্রিভিউ দেখার আগে সাতটি চওড়া খাতায় লিখুন — স্ক্রিপ্ট নিচে মাপ ছাপবে।
<style>
.row { display: flex; width: 600px; margin-bottom: 8px; }
.row div { height: 30px; background: #c7d2fe; box-shadow: inset 0 0 0 1px #4338ca; }
.r1 div { width: 100px; }
.r1 .a { flex-grow: 1; } .r1 .b { flex-grow: 3; }
.r2 div { flex: 1; } .r2 .c { flex: 2; }
.r3 { width: 300px; }
.r3 .a { width: 400px; } .r3 .b { width: 200px; }
</style>
<div class="row r1"><div class="a">a</div><div class="b">b</div></div>
<div class="row r2"><div class="a">a</div><div class="b">b</div><div class="c">c</div></div>
<div class="row r3"><div class="a">a</div><div class="b">b</div></div>
<script>
(function m() {
if (!document.body.offsetWidth) return setTimeout(m, 50);
for (const r of document.querySelectorAll(".row"))
console.log(r.className, "→", [...r.children].map(d => d.getBoundingClientRect().width).join(" / "));
})();
</script>প্রিভিউতে তিনটি নীলচে সারি, নিচে তিনটি লাইনে মাপ। নিজের সংখ্যা মিলিয়ে উত্তর খুলুন।
ছাপা হয়: row r1 → 200 / 400 (basis 100 + 400-এর 1:3 ভাগ), row r2 → 150 / 150 / 300 (basis 0, 600-এর 1:1:2 ভাগ), row r3 → 200 / 100 (ঘাটতি 300, কাটা 400:200 = 2:1 অনুপাতে)। চেষ্টা করুন: .r3 .a-তে flex-shrink: 0 যোগ করুন — a থাকে পুরো 400 (300px-এর সারি থেকে বেরিয়ে), আর b নেমে আসে শুধু নিজের লেখা “b”-এর সমান চওড়ায় — কারণ min-width: auto তাকে তার content-এর নিচে নামতে দেয় না। তারপর .r1-এর দুই item-এর width 0 করে দিন — এবার ফল হয় 150 / 450, কারণ basis 0 হলে পুরো 600 সরাসরি 1:3-এ ভাগ।
নিজে অনুমান করে দেখুন — flex: 1 তবু সমান হয় না কেন
দুটি item, দুটিতেই flex: 1, container 300px. প্রথমটির ভেতরে একটি 400px চওড়া “ছবি”. প্রিভিউ দেখার আগে লিখুন: প্রথম item কত চওড়া হবে — 150, নাকি অন্য কিছু?
<style>
.row { display: flex; width: 300px; background: #eee; }
.row > div { flex: 1; box-shadow: inset 0 0 0 1px #888; }
.photo { width: 400px; height: 40px; background: #93c5fd; }
</style>
<div class="row">
<div class="a"><div class="photo">ছবি</div></div>
<div class="b">বিবরণ</div>
</div>
<script>
(function m() {
if (!document.body.offsetWidth) return setTimeout(m, 50);
const a = document.querySelector(".a").getBoundingClientRect().width;
console.log("a-এর চওড়া:", a, "| সারি থেকে বেরিয়েছে?", document.querySelector(".row").scrollWidth > 300);
})();
</script>প্রিভিউতে ধূসর সারি থেকে নীল ছবি ডানে বেরিয়ে গেছে কি না, আর “বিবরণ” কোথায় — দেখুন। নিচে একটি মাপ আর একটি true/false. অনুমান মিলিয়ে উত্তর খুলুন।
ছাপা হয় a-এর চওড়া: 400 | সারি থেকে বেরিয়েছে? true. flex item-এর ডিফল্ট min-width: auto মানে “content-এর min-content-এর নিচে নয়” — ভেতরের ছবি 400px, তাই a 400-এর কম হতেই পারে না; b চাপা পড়ে লেখার সমান সরু হয়ে সারির বাইরে। এটাই “flex: 1 দিলাম, তবু কলাম সমান হয় না / লম্বা URL পুরো লেআউট ঠেলে দেয়” বাগ (automatic minimum size). চেষ্টা করুন: .row > div-এ min-width: 0; যোগ করুন — এবার দুটিই 150, আর ছবি a-এর ভেতর থেকে উপচে পড়ে। min-width: 0-এর জায়গায় overflow: hidden দিলেও 150 / 150, এবার উপচে পড়া অংশ কাটা যায়।
৭ · CSS Grid — কয়টি কলাম, কোন ঘরে কে
Grid-এর প্রশ্নে দুটি হিসাব পরপর করুন। প্রথমে track-এর মাপ: container-এর চওড়া থেকে fixed track (px) আর gap বাদ দিন, বাকিটা fr-এর অনুপাতে ভাগ — তবে মনে রাখুন 1fr আসলে minmax(auto, 1fr), তাই content-এর min-content-এর নিচে নামে না। auto-fill/auto-fit-এ আগে গুনুন কয়টি track এঁটে যায়। তারপর item বসানো (auto-placement): ওপর-বাঁ থেকে সারি ধরে, প্রতিটি item প্রথম যে খালি জায়গায় পুরোটা এঁটে যায় সেখানে — পেছনে ফিরে গর্ত ভরাট হয় না, যদি না dense থাকে।
ঝালিয়ে নিন: পর্ব ২৭ · CSS Grid, পর্ব ২৮ · Grid গভীরে — template areas, auto-fit, minmax আর subgrid, পর্ব ২৯ · প্রচলিত লেআউট প্যাটার্ন.
(সহজ) width: 600px; gap: 20px; grid-template-columns: 200px 1fr 1fr;. তিন কলামের চওড়া কত?
- 200 · 200 · 200
- 200 · 190 · 190
- 200 · 180 · 180
- 180 · 180 · 180 (+ gap)
(সহজ) grid-template-columns: repeat(3, 1fr), কোনো সারি ঘোষণা নেই, ভেতরে ৭টি item. কয়টি সারি হবে, সপ্তম item কোথায়?
- ১টি সারি — সাতটি কলামে
- ৩টি সারি — সপ্তমটি তৃতীয় সারির প্রথম ঘরে
- ২টি সারি — সপ্তমটি দেখাবে না
- ৩টি সারি — সপ্তমটি পুরো সারি জুড়ে
(মাঝারি) width: 700px; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));, gap নেই, ৫টি item. কয়টি কলাম, প্রতিটি কত চওড়া?
- ৫টি কলাম · 140px
- ৪টি কলাম · 150px, ডানে 100px ফাঁকা
- ৫টি কলাম · 150px
- ৪টি কলাম · 175px
(মাঝারি) ৩ কলামের 600px grid-এ শিরোনাম-item grid-column: 1 / -1. সেটি কত চওড়া?
- 600px — প্রথম থেকে শেষ রেখা পর্যন্ত
- 200px — শুধু শেষ কলাম
- অবৈধ — ঋণাত্মক সংখ্যা
- 400px
(কঠিন) grid-template-areas: "a a" "a b" "c a"; — getComputedStyle-এ gridTemplateAreas কী দেবে?
- যেমন লেখা —
"a a" "a b" "c a" - শুধু বৈধ অংশ —
"a a" "a b" - একটি error message
none— অ-আয়তাকার area, পুরো declaration বাদ
(মাঝারি) ৩টি 100px কলাম, grid-template-areas: "head head head" "side . main". .m { grid-area: main } আর .h { grid-area: head } — HTML-এ .m আগে লেখা। .m কোথায়, .h কত চওড়া?
- .m প্রথম সারিতে (DOM-এ আগে বলে) · .h 100px
- অবৈধ —
.কোনো নাম নয় - .m দ্বিতীয় সারির শেষ ঘরে (বাঁ থেকে 200px) · .h 300px
- .m দ্বিতীয় সারির মাঝের ঘরে · .h 300px
(কঠিন) 600px grid, grid-template-columns: 1fr 1fr. প্রথম item-এর ভেতরে একটি 500px চওড়া বাক্স, দ্বিতীয়টিতে ছোট লেখা। দুই কলাম কত চওড়া?
- 300px · 300px — ভেতরের বাক্স উপচে পড়ে
- 500px · 100px
- 300px · 300px — বাক্স কেটে যায়
- 500px · 500px
(মাঝারি) দুটি grid item, দুটিতেই grid-area: 1 / 1 (একই ঘর), z-index নেই। কোনটি দেখা যাবে?
- কোনোটিই না
- প্রথমটি
- দুটি পাশাপাশি — grid নিজে সরিয়ে দেয়
- দ্বিতীয়টি — DOM-এ পরে
(কঠিন) grid-template-columns: repeat(3, 100px); grid-auto-columns: 50px;. একমাত্র item-এ grid-column: 5. getComputedStyle-এ gridTemplateColumns কী?
- ১০০ ১০০ ১০০-এর পরে দুটি 50px —
100px 100px 100px 50px 50px 100px 100px 100px 100px 100px100px 100px 100px— item বাদ পড়ে- item কলাম ১-এ চলে যায়
(সহজ) দুই কলামের grid-এ বাঁ item-এ height: 120px, ডান item-এ ছোট লেখা, height নেই। ডান item কত উঁচু?
- লেখার সমান
- 120px — সারির উচ্চতায় টানা
- 0px
- 60px — দুইয়ের গড়
নিজে অনুমান করে দেখুন — auto-fill বনাম auto-fit
দুটি 500px grid, দুটিতেই মাত্র দুটি item; একটিতে auto-fill, অন্যটিতে auto-fit. প্রিভিউ দেখার আগে লিখুন: প্রতিটিতে কয়টি track, item কত চওড়া?
<style>
.g { display: grid; width: 500px; margin-bottom: 10px; outline: 1px dashed #999; }
.fill { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.fit { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.g div { background: #bbf7d0; box-shadow: inset 0 0 0 1px #15803d; padding: 6px; }
</style>
<div class="g fill"><div>১</div><div>২</div></div>
<div class="g fit"><div>১</div><div>২</div></div>
<script>
(function m() {
if (!document.body.offsetWidth) return setTimeout(m, 50);
for (const g of document.querySelectorAll(".g")) {
const t = getComputedStyle(g).gridTemplateColumns.split(" ").map(v => Math.round(parseFloat(v)));
console.log(g.className, "→ track:", t.join(" / "));
}
})();
</script>প্রিভিউতে দুটি ড্যাশ-দাগের grid; একটিতে item ছোট, ডানে ফাঁকা — অন্যটিতে item ছড়ানো। নিচে track-এর মাপ। অনুমান মিলিয়ে উত্তর খুলুন।
ছাপা হয় g fill → track: 167 / 167 / 167 আর g fit → track: 250 / 250 / 0. 500px-এ 150-এর তিনটি track আঁটে, দুটি ক্ষেত্রেই। পার্থক্য খালি track-এ: auto-fill খালি তৃতীয় track রেখে দেয় (item 166.67px, ডানে একটি খালি কলাম), auto-fit খালি track-কে 0-তে গুটিয়ে দেয়, তাই 1fr দুটি item-কে 250px করে ছড়িয়ে দেয়। item তিনটি বা বেশি হলে দুটি একই আচরণ করে। চেষ্টা করুন: প্রথম grid-এ আরও তিনটি <div> যোগ করুন — track এখনো 167 × 3, আর বাকি item নিচের সারিতে। তারপর width 320px করুন — দুটিতেই 2টি track, item 160px.
নিজে অনুমান করে দেখুন — গর্ত আর dense
দুটি তিন-কলামের grid, একই পাঁচটি item; তৃতীয়টি (লাল) দুই কলাম জোড়া। দ্বিতীয় grid-এ dense. প্রিভিউ দেখার আগে দুটি grid-এর ছবি খাতায় আঁকুন — কোন ঘর খালি থাকবে?
<style>
.g { display: grid; grid-template-columns: repeat(3, 100px);
gap: 6px; margin-bottom: 12px; }
.g div { background: #fde68a; padding: 8px 0; text-align: center; }
.g .w { grid-column: span 2; background: #fca5a5; }
.dense { grid-auto-flow: dense; }
</style>
<div class="g">
<div>১</div><div>২</div><div class="w">৩</div><div>৪</div><div>৫</div>
</div>
<div class="g dense">
<div>১</div><div>২</div><div class="w">৩</div><div>৪</div><div>৫</div>
</div>প্রিভিউতে দুটি grid — একটিতে প্রথম সারির ডানে একটি সাদা ফাঁক, অন্যটিতে নেই। নিজের আঁকা ছবি মিলিয়ে উত্তর খুলুন।
প্রথম grid: সারি ১-এ ১, ২, খালি; সারি ২-এ ৩ (দুই ঘর), ৪; সারি ৩-এ ৫. দ্বিতীয় (dense): সারি ১-এ ১, ২, ৪; সারি ২-এ ৩ (দুই ঘর), ৫ — মোট দুই সারি। dense চোখের ক্রম বদলেছে (৪ এখন ৩-এর আগে), কিন্তু DOM বদলায়নি — Tab চাপলে ক্রম ১-২-৩-৪-৫ থাকে। যাচাই: Edge-এ প্রতিটি item-এর অবস্থান মেপে ঠিক এই ছবি পাওয়া গেছে। চেষ্টা করুন: প্রথম grid-এ “৪”-এর আগে আরেকটি এক-ঘরের <div>নতুন</div> বসান — সেটি দ্বিতীয় সারির তৃতীয় ঘরে যায়, “৪” নামে তৃতীয় সারিতে, আর প্রথম সারির গর্ত তবু খালি। অর্থাৎ dense ছাড়া auto-placement কখনো পেছনে ফেরে না।
৮ · রেসপন্সিভ আর আধুনিক CSS — media, container, variable, :has() আর nesting
এই ভাগের উত্তর প্রায়ই নির্ভর করে একটি শর্তের ওপর — viewport-এর চওড়া, container-এর চওড়া, ব্যবহারকারীর পছন্দ। তাই আগে শর্তটি লিখুন, তারপর দেখুন কোন rule “চালু”। চালু rule-গুলোর মধ্যে বিচার আবার সেই পুরোনো cascade: media query বা container query specificity বাড়ায় না — দুটি চালু rule-এর ওজন সমান হলে পরে লেখাটি জেতে। আর custom property-র প্রশ্নে মনে রাখুন: var() বসে computed-value-এর সময়, তাই ভুল মান “আগের declaration-এ ফেরে না” — এটাই IACVT.
ঝালিয়ে নিন: পর্ব ৩০ · রেসপন্সিভ ডিজাইন, পর্ব ৩১ · Media query আর container query, পর্ব ৩৩ · CSS variable, পর্ব ৩৪ · Pseudo-class আর pseudo-element, পর্ব ৩৫ · আধুনিক CSS, পর্ব ৩৬ · Dark mode আর থিম, পর্ব ৩৭ · একেবারে নতুন CSS, পর্ব ৪৮ · @supports আর progressive enhancement. (রেসপন্সিভ ছবির srcset-এ কোন ফাইল আসবে তা ব্রাউজারের সিদ্ধান্ত — পর্দার ঘনত্ব, ক্যাশ, নেটওয়ার্ক — তাই সেটি “অনুমান” প্রশ্ন নয়; পর্ব ৩২ দেখুন।)
(সহজ) viewport ঠিক 600px চওড়া। p { color: black } @media (min-width: 600px) { p { color: red } }. রং কী?
- কালো — 600-এর চেয়ে বড় হতে হবে
- লাল — min-width শর্তে সমান হলেও চলে
- কালো — বাইরের rule আগে
- দুটি পালাক্রমে
(মাঝারি) viewport 1000px. দুই অনুচ্ছেদ .a আর .b — দুটির query একই, শুধু লেখার ক্রম উল্টো। রং কী?
@media (min-width: 600px) { .a { color: red } }
@media (min-width: 900px) { .a { color: blue } }
@media (min-width: 900px) { .b { color: blue } }
@media (min-width: 600px) { .b { color: red } }
- দুটিই নীল — 900-এর query বেশি নির্দিষ্ট
- দুটিই লাল — ছোট query আগে মেলে
- .a লাল · .b নীল
- .a নীল · .b লাল — পরে লেখা জেতে
(মাঝারি) viewport 1200px. .wrap { container-type: inline-size; width: 400px }, ভেতরে .card. @container (min-width: 500px) { .card { color: red } }. রং কী?
- কালো — .wrap মাত্র 400px
- কালো — container query অবৈধ
- card-এর চওড়ার ওপর নির্ভর করে
- লাল — viewport 1200 > 500
(কঠিন) .wrap { container-type: inline-size; width: 400px }. @container (min-width: 300px) { .wrap { background: red } .wrap p { color: red } }. কী কী লাল হবে?
- .wrap-এর পটভূমি আর p — দুটিই
- শুধু ভেতরের p-এর লেখা
- শুধু .wrap-এর পটভূমি
- কিছুই না
(কঠিন) .row { display: flex }-এর একমাত্র সন্তান .wrap { container-type: inline-size } — width লেখা নেই, ভেতরে লেখা আছে। .wrap কত চওড়া?
- লেখার সমান
- পুরো সারির চওড়া
- 0px — size containment content-এর মাপ উপেক্ষা করে
- container-type flex item-এ কাজ করে না, তাই লেখার সমান
(কঠিন) body { color: navy } :root { --size: 20px } p { color: red; color: var(--size); }. p-এর রং কী?
- navy — IACVT, তাই parent থেকে উত্তরাধিকার
- কালো — initial মান
- লাল — দ্বিতীয়টি অবৈধ, তাই প্রথমটি থাকে
- একটি ধূসর রং
(কঠিন) :root { --n: 10 } p { margin-top: var(--n)px; margin-left: calc(var(--n) * 1px); }. p-এর margin-top আর margin-left কত? (p-এর ডিফল্ট margin 16px)
- 10px · 10px
- 0px · 0px
- 16px · 10px
- 0px · 10px
(মাঝারি) .card:has(img) { outline: 2px solid red }. কার্ড .a-তে একটি <img>, কার্ড .b-তে শুধু লেখা। কোনটিতে outline?
- শুধু .a — যার ভেতরে img আছে
- দুটিতেই
- কোনোটিতে না — :has() অবৈধ
- ছবিতে — কার্ডে নয়
(কঠিন) native CSS nesting. তিনটি p-তে class: .a = card (একটি .title-এর ভেতরে), .b = card active, .c = card. রং কী?
.card {
color: black;
.title & { color: red; }
&.active { color: blue; }
}
- .a কালো · .b নীল · .c কালো — .title & মানে .card .title
- .a লাল · .b নীল · .c কালো
- সবগুলো কালো — nesting শুধু Sass-এ চলে
- .a লাল · .b কালো · .c কালো — &.active মানে .card .active
(মাঝারি) #nav { a { color: red } } আর পরে .menu a { color: blue }. লিংকটি <div id="nav" class="menu">-এর ভেতরে। রং কী?
- নীল — পরে লেখা
- লাল — nested rule আসলে
#nav a - নীল — nested rule-এর ওজন কম
- কালো — & ছাড়া nesting অবৈধ
(মাঝারি) p { margin: 0; margin-inline-start: 20px; }. একটি p-তে dir="rtl" (যেমন আরবি বা উর্দু লেখা)। সেই p-এর বাস্তব margin কোন দিকে?
- ডানে 20px — rtl-এ লেখা শুরু ডান থেকে
- দুই দিকে 20px
- বাঁয়ে 20px — inline-start সবসময় বাঁ
- কোথাও না — logical property অবৈধ
(সহজ) তিনটি অনুচ্ছেদ .a, .b, .c. কোনগুলো লাল হবে?
@supports (display: grid) { .a { color: red } }
@supports (display: frobnicate) { .b { color: red } }
@supports not (display: frobnicate) { .c { color: red } }
- তিনটিই
- .a আর .c
- শুধু .a
- .a আর .b
লিখিত ৬(মাঝারি) h1 { font-size: clamp(16px, 4vw, 24px) } — viewport 320px, 500px আর 1000px চওড়া হলে font-size কত? কোন চওড়ার পর থেকে শিরোনাম আর বড় হয় না?
320px-এ 16px, 500px-এ 20px, 1000px-এ 24px. 4vw = viewport-এর 4%: 320-এ 12.8 → নিচের সীমা 16 বসে; 500-এ 20 → সীমার ভেতরে; 1000-এ 40 → ওপরের সীমা 24 বসে। শিরোনাম বাড়া থামে যেখানে 4vw = 24px, অর্থাৎ viewport 600px-এ; নিচের সীমা খাটে 400px-এর নিচে (4vw = 16 যখন viewport 400). তাই 400 থেকে 600-এর মধ্যে লেখা মসৃণভাবে বাড়ে — একেই বলে fluid typography. একটি অ্যাক্সেসিবিলিটি সতর্কতা: শুধু vw দিলে ব্যবহারকারী ব্রাউজারে zoom বা বড় লেখা বেছে নিলেও লেখা বড় হয় না; তাই মাঝের মানে rem মেশানো ভালো, যেমন clamp(1rem, 0.8rem + 1.5vw, 1.5rem) (পর্ব ৩৫, ৪৫)। (যাচাই: Edge-এ তিন চওড়ায় মাপা হয়েছে 16, 20, 24px.)
নিজে অনুমান করে দেখুন — গোনা আর আঁকা লেখা
বাজারের একটি তালিকা। প্রিভিউ দেখার আগে লিখুন: “চাল” আর “ডাল”-এর কোনটি লাল, কোনটির পেছনে হলুদ? চারটি সবজির কোনগুলো মোটা? আর স্ক্রিপ্ট প্রথম দামের textContent হিসেবে কী ছাপবে?
<style>
p:nth-child(2) { color: crimson; }
p:nth-of-type(2) { background: #fef08a; }
li:nth-child(odd) { font-weight: bold; }
.price::before { content: "৳ "; color: green; }
</style>
<div>
<h3>আজকের বাজার</h3>
<p class="price">চাল ৭৫</p>
<p class="price">ডাল ১৩০</p>
</div>
<ul><li>আলু</li><li>পেঁয়াজ</li><li>রসুন</li><li>আদা</li></ul>
<script>
console.log("textContent:", document.querySelector(".price").textContent);
</script>প্রিভিউতে দুটি দাম — সামনে সবুজ “৳” — আর চারটি সবজি; নিচে একটি লাইন। অনুমান মিলিয়ে উত্তর খুলুন।
“চাল ৭৫” লাল (div-এর দ্বিতীয় সন্তান), “ডাল ১৩০”-এর পেছনে হলুদ (দ্বিতীয় p). আলু আর রসুন মোটা (১ম ও ৩য়)। ছাপা হয় textContent: চাল ৭৫ — সবুজ “৳ ” পর্দায় আছে, DOM-এ নেই। চেষ্টা করুন: <h3> মুছে দিন — এবার “ডাল” লাল ও হলুদ দুটিই, কারণ সে দ্বিতীয় সন্তানও, দ্বিতীয় p-ও। তারপর li:nth-child(odd)-কে li:nth-child(odd of :not(:first-child)) লিখুন — নতুন “of S” syntax (সব আধুনিক ব্রাউজারে চলে) প্রথম আইটেম বাদ দিয়ে বাকিদের মধ্যে গোনে: পেঁয়াজ আর আদা মোটা হয়।
নিজে অনুমান করে দেখুন — custom property-র চার ফাঁদ
চারটি অনুচ্ছেদ। প্রিভিউ দেখার আগে প্রতিটির রং আর বাঁ margin লিখুন। সাবধান: দুটিতে var() এমনভাবে লেখা, যা ব্রাউজার “বুঝে নেয় না”।
<style>
:root { --brand: teal; --gap: 12; --size: 20px; }
.card { --brand: crimson; }
p { color: var(--brand); }
.a { margin-left: calc(var(--gap) * 1px); }
.b { margin-left: var(--gap)px; }
.c { color: red; color: var(--size); }
.d { color: var(--nope, darkorange); }
</style>
<p class="a">ক</p>
<div class="card"><p class="b">খ</p></div>
<p class="c">গ</p>
<p class="d">ঘ</p>
<script>
for (const p of document.querySelectorAll("p")) {
const s = getComputedStyle(p);
console.log(p.className, s.color, s.marginLeft);
}
</script>প্রিভিউতে চারটি অক্ষর, চার রকম বা কম রকম রঙে; নিচে চারটি লাইন। নিজের অনুমান মিলিয়ে উত্তর খুলুন।
ছাপা হয়: a rgb(0, 128, 128) 12px · b rgb(220, 20, 60) 0px · c rgb(0, 0, 0) 0px · d rgb(255, 140, 0) 0px. ক teal আর 12px (calc দিয়ে একক জোড়া)। খ crimson (.card-এর --brand), কিন্তু var(--gap)px অবৈধ — margin 0. গ লাল নয়, কালো: var(--size) রং নয় (IACVT), তাই body থেকে উত্তরাধিকারে কালো। ঘ কমলা — --nope নেই, fallback বসেছে। চেষ্টা করুন: :root-এ --size: green লিখুন — গ সবুজ হয়। আর .card-এ --gap: 30 যোগ করে .b-কে calc(var(--gap) * 1px) লিখুন — খ সরে যায় 30px.
৯ · মোশন, ইফেক্ট আর SVG — চেহারা বদলায়, লেআউট বদলায় না
এই ভাগের মূল নিয়ম একটি: transform, opacity, filter, clip-path — এগুলো paint ধাপের জিনিস। বাক্সটি পর্দায় সরে, ঘোরে, স্বচ্ছ হয়, কেটে যায় — কিন্তু layout-এ তার জায়গা আর মাপ একই থাকে, আশপাশের element নড়ে না। তবে চোখে না দেখা গেলেও বাক্সটি ক্লিক ধরতে পারে কি না (hit-testing), আর নতুন stacking context বা containing block তৈরি হলো কি না — এই দুটি প্রশ্ন আলাদা করে করুন। Animation-এর প্রশ্নে জিজ্ঞেস করুন: শেষ হওয়ার পরে মান কোথায় থাকে (fill-mode), আর delay ঋণাত্মক হলে animation কোথা থেকে শুরু।
ঝালিয়ে নিন: পর্ব ৩৮ · Transition, পর্ব ৩৯ · Keyframe animation, পর্ব ৪০ · Transform, পর্ব ৪১ · filter, blend mode, clip-path আর mask, পর্ব ৪২ · স্ক্রল ইফেক্ট, পর্ব ৪৩ · ফর্ম স্টাইলিং, পর্ব ৪৪ · SVG আর আইকন, পর্ব ৪৫ · অ্যাক্সেসিবল CSS, পর্ব ৪৯ · পারফরম্যান্স.
(সহজ) body { margin: 0 }. একটি 50px উঁচু বাক্সে transform: translateX(100px), তার নিচে আরেকটি div. প্রথম বাক্সের offsetLeft, getBoundingClientRect().left আর নিচের div-এর top কত?
- 100 · 100 · 50
- 0 · 100 · 50
- 0 · 0 · 50
- 0 · 100 · 0 — নিচের div ওপরে উঠে আসে
(মাঝারি) .k { width: 100px; height: 40px; transform: scale(2); }. offsetWidth আর getBoundingClientRect().width কত?
- 100 · 200
- 200 · 200
- 100 · 100
- 100 · 102
(মাঝারি) @keyframes go { to { opacity: .2 } }. .a { animation: go .1s }, .b { animation: go .1s forwards }. animation শেষ হওয়ার পরে দুটির opacity কত?
- দুটিই 0.2
- .a 1 · .b 0.2
- দুটিই 1
- .a 0.2 · .b 1
(কঠিন) @keyframes mv { from { transform: translateX(0) } to { transform: translateX(100px) } }, আর .k { animation: mv 10s linear -5s paused; }. পাতা খোলার মুহূর্তে বাক্সটি কোথায়?
- 0px — paused, তাই শুরুতেই
- animation বাতিল — ঋণাত্মক delay অবৈধ
- 100px
- 50px — অর্ধেক পথে থেমে
(মাঝারি) একটি বাটনের ওপরে পুরোপুরি ঢাকা দুটি স্তর: প্রথম ক্ষেত্রে opacity: 0, দ্বিতীয় ক্ষেত্রে visibility: hidden. কোন ক্ষেত্রে ক্লিক নিচের বাটনে পৌঁছায়?
- দুই ক্ষেত্রেই
- কোনো ক্ষেত্রেই না
- শুধু visibility: hidden-এ
- শুধু opacity: 0-এ
(কঠিন) 200 × 200px লাল বাক্সে clip-path: circle(50%). বাক্সের একদম কোণে (বৃত্তের বাইরে) আর কেন্দ্রে ক্লিক করলে কে ক্লিক পাবে?
- দুই জায়গাতেই লাল বাক্স
- দুই জায়গাতেই নিচের parent
- কোণে নিচের parent · কেন্দ্রে লাল বাক্স
- কোণে লাল বাক্স · কেন্দ্রে parent
(মাঝারি) <svg width="200" height="100" viewBox="0 0 100 100"><circle cx="50" cy="50" r="50"/></svg>. বৃত্তটি পর্দায় কত বড়, svg-এর বাঁ কিনারা থেকে কত দূরে শুরু?
- 200 × 100-এর ডিম্বাকার, বাঁ কিনারা থেকেই
- 100px ব্যাস, বাঁ কিনারা থেকেই
- 200px ব্যাস, ওপর-নিচ কেটে
- 100px ব্যাস, বাঁ থেকে 50px দূরে — মাঝখানে
(সহজ) button { color: crimson }, আর বাটনের ভেতরে inline SVG আইকন, যার path-এ fill="currentColor". আইকনের রং কী?
- কালো — SVG-র ডিফল্ট fill
- crimson — বাটনের লেখার রং
- অদৃশ্য — currentColor অবৈধ
- নীল — SVG বাইরের CSS পায় না
(কঠিন) ধূসর parent-এ transform: scale(1) (চোখে কোনো বদল নেই), position বা z-index নেই। ভেতরে লাল child position: absolute; z-index: -1. লাল কি দেখা যাবে?
- না — parent-এর পটভূমির নিচে
- না — scale(1) উপেক্ষিত
- না — ঋণাত্মক z-index অবৈধ
- হ্যাঁ — transform stacking context বানিয়েছে
লিখিত ৭(কঠিন) body { margin: 0 }. .p { filter: blur(0); margin: 60px; }-এর ভেতরে .k { position: fixed; top: 0; left: 0 }. .k কোথায় বসবে? transform ছাড়া আর কোন কোন property একই কাণ্ড ঘটায়, আর কীভাবে এড়াবেন?
.k বসে (60, 60) — .p-এর কোণে, viewport-এর নয়। fixed-এর containing block সাধারণত viewport, কিন্তু কোনো ancestor-এ এগুলোর কোনোটি থাকলে সেই ancestor-ই containing block হয়ে যায়: transform বা translate/rotate/scale (none ছাড়া), perspective, filter (none ছাড়া — blur(0)-ও), backdrop-filter, contain: paint/layout, আর will-change-এ এদের কোনোটির নাম। ফলে “sticky হেডার” বা “ভাসমান chat বাটন” .p-এর সাথে স্ক্রল করে। এড়ানোর উপায়: fixed element-কে এমন জায়গায় রাখুন, যার কোনো ancestor-এ এগুলো নেই — সাধারণত body-র সরাসরি সন্তান; মডালের জন্য <dialog> বা popover, যা top layer-এ যায় এবং এসব ancestor-এর প্রভাবমুক্ত (পর্ব ১১)। DevTools-এ সন্দেহ হলে ancestor-দের Computed-এ transform/filter খুঁজুন। যাচাই: Edge-এ .k-এর getBoundingClientRect দেয় left 60, top 60.
নিজে অনুমান করে দেখুন — transform-এর ক্রম
ড্যাশ-দাগের বাক্সটি আসল জায়গা (transform নেই)। লাল আর নীল বাক্সে একই দুটি function, ক্রম উল্টো। প্রিভিউ দেখার আগে খাতায় আঁকুন: দুটি কোথায় যাবে? স্ক্রিপ্ট stage-এর সাপেক্ষে বাঁ-ওপরের কোণ ছাপবে।
<style>
.stage { position: relative; height: 230px; background: #f1f5f9; }
.k { position: absolute; top: 60px; left: 60px; width: 60px; height: 30px; }
.ghost { outline: 2px dashed #64748b; }
.a { background: #fca5a5; transform: translateX(100px) rotate(90deg); }
.b { background: #93c5fd; transform: rotate(90deg) translateX(100px); }
</style>
<div class="stage">
<div class="k ghost"></div>
<div class="k a">a</div>
<div class="k b">b</div>
</div>
<script>
(function m() {
if (!document.body.offsetWidth) return setTimeout(m, 50);
const s = document.querySelector(".stage").getBoundingClientRect();
for (const c of ["a", "b"]) {
const r = document.querySelector("." + c).getBoundingClientRect();
console.log(c, "→ বাঁ:", Math.round(r.left - s.left), "ওপর:", Math.round(r.top - s.top),
"| offsetLeft:", document.querySelector("." + c).offsetLeft);
}
})();
</script>প্রিভিউতে একটি ড্যাশ-দাগের বাক্স, একটি লাল আর একটি নীল খাড়া বাক্স; নিচে দুই লাইন। অনুমান মিলিয়ে উত্তর খুলুন।
ছাপা হয় a → বাঁ: 175 ওপর: 45 | offsetLeft: 60 আর b → বাঁ: 75 ওপর: 145 | offsetLeft: 60. লাল: আগে ডানে 100px, তারপর নিজের কেন্দ্রে খাড়া — ডানে সরে খাড়া হয়েছে। নীল: আগে খাড়া, তখন তার x-অক্ষ নিচের দিকে, তাই translateX(100px) তাকে নিচে নামায়। দুটির offsetLeft-ই 60 — layout-এ কেউ নড়েনি। চেষ্টা করুন: .b-তে transform-origin: top left; যোগ করুন — ঘোরার কেন্দ্র বদলায়, নীল বাক্স বাঁয়ে আর একটু নিচে সরে যায় (বাঁ 30, ওপর 160). তারপর .a-র transform মুছে translate: 100px; rotate: 90deg; লিখুন — আলাদা (individual) transform property-র নিজস্ব নির্দিষ্ট ক্রম আছে (translate → rotate → scale), তাই ফল আগের লাল বাক্সের মতোই।
১০ · AI-এর যুগে — রেন্ডার করা পাতাই শেষ বিচারক
“এই CSS-এ বাক্সটি কত চওড়া হবে?” — AI টুল এ প্রশ্নের উত্তর দেয় আত্মবিশ্বাসের সাথে, আর প্রায়ই ভুল। কারণ সে ব্রাউজার চালায় না; সে অনুমান করে লাখো ব্লগ আর পুরোনো Stack Overflow উত্তর থেকে, যেগুলোর অনেকটাই flexbox-এর আগের যুগের, বা “id = ১০০ পয়েন্ট”-এর মতো সরলীকরণ। আপনার শক্তি হলো আপনি দুই মিনিটে একটি পরীক্ষা লিখে ব্রাউজারকে জিজ্ঞেস করতে পারেন। এই পাতার প্রতিটি উত্তর ঠিক এভাবেই যাচাই করা।
AI সাধারণত যেখানে রেন্ডারের ফল ভুল বলে
| AI যা বলে | আসলে যা হয় | কীভাবে যাচাই |
|---|---|---|
| “z-index: 9999 দিলে সবার ওপরে যাবে” | stacking context-এর ভেতরে আটকা থাকতে পারে; static element-এ কাজই করে না | elementFromPoint(), DevTools-এর Layers প্যানেল |
| “দুই margin যোগ হয়ে 50px ফাঁক” | normal flow-তে মিশে বড়টি থাকে — কিন্তু flex/grid-এ যোগ হয় | getBoundingClientRect() দিয়ে দুই বাক্সের মাঝের দূরত্ব |
| “flex: 1 বা 1fr দিলে সব কলাম সমান” | min-content-এর নিচে নামে না — ভেতরে বড় কিছু থাকলে অসমান | ভেতরে একটি 500px বাক্স রেখে মেপে দেখা |
| “specificity: id 100, class 10, element 1 পয়েন্ট” | তিন ঘরের তুলনা; ১১টি class একটি id-কে হারায় না | DevTools-এ selector-এর ওপর মাউস রাখলে specificity দেখায় |
| “var() অবৈধ হলে আগের মান থাকবে” | IACVT — উত্তরাধিকার বা initial মান | getComputedStyle() |
| “ভুল HTML-এ ব্রাউজার error দেবে” বা “যেমন লেখা তেমনই DOM” | parser নির্দিষ্ট নিয়মে মেরামত করে — DOM আলাদা হয় | Elements প্যানেল বনাম View Source; validator.w3.org |
AI-কে দিয়ে নতুন অনুশীলনের প্রশ্ন বানানো খুব কাজের — শুধু তার দেওয়া উত্তরকে প্রমাণ নয়, প্রস্তাব হিসেবে ধরুন। এভাবে চাইতে পারেন:
AI-এর দেওয়া প্রশ্ন বা উত্তর হাতে পেলে — যাচাইয়ের চেকলিস্ট
পরীক্ষা ও ইন্টারভিউতে এ ধরনের প্রশ্ন সাধারণত এই চেহারায় আসে:
- “এই CSS-এ div-টির মোট চওড়া কত?” — box-sizing আগে বলুন, তারপর যোগফল লিখে দেখান: 5 + 20 + 200 + 20 + 5.
- “কোন রং দেখাবে, কেন?” — শুধু রং নয়, cascade-এর কোন ধাপে ফয়সালা হলো তা বলুন: “দুটির specificity (0,1,0) সমান, তাই পরে লেখাটি।”
- “এই মডাল হেডারের নিচে চাপা পড়ছে কেন?” — stacking context খুঁজুন: কোন ancestor-এ z-index, opacity বা transform আছে।
- “flex: 1 দিলাম, তবু কলাম সমান হচ্ছে না কেন?” — min-width: auto; সমাধান min-width: 0 বা overflow: hidden.
- “ব্রাউজার এই ভুল HTML কীভাবে দেখাবে?” — বলুন parser কোন নিয়মে মেরামত করে (p-এর স্বয়ংক্রিয় বন্ধ, tbody, foster parenting), আর বলুন validator এটি ধরবে।
সব প্রশ্নের উত্তর দেওয়া শেষ হলে এখানে আপনার প্রথম চেষ্টার স্কোর দেখাবে:
ভাবনার প্রশ্ন · নিয়মগুলোর পেছনের গল্প
যে নিয়মগুলো সবচেয়ে বেশি ভুল উত্তর তৈরি করে, সেগুলো কেন এমন — পাঁচটি বড় প্রশ্ন। প্রতিটি নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।
প্র ০১HTML parser ভুল HTML-কে ক্ষমা করে কেন? XML-এর মতো কঠোর হলে — একটি ভুলেই পাতা বন্ধ — কি ভালো হতো না?
এই পরীক্ষা ওয়েবে একবার সত্যিই হয়েছিল। ২০০০-এর দশকের শুরুতে W3C-র লক্ষ্য ছিল HTML-কে XML-এর নিয়মে আনা — XHTML. XHTML-কে যদি সত্যিকারের XML হিসেবে পাঠানো হয় (application/xhtml+xml), ব্রাউজার XML parser চালায়: একটি বন্ধ না করা ট্যাগ বা একটি ভুল & — পুরো পাতার জায়গায় শুধু একটি error বার্তা। Firefox-এর সেই হলুদ error পাতাকে ডেভেলপাররা মজা করে “yellow screen of death” বলতেন।
বাস্তবে প্রায় কেউই এই কঠোরতা মেনে নেয়নি। বেশিরভাগ “XHTML” সাইট আসলে সাধারণ HTML হিসেবেই পাঠানো হতো, ফলে ব্রাউজার পুরোনো ক্ষমাশীল parser-ই চালাত। কারণটা সহজ: পাতার লেখা আসে অনেক উৎস থেকে — CMS, বিজ্ঞাপন, ব্যবহারকারীর মন্তব্য। একজনের একটি ভুল ট্যাগে পুরো সংবাদপত্রের সাইট বন্ধ হয়ে যাওয়া ব্যবসা হিসেবে অচল।
সমস্যা ছিল অন্য জায়গায়: প্রতিটি ব্রাউজার ভুল HTML নিজের মতো করে মেরামত করত, তাই একই ভাঙা পাতা চার ব্রাউজারে চার রকম DOM দিত। ২০০৪ সালে Apple, Mozilla আর Opera-র লোকজন মিলে WHATWG গঠন করেন, আর Ian Hickson-এর নেতৃত্বে HTML5-এর স্পেসিফিকেশনে প্রথমবার পুরো parsing algorithm লেখা হয় — প্রতিটি ভুলের জন্য কী করতে হবে, ধাপে ধাপে। বিদ্যমান ব্রাউজারের আচরণ খুঁটিয়ে দেখে, যতটা সম্ভব সাইট না ভেঙে। “Adoption agency algorithm”, foster parenting, </br>-কে br বানানো — এসবই সেই কাজের ফল। ২০০৯ সালে W3C XHTML 2-এর কাজ বন্ধ করে দেয়।
ফল: আজ ভুল HTML-ও সব আধুনিক ব্রাউজারে একই DOM দেয়, আর এই পাতার parsing প্রশ্নের উত্তর তাই নির্দিষ্ট। তবু “ক্ষমা” মানে “ঠিক” নয় — validator সব parse error দেখায়, আর screen reader বা search engine-এর কাছে মেরামত-করা কাঠামো আপনার উদ্দেশ্যের চেয়ে আলাদা হতে পারে।
মূল উপলব্ধি: ওয়েব কঠোরতার চেয়ে টিকে থাকাকে বেছে নিয়েছে, কিন্তু “যেমন খুশি” নয় — ক্ষমার নিয়মগুলোও এখন মান-নির্দিষ্ট। তাই ভাঙা HTML-এর ফলও মাথায় হিসাব করা যায়।
প্র ০২উল্লম্ব margin মিশে যায় কেন? এটা কি CSS-এর একটি নকশাগত ভুল, নাকি ইচ্ছাকৃত?
ইচ্ছাকৃত — এবং মূল লক্ষ্যটা বুঝলে নিয়মটা স্বাভাবিক লাগে। CSS-এর জন্ম ১৯৯০-এর দশকে, যখন ওয়েব মানে ছিল ডকুমেন্ট: শিরোনাম, অনুচ্ছেদ, তালিকা, উদ্ধৃতি। ছাপাখানার টাইপোগ্রাফিতে দুই অনুচ্ছেদের মাঝে ফাঁক একটি নির্দিষ্ট মাপ, আর শিরোনামের আগে বেশি ফাঁক — কিন্তু শিরোনামের পরের অনুচ্ছেদের আগে দ্বিগুণ ফাঁক কেউ চায় না।
margin collapse ঠিক এই চিন্তা থেকে: প্রতিটি element-এর margin মানে “আমার আশপাশে অন্তত এতটুকু জায়গা চাই”। দুটি অনুচ্ছেদের প্রত্যেকে 1em চাইলে মাঝে 1em-ই যথেষ্ট — দুজনের দাবিই পূরণ হলো। h2 যদি বলে “আমার ওপরে 2em”, আর তার আগের অনুচ্ছেদ বলে “আমার নিচে 1em”, তাহলে মাঝে 2em — বড় দাবিটি। লেখককে প্রতিটি জোড়ার জন্য আলাদা হিসাব করতে হয় না। parent-child collapse-এর যুক্তিও একই: একটি div-এর প্রথম অনুচ্ছেদের ওপরের margin আসলে “অনুচ্ছেদের আগে ফাঁক” — div-এর কোনো দেয়াল (border, padding) না থাকলে সেই ফাঁক div-এর বাইরে প্রকাশ পাওয়াই ডকুমেন্টের দৃষ্টিতে সঠিক।
সমস্যা তৈরি হলো যখন ওয়েব হয়ে উঠল অ্যাপ্লিকেশন, আর আমরা div দিয়ে কার্ড, প্যানেল, কম্পোনেন্ট বানাতে লাগলাম — যাদের নিজস্ব সীমানা থাকা উচিত। তাই পরের দিকের layout-এ নিয়ম আলাদা: flex আর grid item-এর margin কখনো মেশে না; display: flow-root একটি নতুন block formatting context দিয়ে collapse আটকায়। আধুনিক কম্পোনেন্ট-ভাবনায় অনেকে আর margin-ই দেন না — parent-এ gap দিয়ে ফাঁক, যা কখনো মেশে না, কখনো বাইরে গলে না। Safari-তে margin-trim নামে একটি property আছে, যা container-এর কিনারার margin ছেঁটে দেয় — তবে এটি এখনো Baseline নয়।
মূল উপলব্ধি: margin collapse ডকুমেন্টের জন্য নকশা করা একটি সুবিধা, যা কম্পোনেন্টের জগতে ফাঁদ হয়ে দাঁড়িয়েছে। প্রশ্নে দেখুন বাক্সটি কোন জগতে আছে — normal flow (মেশে) নাকি flex/grid (মেশে না)।
প্র ০৩z-index পুরো পাতায় এক তালিকায় তুলনা হয় না কেন? stacking context না থাকলে কী সমস্যা হতো?
z-index যদি পুরো পাতায় এক তালিকা হতো, তাহলে প্রতিটি element-এর ক্রম নির্ভর করত পাতার অন্য সব element-এর ওপর। একটি কম্পোনেন্ট — ধরুন একটি dropdown — ভেতরের অংশগুলো ঠিকমতো সাজাতে z-index দিল 1, 2, 3; পাতার আরেক কোণে অন্য ডেভেলপারের লেখা কোনো ব্যানারের z-index 2 হলে dropdown-এর অংশগুলো ব্যানারের ফাঁকে ফাঁকে ঢুকে যেত। কম্পোনেন্ট কখনো “বন্ধ” হতো না।
Stacking context সেই খাম। একটি element context তৈরি করলে তার পুরো subtree একটি একক স্তর হিসেবে আঁকা হয় — ভেতরে যত z-index থাকুক, বাইরের দুনিয়া দেখে শুধু খামের নিজের z-index. CSS 2.1-এর একটি পরিশিষ্টে (Appendix E) আঁকার পুরো ক্রম লেখা আছে: পটভূমি, ঋণাত্মক z-index, block, float, inline, তারপর positioned — প্রতিটি context-এর ভেতরে এই একই ক্রম, পুনরাবৃত্তভাবে।
opacity বা transform কেন context তৈরি করে, তার কারণ আঁকার কৌশলে। opacity: 0.5 মানে পুরো element আর তার সন্তানদের একসাথে একটি ছবিতে এঁকে তারপর সেই ছবিকে আধা-স্বচ্ছ করা — প্রতিটি সন্তানকে আলাদা আধা-স্বচ্ছ করলে ওপর-নিচের অংশ দুবার রং পেত, ভুল দেখাত। “একসাথে এঁকে তারপর মেশানো” মানেই একটি আলাদা স্তর — বাইরের কোনো element তার মাঝখানে ঢুকতে পারে না। transform, filter, mask-এর ক্ষেত্রেও একই; আধুনিক ব্রাউজার এসব স্তরকে GPU-তে আলাদা compositing layer হিসেবে রাখতে পারে, তাই animation মসৃণ হয়।
এই নিয়মের দাম হলো “z-index: 9999 তবু নিচে” বাগ। এর আধুনিক সমাধান হলো top layer: <dialog>-এর showModal() আর popover API দিয়ে খোলা element পাতার সব stacking context-এর বাইরে, একদম ওপরের আলাদা স্তরে যায় — কোনো z-index লাগে না (পর্ব ১১)।
মূল উপলব্ধি: stacking context ইচ্ছাকৃত encapsulation আর দ্রুত আঁকার কৌশল। z-index-এর প্রশ্নে সংখ্যা তুলনার আগে সবসময় খাম খুঁজুন।
প্র ০৪flex item-এর min-width: auto আর grid-এর 1fr = minmax(auto, 1fr) — দুটিই content-কে ছোট হতে দেয় না। CSS কেন এমন “একগুঁয়ে”?
CSS-এর নকশায় একটি পুরোনো নীতি আছে: ডেটা হারানো এড়াও। লেখকের ভুল হিসাবের কারণে লেখা বা ছবি চুপচাপ অদৃশ্য হয়ে যাওয়ার চেয়ে উপচে পড়া ভালো — কারণ উপচে পড়া চোখে পড়ে, ঠিক করা যায়; লুকানো content কেউ টেরই পায় না। এজন্য overflow-এর ডিফল্ট visible, আর alignment-এ “safe” ধারণা আছে, যাতে কেন্দ্রে আনতে গিয়ে content স্ক্রিনের বাইরে, যেখানে স্ক্রল করেও পৌঁছানো যায় না, চলে না যায়।
Flexbox-এর শুরুর দিকের নিয়মে flex item-এর ন্যূনতম মাপ ছিল 0 — ফলে item অবাধে সংকুচিত হতো, আর ভেতরের লম্বা শব্দ বা ছবি পাশের item-এর ওপর উঠে যেত, লেখা একে অপরের ওপর চাপা পড়ত। স্পেসিফিকেশনের পরের সংশোধনে আসে automatic minimum size: min-width: auto flex item-এর জন্য মানে “content-এর min-content-এর নিচে নয়” (overflow visible থাকলে)। Grid-এ 1fr-এর নিচের সীমা auto রাখা হয় একই যুক্তিতে।
এই সিদ্ধান্তের দাম আমরা সবাই দিয়েছি: “flex: 1 দিলাম, তবু কলাম সমান নয়”, “একটি লম্বা URL পুরো মোবাইল লেআউট ডানে ঠেলে দিল”। কিন্তু সমাধান সহজ আর স্পষ্ট — min-width: 0 (বা grid-এ minmax(0, 1fr)) লিখে আপনি ঘোষণা করছেন “আমি জানি, content কাটা বা উপচে পড়া আমি সামলাব”, সাথে overflow-wrap: anywhere বা overflow: hidden. অর্থাৎ ডিফল্ট নিরাপদ, আর ঝুঁকি নেওয়ার সিদ্ধান্ত লেখকের।
ইন্টারভিউতে এই প্রশ্নটি তাই প্রায়ই আসে: এটা দেখায় আপনি শুধু property-র নাম জানেন, নাকি layout algorithm-এর ভেতরের নিয়মও বোঝেন।
মূল উপলব্ধি: CSS ডিফল্টে content রক্ষা করে, নিখুঁত জ্যামিতি নয়। “আমার কলাম সমান হচ্ছে না” দেখলে প্রথমেই ভাবুন: ভেতরে কি এমন কিছু আছে যা ছোট হতে পারে না?
প্র ০৫“ব্রাউজারে চালিয়ে দেখুন” — কিন্তু ব্রাউজারভেদে ফল কি আলাদা হয় না? তাহলে একটি ব্রাউজারে যাচাই করা উত্তর কতটা নির্ভরযোগ্য?
একসময় সত্যিই হতো — Internet Explorer-এর যুগে একই CSS ভিন্ন ব্রাউজারে ভিন্ন box মাপ দিত, আর “cross-browser hack” ছিল ফ্রন্ট-এন্ড কাজের বড় অংশ। আজ পরিস্থিতি অনেক আলাদা, তিনটি কারণে।
প্রথম, স্পেসিফিকেশন এখন অনেক বেশি নির্দিষ্ট: HTML parsing-এর মতো CSS-এর cascade, box model, flex আর grid-এর algorithm ধাপে ধাপে লেখা। দ্বিতীয়, Web Platform Tests (WPT) নামে একটি যৌথ পরীক্ষার ভাণ্ডার আছে, যেখানে সব প্রধান ব্রাউজার নির্মাতা একই পরীক্ষা চালান — কোনো ব্রাউজার আলাদা ফল দিলে সেটি বাগ হিসেবে ধরা পড়ে। তৃতীয়, ২০২১ সাল থেকে বড় ব্রাউজার নির্মাতারা (Apple, Google, Microsoft, Mozilla, সাথে Igalia-র মতো প্রতিষ্ঠান) প্রতি বছর একসাথে কিছু ক্ষেত্র বেছে নেন, যেখানে পার্থক্য দূর করবেন — এই উদ্যোগের নাম এখন Interop. flex, grid, subgrid, :has(), container query — অনেক feature এভাবে সব ব্রাউজারে একই আচরণে এসেছে। Baseline লেবেল (Widely available / Newly available) ঠিক এটাই জানায়: কোন feature সব প্রধান ব্রাউজারে একইভাবে পাওয়া যাচ্ছে।
তাই এই পাতায় নিয়ম মানা হয়েছে: প্রশ্ন শুধু মান-নির্দিষ্ট আচরণ নিয়ে, যেখানে স্পেসিফিকেশন একটিই ফল বলে — তখন একটি আধুনিক ব্রাউজারে মাপা উত্তর বাকিগুলোতেও একই হওয়ার কথা। যেখানে আলাদা হতে পারে (ডিফল্ট লিংকের রঙের নির্দিষ্ট মান, dark mode-এর system color, ফর্ম-control-এর চেহারা, ফন্টের মাপ), সেখানে প্রশ্নে “Chromium-এ” লেখা, বা প্রশ্নই এড়ানো হয়েছে। srcset-এ কোন ছবি আসবে, তা স্পেসিফিকেশন ইচ্ছা করেই ব্রাউজারের হাতে ছেড়ে দেয় — এমন প্রশ্নের সঠিক উত্তর “নির্দিষ্ট নয়”।
আরেকটি সূক্ষ্মতা: getComputedStyle() সবসময় “computed value” দেয় না — width-এর মতো property-তে, element রেন্ডার হলে, দেয় layout-এর পরের used value (px-এ)। স্পেসিফিকেশন একে বলে resolved value. প্রশ্নের উত্তর লেখার সময় এই শব্দগুলো ঠিকমতো ব্যবহার করতে পারলে লিখিত পরীক্ষায় পূর্ণ নম্বর।
মূল উপলব্ধি: আধুনিক ওয়েবে ব্রাউজারগুলো একই নিয়মবই মানে, আর তার প্রমাণ যৌথ পরীক্ষা। তবু শেষ কথা বলে রেন্ডার করা পাতা — নিয়ম মাথায়, যাচাই ব্রাউজারে।
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বে ব্যবহৃত সব শব্দ এখানে একসাথে:
মনে রাখুন
- রেন্ডার-প্রশ্নে পাঁচ ধাপে ভাবুন: parse → cascade → box → layout → paint. বেশিরভাগ ফাঁদ প্রথম দুই ধাপে — কোন DOM তৈরি হলো, কোন declaration আসলে লাগল।
- HTML parser কখনো থামে না; নির্দিষ্ট নিয়মে মেরামত করে — p-এর স্বয়ংক্রিয় বন্ধ, tbody, foster parenting, adoption agency. CSS-এ অবৈধ declaration বা অচেনা selector চুপচাপ বাদ পড়ে।
- Cascade-এর সিঁড়ি: উৎস ও !important → inline → layer → specificity (a, b, c) → ক্রম; সরাসরি লাগা যেকোনো rule উত্তরাধিকারকে হারায়, আর
*-ও সরাসরি লাগে। - মাপের হিসাবে আগে box-sizing, তারপর প্রতিটি % কার সাপেক্ষে; উল্লম্ব margin normal flow-তে মেশে, flex/grid-এ মেশে না; flex আর grid-এ min-content-এর নিচে কেউ নামে না (min-width: 0 বা minmax(0, 1fr) ছাড়া)।
- transform, opacity, filter চেহারা বদলায়, layout নয় — কিন্তু নতুন stacking context আর containing block তৈরি করতে পারে। আর প্রতিটি উত্তর শেষে ব্রাউজারে মেপে যাচাই করুন।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ৫৬ · MCQ প্রশ্নব্যাংক — HTML আর CSSপরবর্তী পর্বধারণা আর তথ্যের দ্রুত প্রশ্ন, চাকরির বাছাই পরীক্ষার ধাঁচে।
- HTML ও CSS · কোর্স হোম৫৯টি পর্বপুরো কোর্সের রোডম্যাপ — যে ভাগে বেশি ভুল হলো, সেই মডিউলে ফিরে যান।
- JavaScript · আউটপুট কী হবে?পাশের ট্র্যাকএকই ধাঁচের অনুশীলন JavaScript-এ — coercion, closure, event loop.
- JavaScript · DOM-এর ভিত্তিগভীরে যান
getComputedStyle(),getBoundingClientRect()দিয়ে নিজের যাচাই-স্ক্রিপ্ট লেখা। - কম্পিউটার ও ICT · ইন্টারনেট কীভাবে চলেভিত্তিব্রাউজার, সার্ভার আর পাতা আসার পুরো পথ — ICT পরীক্ষার দৃষ্টিকোণ থেকে।