এই পর্বে যা শিখবেন
- box model-এর চার স্তর, আর DevTools-এর box-model ছবি পড়ে যেকোনো element-এর মাপ বের করা
- content-box আর border-box-এ মোট মাপের হিসাব, আর universal reset কেন সবাই ব্যবহার করে
- margin ও padding-এর shorthand — ১, ২, ৩ আর ৪টি মানের নিয়ম
- margin collapsing কখন হয়, কখন হয় না — আর এর জন্য তৈরি অদ্ভুত বাগ সারানো
- auto margin দিয়ে মাঝখানে বসানো, negative margin, min/max-width, outline, inline বাক্সের আচরণ আর aspect-ratio
১ · প্রতিটি element একটি বাক্স — বাঁধানো ছবির গল্প
আগের তিন পর্বে আপনি CSS-এর নিয়ম লিখতে, selector দিয়ে element বাছতে আর কোন নিয়ম জেতে তা বুঝতে শিখেছেন। এবার প্রশ্ন হলো, ব্রাউজার পাতাটা আঁকে কীভাবে? উত্তরের প্রথম ধাপ একটি সহজ কিন্তু শক্তিশালী ধারণা: ব্রাউজারের চোখে পাতার প্রতিটি element একটি আয়তাকার বাক্স। শিরোনাম একটি বাক্স, প্যারাগ্রাফ একটি বাক্স, একটি লিংক বা মোটা করা শব্দও একটি (বা কয়েকটি) বাক্স। গোল ছবি বা বাঁকা কোণের বোতামও ভেতরে ভেতরে আয়তক্ষেত্র — গোলাইটা শুধু আঁকার সময় যোগ হয়।
প্রতিটি বাক্সের মাপ আর চারপাশের ফাঁকা জায়গা কীভাবে হিসাব হবে, তার নিয়মের নাম box model. CSS-এ লেআউটের যত কৌশল আছে — Flexbox, Grid, রেসপন্সিভ ডিজাইন — সবকিছুর নিচে এই হিসাবটাই কাজ করে। তাই এই পর্বটি ভালো করে বুঝলে পরের প্রায় প্রতিটি পর্ব সহজ হয়ে যাবে।
বসার ঘরের দেয়ালে টাঙানো একটি বাঁধানো ছবির কথা ভাবুন। মাঝখানে আসল ছবি। ছবির চারপাশে সাদা বা ঘিয়া রঙের একটি কার্ডবোর্ডের পাড় থাকে — দোকানে একে বলে ম্যাট। তার বাইরে কাঠের ফ্রেম। আর ফ্রেমের বাইরে দেয়ালের ফাঁকা জায়গা, যাতে পাশের ছবির সাথে গায়ে গায়ে লেগে না যায়। CSS-এর বাক্সও হুবহু এমন: ছবি = content, ম্যাট = padding, ফ্রেম = border, দেয়ালের ফাঁকা = margin. খেয়াল করুন, ম্যাট ফ্রেমের ভেতরে, তাই ছবির ব্যাকগ্রাউন্ডের মতোই ম্যাটও “ছবির অংশ” মনে হয়; কিন্তু দেয়ালের ফাঁকা জায়গা ফ্রেমের বাইরে, সেখানে দেয়ালের রংই দেখা যায়।
বাক্সগুলো নিজের চোখে দেখার সবচেয়ে সহজ কৌশল হলো সব element-কে একটি দাগ দিয়ে ঘিরে দেওয়া। নিচের এডিটরে একটি ছোট দোকানের পাতা আছে, আর ওপরের <style> অংশে * selector দিয়ে সবার গায়ে লাল outline দেওয়া হয়েছে (outline কী, তা অংশ ৮-এ বিস্তারিত দেখব — এটি এমন দাগ, যা কোনো জায়গা নেয় না)।
<style>
* { outline: 2px solid tomato; }
</style>
<h2>রহিম স্টোর</h2>
<p>চাল, ডাল, তেল সব পাবেন <strong>পাইকারি দামে</strong>,
এখনই <a href="#order">অর্ডার করুন</a></p>
<ul>
<li>মিনিকেট চাল</li>
<li>মসুর ডাল</li>
</ul>
<button id="order">কার্টে যোগ করুন</button>দেখবেন দুই রকম বাক্স। h2, p, ul, li পুরো লাইন জুড়ে বসে — এরা block বাক্স। আর strong, a শুধু নিজের লেখাটুকু ঘিরে থাকে, লাইনের ভেতরেই বসে — এরা inline বাক্স। সবকিছু ঘিরে আছে আরও একটি বড় দাগ — body; হ্যাঁ, সেও একটি বাক্স (তার বাইরের html-ও, যদিও তার দাগ প্রিভিউর একেবারে কিনারায় পড়ে প্রায় চোখে পড়ে না)। খেয়াল করুন, body-র দাগ আর প্রিভিউর বাঁ কিনারার মাঝে একটু ফাঁক আছে; এটি ব্রাউজারের নিজের CSS (user-agent stylesheet) থেকে আসা body-র 8px margin. আর তালিকার বুলেটগুলো li-র বাক্সের বাইরে ঝুলে আছে — সেটাও ডিফল্ট আচরণ। চেষ্টা করুন: outline-কে border করে দেখুন — সব কিছু একটু করে সরে গেল কি? কেন সরল, তার উত্তর এই পর্বেই। বাক্সগুলো কোন নিয়মে পাশাপাশি বা নিচে নিচে সাজে (block আর inline-এর পুরো গল্প), সেটি পর্ব ২৩-এর বিষয়।
CSS লেখার সময় নিজেকে বারবার জিজ্ঞেস করুন: “এই element-এর বাক্সটা কত বড়, আর তার চারপাশে কতটা ফাঁকা?” লেআউটের বেশিরভাগ বাগ — কিছু একটা বাইরে বেরিয়ে যাওয়া, অকারণ ফাঁক, পাশাপাশি না বসা — এই একটি প্রশ্নের উত্তর না জানা থেকে আসে।
২ · বাক্সের চার স্তর — content, padding, border, margin
এবার স্তরগুলো একে একে চিনে নিই। নিচের ডায়াগ্রামে “পরে” চাপলে ভেতর থেকে বাইরের দিকে একটি করে স্তর যোগ হবে, আর শেষ ধাপে দেখবেন ব্রাউজারের DevTools ঠিক এই ছবিটাই কীভাবে দেখায়।
- Content — আসল ছবি। বাক্সের একেবারে ভেতরের অংশ, যেখানে লেখা, ছবি বা ভেতরের অন্য element বসে। এর মাপ ঠিক করে
widthআরheight(না দিলে ভেতরের জিনিস দেখে ব্রাউজার নিজেই হিসাব করে)। এখানে content 200px চওড়া, 120px উঁচু। একে বলে content area. - Padding — ম্যাট। content আর border-এর মাঝের ভেতরের ফাঁকা জায়গা। padding-এ element-এর নিজের ব্যাকগ্রাউন্ড দেখা যায় — তাই বোতামে padding বাড়ালে বোতামটাই বড় দেখায়, লেখার চারপাশে রঙিন জায়গা বাড়ে। এখানে চারদিকে 20px, তাই চওড়া হলো 240px.
- Border — ফ্রেম। padding-এর চারপাশের দাগ বা পাড়। border-এর পুরুত্ব, ধরন (solid, dashed, dotted…) আর রং থাকে। পুরুত্বটাও বাক্সের মাপে যোগ হয় — এখানে দুই পাশে 12px করে, চওড়া দাঁড়াল 264px. border-এর নানা নকশা আর গোল কোণ পর্ব ২২-এ।
- Margin — দেয়ালের ফাঁকা। border-এর বাইরের ফাঁকা জায়গা, যা প্রতিবেশী element-কে দূরে রাখে। margin সবসময় স্বচ্ছ — element-এর ব্যাকগ্রাউন্ড সেখানে যায় না, পেছনের (parent-এর) রং দেখা যায়। margin বাক্সের চেহারার মাপ বাড়ায় না, কিন্তু পাতায় জায়গা দখল করে: 324px.
- DevTools-এর box-model ছবি। যেকোনো পাতায় element-এর ওপর ডান-ক্লিক করে “Inspect” চাপুন। Chrome বা Edge-এ Elements প্যানেলের Computed ট্যাবে, আর Firefox-এ Layout ট্যাবে ঠিক এমন রঙিন ছবি পাবেন — চার পাশের প্রতিটি মান আলাদা লেখা থাকে, আর ছবির কোনো স্তরে মাউস রাখলে পাতার ওপর সেই অংশটি রঙিন হয়ে ওঠে। কোথাও অকারণ ফাঁক দেখলে প্রথমে এই ছবিটাই দেখুন — বেশিরভাগ সময় উত্তর এক নজরেই মেলে।
এবার নিজের হাতে একটি বাঁধানো ছবি বানান। নিচের CSS-এ চারটি স্তরের প্রতিটির পাশে মন্তব্যে লেখা আছে সে কোন অংশ।
.photo {
width: 200px;
height: 100px;
/* ছবি শুধু content-এ, ম্যাটের রং padding-এ */
background: linear-gradient(#fbbf24, #f97316) content-box,
#fef3c7;
padding: 20px; /* ম্যাট */
border: 12px solid #78350f; /* কাঠের ফ্রেম */
margin: 30px; /* দেয়ালের ফাঁকা */
color: #fff;
font: 700 18px sans-serif;
}
p { margin: 0; }কমলা ছবি (content), তার চারপাশে ঘিয়া ম্যাট (padding), বাদামি ফ্রেম (border), আর ফ্রেমের বাইরে সাদা ফাঁকা (margin) — নিচের লেখাটি 30px দূরে। একটি ছোট কৌশল খেয়াল করুন: ব্যাকগ্রাউন্ড সাধারণত padding-এর নিচেও ছড়িয়ে থাকে; এখানে content-box শব্দটি দিয়ে গ্রেডিয়েন্টকে শুধু content-এ আটকানো হয়েছে, যাতে ম্যাট আলাদা রঙে দেখা যায় (ব্যাকগ্রাউন্ডের এসব কৌশল পর্ব ২২-এ)। চেষ্টা করুন: padding-কে 40px করুন — ছবি একই থাকল, কিন্তু পুরো ফ্রেমটা বড় হলো। তারপর margin-কে 0 করুন — ফ্রেম বাঁ দিকে সরে গেল (এখন প্রিভিউর কিনারা থেকে শুধু body-র 8px margin দূরে), নিচের লেখাও উঠে এলো।
padding — ভেতরের ফাঁক
border-এর ভেতরে। element-এর ব্যাকগ্রাউন্ড দেখা যায়, ক্লিক করার জায়গাও বাড়ে। ঋণাত্মক মান হয় না। বোতাম বড় করা, কার্ডের লেখা কিনারা থেকে দূরে রাখা — padding-এর কাজ।
ভেতর থেকে ঠেলেmargin — বাইরের ফাঁক
border-এর বাইরে। সবসময় স্বচ্ছ, ক্লিক ধরে না। ঋণাত্মক হতে পারে, auto হতে পারে, আর ওপর-নিচে কখনো কখনো পাশেরটার সাথে মিশে যায়। দুই element-এর মধ্যে দূরত্ব — margin-এর কাজ।
৩ · মোট মাপের হিসাব — width আসলে কিসের width?
এখানেই নতুনরা সবচেয়ে বেশি অবাক হন। ধরুন একটি অনলাইন দোকানের পণ্য-কার্ডে লিখলেন width: 300px. স্বাভাবিকভাবে মনে হয় কার্ডটা 300px চওড়া হবে। কিন্তু সাথে padding: 20px আর border: 5px দিলে DevTools-এ মেপে দেখবেন কার্ডটা 350px! কারণ CSS-এর ডিফল্ট নিয়মে width মানে শুধু content-এর চওড়া। এই নিয়মের নাম box-sizing: content-box. নিচের ধাপগুলোতে হিসাবটা লাইন ধরে ধরে দেখুন:
1.card {2 width: 300px;3 padding: 20px;4 border: 5px solid #333;5 margin: 10px;7}
| content | |
| padding (বাঁ + ডান) | |
| border (বাঁ + ডান) | |
| চোখে দেখা চওড়া | |
| margin সহ জায়গা |
- width: 300px. ডিফল্ট
content-boxনিয়মে এই 300px শুধু content-এর মাপ। এখনো padding বা border নেই, তাই চোখে দেখা চওড়াও 300px. - padding যোগ হলো। চারদিকে 20px মানে বাঁয়ে 20 আর ডানে 20 — মোট 40px. content একটুও ছোট হয়নি, বরং বাক্সটা বাইরের দিকে ফুলে 340px হলো। নতুনরা প্রায়ই এক পাশের মান যোগ করে ভুল করেন — সবসময় দুই পাশ ধরুন।
- border যোগ হলো। দুই পাশে 5px করে আরও 10px. কার্ড এখন চোখে 350px চওড়া। এই মাপকে বলে border box-এর মাপ — border-এর বাইরের কিনারা থেকে বাইরের কিনারা।
- margin যোগ হলো। চোখে দেখা কার্ড বদলায়নি — 350px-ই। কিন্তু পাতায় সে এখন 370px জায়গা নেয়, কারণ দুই পাশে 10px করে ফাঁকা রাখতে হবে। একটি 360px চওড়া ফোনের পর্দায় এই কার্ড আর আঁটবে না — ডানে বেরিয়ে যাবে।
- box-sizing: border-box. এবার নিয়ম বদলাল:
widthমানে border-এর বাইরের কিনারা পর্যন্ত পুরো বাক্স। ব্রাউজার উল্টো দিক থেকে হিসাব করে — 300 থেকে padding আর border বাদ দিয়ে content পায় 250px. চোখে দেখা চওড়া ঠিক যা লিখেছেন তাই: 300px. পরের অংশে দেখব কেন প্রায় সবাই এই নিয়মটাই পছন্দ করে।
border-box: চোখে দেখা চওড়া = width; content = width − padding − border
উচ্চতার হিসাবও একই: height + ওপর-নিচের padding + ওপর-নিচের border. তবে বাস্তবে উচ্চতা সাধারণত ঠিক করে দেওয়া হয় না — লেখা যত, বাক্স তত উঁচু হয়। লেখার পরিমাণ জানা না থাকলে (যেমন বাংলা অনুবাদে লেখা প্রায়ই লম্বা হয়) height ঠিক করে দিলে লেখা বাক্সের বাইরে উপচে পড়তে পারে। বাক্সের বাইরে উপচে পড়া লেখা সামলানোর property overflow, যা আসবে পর্ব ২৩-এ।
আরও গভীরে: padding আর margin-এ শতাংশ (%) দিলে সেটি হিসাব হয় parent-এর (আরও ঠিক করে বললে containing block-এর) চওড়া থেকে — এমনকি padding-top বা margin-bottom দিলেও! কারণ block-এর উচ্চতা সাধারণত ভেতরের জিনিস দেখে ঠিক হয়; উচ্চতার শতাংশ নিলে হিসাব নিজের লেজ নিজে কামড়ানোর মতো চক্রে পড়ত। আর DevTools যে মাপ দেখায়, তা “used value” — সব নিয়ম মিলিয়ে ব্রাউজার শেষ পর্যন্ত যা ব্যবহার করেছে। সেজন্য সেখানে মাঝে মাঝে 263.5-এর মতো ভগ্নাংশও দেখবেন; পর্দার পিক্সেলে আঁকার সময় ব্রাউজার তা সমন্বয় করে নেয়।
৪ · box-sizing: border-box — হিসাবের ঝামেলা থেকে মুক্তি
বাস্তব কাজে content-box-এর সবচেয়ে বড় সমস্যা দেখা দেয় শতাংশের সাথে। ধরুন একটি সার্চ বক্স বা কার্ডকে বলছেন “parent-এর পুরো চওড়া নাও” — width: 100% — আর ভেতরের লেখা কিনারা থেকে দূরে রাখতে দিলেন padding: 20px. তাহলে বাক্স হবে 100% যোগ 40px যোগ border — অর্থাৎ parent-এর চেয়ে চওড়া, ডান দিকে বেরিয়ে যাবে। নিচে দুটি একই রকম বাক্স, একটি মাত্র লাইনের পার্থক্য:
.wrap {
width: 260px;
border: 2px dashed #64748b; /* parent-এর সীমানা */
margin-bottom: 16px;
}
.box {
width: 100%;
padding: 20px;
border: 4px solid #0369a1;
background: #e0f2fe;
}
.bb { box-sizing: border-box; }প্রথম নীল বাক্সটি ধূসর ডটেড সীমানা পেরিয়ে ডানে 48px বেরিয়ে গেছে (260 + 40 + 8 = 308px). দ্বিতীয়টি ঠিক 260px — padding আর border ভেতরে ঢুকে গেছে, content একটু ছোট হয়েছে। চেষ্টা করুন: প্রথম বাক্সে width: calc(100% - 48px) লিখে দেখুন — এটিও কাজ করে, কিন্তু padding বা border বদলালেই সংখ্যাটা আবার বদলাতে হবে। border-box-এ সেই হিসাবই লাগে না। এবার .bb-এর padding বাড়িয়ে 60px করুন — বাক্স 260px-ই থাকল, শুধু ভেতরের লেখার জায়গা কমল।
Universal reset — প্রায় প্রতিটি আধুনিক প্রজেক্টের প্রথম লাইন
প্রতিটি element-এ আলাদা করে box-sizing লেখার বদলে পেশাদাররা CSS ফাইলের একেবারে শুরুতে একবার লিখে দেন:
*,
*::before,
*::after {
box-sizing: border-box;
}এখানে * মানে “সব element”, আর ::before/::after হলো CSS দিয়ে তৈরি বাড়তি বাক্স, যাদের বলে pseudo-element (পর্ব ৩৪-এ বিস্তারিত)। এরা *-এর মধ্যে পড়ে না, তাই আলাদা করে লিখতে হয়। box-sizing নিজে থেকে parent থেকে child-এ উত্তরাধিকারে (inheritance) যায় না — তাই প্রতিটি element-কে সরাসরি বলতে হয়। কেউ কেউ একটু ভিন্ন রূপ ব্যবহার করেন: html { box-sizing: border-box; } আর *, *::before, *::after { box-sizing: inherit; } — এতে কোনো তৃতীয় পক্ষের উইজেট যদি content-box চায়, তার parent-এ একবার বদলালেই ভেতরের সবাই মেনে নেয়। দুটোই চলে; নতুন প্রজেক্টে প্রথমটিই যথেষ্ট সহজ।
box-sizing এখন Baseline Widely available — বহু বছর ধরে সব ব্রাউজারে কোনো prefix ছাড়াই চলে। পুরোনো টিউটোরিয়াল বা AI-এর কোডে -webkit-box-sizing আর -moz-box-sizing দেখলে বুঝবেন সেগুলো ২০১০-এর দশকের শুরুর দিকের অভ্যাস; আজ মুছে দিতে পারেন। মানও মাত্র দুটি: content-box (ডিফল্ট) আর border-box.
মজার ব্যাপার হলো, border-box-এর গল্পটা আসলে একটি “ভুলের” জয়ের গল্প। ১৯৯৬ সালের প্রথম CSS নিয়ম (CSS1) বলেছিল width মানে শুধু content. কিন্তু ১৯৯৯ সালে আসা Windows-এর Internet Explorer 5 width-এর ভেতরে padding আর border-ও ধরত — অর্থাৎ আজকের border-box. তখন সবচেয়ে জনপ্রিয় ব্রাউজার ছিল এটিই, তাই একই CSS IE-তে এক মাপে, অন্য ব্রাউজারে আরেক মাপে দেখাত। ডেভেলপাররা দুই ব্রাউজারকে দুই মাপ খাওয়াতে অদ্ভুত CSS কৌশল বানাতেন — Tantek Çelik-এর বিখ্যাত “Box Model Hack” তার একটি। IE6 (২০০১) doctype থাকলে standards mode-এ W3C-র নিয়ম মানল, কিন্তু doctype ছাড়া quirks mode-এ পুরোনো হিসাবই রাখল — doctype কেন জরুরি, তার একটি বড় কারণ এটাই। পরে CSS নিজেই box-sizing property যোগ করে দুই পথই খোলা রাখল, আর ২০১২ সালে Paul Irish-এর একটি জনপ্রিয় লেখার পর * { box-sizing: border-box } প্রায় সবার অভ্যাসে পরিণত হয়। CSS Working Group নিজেই তাদের “CSS-এর নকশায় ভুলের তালিকা”-য় লিখে রেখেছে যে ডিফল্ট হিসেবে border-box হওয়াই উচিত ছিল।
এবার মাপগুলো চোখে না দেখে JavaScript দিয়ে মেপে দেখি। ব্রাউজার একই বাক্সের কয়েক রকম মাপ জানায় — কোনটি কী মাপে, সেটা জানলে DevTools বা JavaScript-এর সংখ্যা দেখে আর বিভ্রান্ত হবেন না:
// দুটি বাক্স: একই width, padding, border — শুধু box-sizing আলাদা
function measure() {
document.querySelectorAll('.box').forEach(function (box) {
const css = getComputedStyle(box);
console.log(box.id + ' (' + css.boxSizing + ')');
console.log(' computed width :', css.width);
console.log(' offsetWidth :', box.offsetWidth);
console.log(' clientWidth :', box.clientWidth);
console.log(' rect.width :', box.getBoundingClientRect().width);
});
}
// ফ্রেমটি পাতায় বসে layout হওয়া পর্যন্ত অপেক্ষা, তারপর মাপা
(function wait() {
document.body.offsetWidth ? measure() : setTimeout(wait, 50);
})();content-box বাক্সের জন্য আসবে computed width: 200px, offsetWidth: 250, clientWidth: 240, rect.width: 250. border-box বাক্সে 200px, 200, 190, 200. মানে: offsetWidth আর getBoundingClientRect() সবসময় border box-এর চওড়া দেয় (চোখে দেখা মাপ); clientWidth দেয় border বাদে, padding সহ মাপ; আর getComputedStyle().width দেয় width property-র মান, যার অর্থ নির্ভর করে box-sizing-এর ওপর। শেষের ছোট wait ফাংশনটি খেয়াল করুন: প্রিভিউর ফ্রেম পাতায় বসে layout শেষ হওয়ার আগে মাপ পড়লে সব সংখ্যা 0 আসতে পারে, তাই body-র চওড়া শূন্যের বেশি না হওয়া পর্যন্ত সে অপেক্ষা করে — বাস্তবের কোডেও “মাপুন layout-এর পরে” নিয়মটি মনে রাখার মতো। আরেকটি পার্থক্য: offsetWidth পূর্ণসংখ্যায় গোল করা, getBoundingClientRect() ভগ্নাংশ রাখে এবং transform-এর ফলও ধরে। চেষ্টা করুন: CSS-এ padding-কে 30px করে আবার চালান — কোন সংখ্যাগুলো বদলাল আর কোনগুলো বদলাল না, মিলিয়ে দেখুন।
৫ · Shorthand — ওপর থেকে ঘড়ির কাঁটার দিকে
margin আর padding-এর প্রতিটি দিকের আলাদা property আছে: margin-top, margin-right, margin-bottom, margin-left (padding-এরও একই চারটি)। কিন্তু চারটি লাইন লেখার বদলে এক লাইনে লেখা যায় — একে বলে shorthand property. মনে রাখার কৌশল: ওপর থেকে শুরু করে ঘড়ির কাঁটার দিকে — ওপর, ডান, নিচ, বাঁ। ইংরেজিতে অনেকে মনে রাখেন “TRouBLe” (Top, Right, Bottom, Left) শব্দটা দিয়ে।
- Property-র নাম।
marginএকাই চারটি আলাদা property-র কাজ করে। একইভাবেpadding, আর border-এর ক্ষেত্রেborder-width,border-color,border-style-ও এই নিয়ম মানে। - প্রথম মান — ওপর। ঘড়ির ১২টা থেকে শুরু।
margin-top: 10px. - দ্বিতীয় মান — ডান। কাঁটা ঘুরে ৩টার দিকে।
margin-right: 20px. - তৃতীয় মান — নিচ। ৬টার দিকে।
margin-bottom: 30px. - চতুর্থ মান — বাঁ। ৯টার দিকে, আর এক পাক পূর্ণ।
margin-left: 40px. - মান কম দিলে কী হয়? নিয়ম একটাই: যে দিকের মান নেই, সে তার উল্টো দিকের মান নকল করে। ৩টি মান দিলে বাঁ দিক ডানের মান নেয়; ২টি দিলে নিচ ওপরের আর বাঁ ডানের মান নেয়; ১টি দিলে চার দিকই সমান। নিচের টেবিলে চারটি রূপ একসাথে দেখুন।
| যা লিখলেন | ওপর | ডান | নিচ | বাঁ | কখন কাজে লাগে |
|---|---|---|---|---|---|
padding: 16px | 16 | 16 | 16 | 16 | চার দিকে সমান ফাঁক — কার্ড, বক্স |
padding: 8px 16px | 8 | 16 | 8 | 16 | ওপর-নিচ এক, দুই পাশ আরেক — বোতাম |
margin: 0 auto 24px | 0 | auto | 24 | auto | মাঝখানে বসানো আর নিচে ফাঁক |
margin: 4px 8px 12px 16px | 4 | 8 | 12 | 16 | চার দিক আলাদা — কম লাগে |
একটি সতর্কতা: shorthand যে দিকগুলো আপনি উল্লেখ করেননি, সেগুলোও সেট করে দেয়। ধরুন আগে margin-top: 40px লিখেছেন, তার নিচে margin: 0 auto — তাহলে ওপরের 40px মুছে 0 হয়ে যাবে, কারণ দ্বিতীয় লাইনটিও চার দিকের মান দিয়েছে আর cascade-এ পরে লেখা নিয়ম জেতে। border-এর shorthand একটু আলাদা: border: 5px solid #333-এ পুরুত্ব, ধরন আর রং যেকোনো ক্রমে লেখা যায়, কিন্তু ধরন (solid) না লিখলে ডিফল্ট ধরন none — অর্থাৎ border দেখাই যাবে না! আর লেখার দিক অনুযায়ী বদলায় এমন “logical” রূপ — margin-inline, padding-block — আসবে পর্ব ৩৫-এ।
৬ · Margin collapsing — দুই margin মিলে এক
এবার box model-এর সবচেয়ে বিখ্যাত “অদ্ভুত” আচরণ। ধরুন একটি নোটিশ বোর্ডের পাতায় দুটি নোটিশ নিচে নিচে আছে। ওপরেরটার margin-bottom: 30px, নিচেরটার margin-top: 20px. দুটির মাঝে ফাঁক কত? হিসাব বলে 50px, কিন্তু ব্রাউজার দেখায় 30px. ওপর-নিচের দুটি margin গায়ে গায়ে লাগলে তারা মিশে একটি হয়ে যায়, আর বড়টাই টিকে থাকে। একে বলে margin collapsing.
দুই প্রতিবেশীর বাড়ির মাঝখানের জায়গার কথা ভাবুন। এক বাড়ির মালিক বললেন “আমার দেয়াল থেকে ৩ হাত খালি থাকবে”, অন্যজন বললেন “আমার দেয়াল থেকে ২ হাত।” দুজনের শর্ত একসাথে মানতে ৫ হাত লাগে না — ৩ হাত রাখলেই দুজনের চাওয়া পূরণ হয়, কারণ সেই একই খালি জায়গা দুজনেরই “খালি জায়গা”। margin ঠিক এভাবে ভাবে: “আমার আশপাশে অন্তত এতটুকু ফাঁকা চাই।” প্যারাগ্রাফের মধ্যে ফাঁকের জন্য এটা খুব কাজের — প্রতিটি <p>-এর ওপর-নিচে 1em margin থাকলেও দুই প্যারাগ্রাফের মাঝে ফাঁক 2em হয় না, 1em-ই থাকে।
সমস্যা হলো, এই নিয়ম মাঝে মাঝে এমন জায়গায় কাজ করে যেখানে আপনি আশা করেননি। নিচের ধাপগুলোতে collapsing-এর তিনটি রূপ আর যেসব অবস্থায় এটি হয় না, দেখুন (হলুদ ডোরাকাটা অংশ = ফাঁক):
- পাশাপাশি দুই ভাই (adjacent siblings). একই parent-এর পরপর দুটি block-এর মাঝে ওপরেরটার নিচের margin আর নিচেরটার ওপরের margin মিশে যায়। ফাঁক = দুটির মধ্যে বড়টি, 30px. শুধু ওপর-নিচের (block দিকের) margin মেশে — বাঁ-ডানের margin কখনো মেশে না।
- ঋণাত্মক margin থাকলে। একটি ধনাত্মক আর একটি ঋণাত্মক হলে দুটি যোগ হয়: 30 + (−10) = 20px. দুটিই ঋণাত্মক হলে সবচেয়ে বেশি ঋণাত্মকটি টেকে। নিয়মটা এক লাইনে: সবচেয়ে বড় ধনাত্মক মান + সবচেয়ে ছোট ঋণাত্মক মান।
- parent আর প্রথম child (parent-child). এটাই সবচেয়ে বেশি বিভ্রান্ত করে। গোলাপি parent-এর ভেতরের সবুজ child-কে
margin-top: 24pxদিলেন, ভাবলেন child parent-এর ভেতরে একটু নিচে নামবে। কিন্তু parent-এর ওপরে যদি padding বা border না থাকে, child-এর margin parent-এর margin-এর সাথে মিশে parent-এর বাইরে চলে যায় — পুরো গোলাপি বাক্সটাই নিচে নেমে যায়, ভেতরে কোনো ফাঁক থাকে না। শেষ child-এর margin-bottom-এর ক্ষেত্রেও একই ঘটনা ঘটে। - যা দিয়ে আটকানো যায়। parent আর child-এর margin-এর মাঝে কিছু একটা থাকলেই মেশা বন্ধ: parent-এর
padding-top(1px হলেও),border-top, অথবা parent-কে একটি নতুন block formatting context বানানো — যার সবচেয়ে পরিষ্কার উপায়display: flow-root(Baseline Widely available). পুরোনো কোডে একই কাজেoverflow: hiddenদেখবেন, যা পার্শ্বপ্রতিক্রিয়ায় বাইরে বেরোনো জিনিস কেটে ফেলে। - খালি বাক্স (empty box). যে div-এ কোনো লেখা, উচ্চতা, padding বা border নেই, তার নিজের ওপরের আর নিচের margin একে অপরের সাথে মিশে যায় — 20 আর 20 মিলে মাত্র 20px. এমনকি তার আগে-পরের element-এর margin-ও এর “ভেতর দিয়ে” মিশে যেতে পারে।
- যেখানে কখনো মেশে না। flex বা grid container-এর ভেতরের item-দের margin মেশে না — এখানে ফাঁক 30 + 20 = 50px. এছাড়া float, absolutely positioned element, inline-block আর পাতার root element (
html)-এর margin-ও মেশে না। এজন্যই আধুনিক লেআউটে item-দের মাঝে ফাঁকের জন্য অনেকে margin-এর বদলেgapব্যবহার করেন (পর্ব ২৫ ও ২৭)।
এবার নিজে পরীক্ষা করুন। নিচের এডিটরে দুটি দৃশ্য আছে — পাশাপাশি দুই নোটিশ, আর একটি parent-এর ভেতরে child. একটি ছোট স্ক্রিপ্ট আসল ফাঁকগুলো মেপে নিচে লিখে দেবে:
<style>
.note { background: #bae6fd; padding: 6px; }
.a { margin-bottom: 30px; }
.b { margin-top: 20px; }
.parent { background: #fecdd3; }
.child { margin-top: 24px; background: #bbf7d0; padding: 6px; }
</style>
<div class="note a">নোটিশ ক — margin-bottom: 30px</div>
<div class="note b">নোটিশ খ — margin-top: 20px</div>
<div class="parent">
<div class="child">child — margin-top: 24px</div>
</div>
<script>
const r = s => document.querySelector(s).getBoundingClientRect();
(function wait() { // layout শেষ না হওয়া পর্যন্ত অপেক্ষা
if (!document.body.offsetWidth) return setTimeout(wait, 50);
console.log('ক থেকে খ:', r('.b').top - r('.a').bottom, 'px');
console.log('খ থেকে parent:', r('.parent').top - r('.b').bottom, 'px');
console.log('parent থেকে child:', r('.child').top - r('.parent').top, 'px');
})();
</script>ফল আসবে ক থেকে খ: 30 px (50 নয়), খ থেকে parent: 24 px আর parent থেকে child: 0 px — child-এর margin গোলাপি parent-এর বাইরে চলে গেছে, গোলাপি রংটা child-এর ঠিক গা থেকে শুরু। চেষ্টা করুন: .parent-এ display: flow-root; যোগ করুন — এবার ফাঁকটা গোলাপি বাক্সের ভেতরে দেখা যাবে, আর শেষ লাইন হবে 24. তারপর ওটা মুছে padding-top: 1px; দিয়ে দেখুন। শেষে .b-এর margin-কে -10px করুন — প্রথম ফাঁক কত হলো?
৭ · margin-এর আরও কৌশল — auto, negative আর min/max
auto margin — মাঝখানে বসানোর সহজ উপায়
একটি block বাক্সকে width বা max-width দিয়ে parent-এর চেয়ে সরু করলে বাক্সটা বাঁ দিকে বসে থাকে, ডানে ফাঁকা পড়ে থাকে। বাঁ আর ডান margin দুটিকেই auto দিলে ব্রাউজার বাকি জায়গাটা দুই পাশে সমান ভাগ করে দেয় — বাক্স মাঝখানে চলে আসে। এটাই auto margin. ব্লগের লেখা, নিউজ পোর্টালের কলাম, লগইন ফর্ম — প্রায় সবখানে এই একটি লাইন: margin: 0 auto.
দুটি শর্ত মনে রাখুন: বাক্সটি block হতে হবে, আর তার চওড়া parent-এর চেয়ে কম হতে হবে (width না দিলে block এমনিতেই পুরো চওড়া নেয়, ভাগ করার মতো জায়গাই থাকে না)। আর সাধারণ block লেআউটে ওপর-নিচের auto margin মানে 0 — তাই margin: auto দিয়ে কোনো বাক্সকে খাড়াখাড়ি মাঝখানে আনা যায় না। Flexbox আর Grid-এর ভেতরে অবশ্য auto margin চার দিকেই ফাঁকা জায়গা শুষে নেয় — সেই কৌশল পর্ব ২৬-এ।
min-width, max-width — নমনীয় কিন্তু সীমার ভেতরে
ফোন থেকে বড় মনিটর — পর্দার মাপ অনেক রকম। width: 700px দিলে ছোট ফোনে বাক্স পর্দা থেকে বেরিয়ে যাবে। এর বদলে max-width: 700px দিলে বাক্স জায়গা থাকলে 700px পর্যন্ত বড় হবে, কম জায়গায় নিজে থেকে সরু হবে। একইভাবে min-width বলে “এর চেয়ে সরু হবে না”, আর min-height/max-height উচ্চতার জন্য। এদের একসাথে বলে min/max size. দ্বন্দ্ব হলে নিয়ম: min-width জেতে max-width-এর ওপর, আর দুটোই জেতে width-এর ওপর। লেখার কলামের জন্য max-width খুব কাজের — খুব লম্বা লাইন পড়তে চোখ ক্লান্ত হয় (পর্ব ২১-এ বিস্তারিত)।
negative margin — ইচ্ছা করে কাছে টানা
margin ঋণাত্মক হতে পারে (padding পারে না)। Negative margin বাক্সকে সেই দিকে টেনে আনে, বা প্রতিবেশীকে নিজের ওপর টেনে নেয়। বাস্তব ব্যবহার: একটি কার্ডের ভেতরে padding আছে, কিন্তু ভেতরের একটি ব্যানার বা ছবিকে কার্ডের কিনারা থেকে কিনারা পর্যন্ত ছড়াতে চান। তখন ব্যানারে padding-এর সমান ঋণাত্মক margin দিন:
.page {
max-width: 320px;
margin: 0 auto; /* বাঁ-ডান auto: মাঝখানে */
padding: 1px 16px;
background: #f1f5f9;
border: 1px solid #94a3b8;
}
.banner {
margin: 0 -16px; /* padding পেরিয়ে দুই কিনারায় */
padding: 8px 16px;
background: #0f766e;
color: #fff;
}ধূসর বিজ্ঞপ্তি-বাক্সটি প্রিভিউর মাঝখানে বসেছে, আর সবুজ ব্যানারটি বাক্সের padding পেরিয়ে দুই পাশের কিনারা ছুঁয়েছে, অথচ ব্যানারের লেখা বাকি লেখার সাথে এক লাইনে আছে। চেষ্টা করুন: margin: 0 auto মুছে দিন — বাক্স বাঁয়ে সরে যাবে। তারপর max-width-কে width: 900px করে দেখুন — প্রিভিউর চেয়ে চওড়া হয়ে ডানে বেরিয়ে যাবে; max-width: 900px হলে বেরোবে না। শেষে ব্যানারের -16px-কে -40px করুন — বাক্স ছাড়িয়ে বাইরে চলে গেল। negative margin শক্তিশালী, তাই মাপ সবসময় padding-এর সাথে মিলিয়ে দিন। (.page-এর padding: 1px 16px-এর ওই 1px কেন? অংশ ৬ মনে করুন — ভেতরের h3 আর p-এর margin যেন বাক্সের বাইরে চলে না যায়।)
aspect-ratio — উচ্চতা আর চওড়ার অনুপাত
YouTube ভিডিওর ফ্রেম, পণ্যের বর্গাকার ছবি, প্রোফাইলের গোল ছবি — অনেক বাক্সের চওড়া পর্দা অনুযায়ী বদলায়, কিন্তু আকৃতির অনুপাত ঠিক থাকা চাই। aspect-ratio property ঠিক এই কাজটি করে: চওড়া জানা থাকলে উচ্চতা অনুপাত থেকে হিসাব হয়।
.video { width: 100%; aspect-ratio: 16 / 9; }
.product-photo { width: 100%; aspect-ratio: 1; object-fit: cover; }aspect-ratio এখন Baseline Widely available. এর আগে একই কাজে “padding hack” ব্যবহার হতো — height: 0; padding-bottom: 56.25% — যা কাজ করত ঠিক সেই কারণে, যা আমরা অংশ ৩-এর “আরও গভীরে” বাক্সে দেখেছি: padding-এর শতাংশ চওড়া থেকে হিসাব হয় (9 ÷ 16 = 0.5625). পুরোনো কোডে এটি দেখলে চিনে নিন, নতুন কোডে aspect-ratio লিখুন। ছবির ক্ষেত্রে HTML-এ width আর height attribute দিলে ব্রাউজার নিজেই অনুপাতটি আগে থেকে জেনে জায়গা রেখে দেয়, ফলে layout shift কমে (পর্ব ৬)।
৮ · outline আর inline বাক্স — দুটি ব্যতিক্রমী আচরণ
outline — জায়গা না নেওয়া দাগ
দেখতে border-এর মতো, কিন্তু স্বভাবে একেবারে আলাদা। outline বাক্সের border-এর বাইরে আঁকা হয়, কিন্তু box model-এর অংশ নয় — কোনো জায়গা নেয় না, কাউকে সরায় না, দরকার হলে প্রতিবেশীর ওপরেই এঁকে ফেলে। এর আলাদা চার দিক নেই (চার দিকেই একই রকম), আর outline-offset দিয়ে বাক্স থেকে একটু দূরে আঁকা যায়। নিচে তিনটি সারিতে একই পণ্য-চিপ, শুধু মাঝখানের “ডাল”-এর সাজ আলাদা:
<style>
.chip { display: inline-block; padding: 6px 10px; background: #e2e8f0; }
.with-border { border: 6px solid #2563eb; }
.with-outline { outline: 6px solid #2563eb; outline-offset: 2px; }
</style>
<p><span class="chip">চাল</span><span class="chip">ডাল</span><span class="chip">তেল</span></p>
<p><span class="chip">চাল</span><span class="chip with-border">ডাল</span><span class="chip">তেল</span></p>
<p><span class="chip">চাল</span><span class="chip with-outline">ডাল</span><span class="chip">তেল</span></p>দ্বিতীয় সারিতে border-এর জন্য “ডাল” বড় হয়ে গেছে, ফলে “তেল” ডানে সরেছে আর সারিটাও একটু উঁচু হয়েছে। তৃতীয় সারিতে outline-এর নীল দাগ একই পুরু, কিন্তু “চাল” আর “তেল” একচুলও নড়েনি — দাগটা বরং তাদের ওপর দিয়ে এঁকে গেছে। চেষ্টা করুন: outline-offset-কে -8px করুন — দাগ বাক্সের ভেতরে চলে আসবে। এজন্যই কীবোর্ডে Tab চাপলে যে focus-এর দাগ দেখা যায়, ব্রাউজার সেটি outline দিয়ে আঁকে: দাগ এলে-গেলে পাতার কিছু নড়ে না।
AI-এর কোডে বা পুরোনো টেমপ্লেটে প্রায়ই দেখবেন *:focus { outline: none; } — “দাগটা দেখতে খারাপ লাগে” বলে। এটি কীবোর্ড দিয়ে চালানো মানুষের জন্য পাতাটাকে প্রায় অচল করে দেয়, কারণ তাঁরা আর বুঝতে পারেন না কোথায় আছেন। WCAG 2.2-এর 2.4.7 (Focus Visible) নিয়মে focus দৃশ্যমান রাখা বাধ্যতামূলক। outline সরাতেই চাইলে তার বদলে স্পষ্ট বিকল্প দিন; সঠিক কৌশল (:focus-visible) আসবে পর্ব ৩৪ ও ৪৫-এ।
inline বাক্সে padding আর margin — অর্ধেক কাজ করে
span, a, strong-এর মতো inline element লেখার লাইনের ভেতরে বসে। তাদের ক্ষেত্রে box model-এর নিয়ম একটু আলাদা: width আর height কাজই করে না; বাঁ-ডানের padding, border আর margin ঠিকঠাক জায়গা নেয়; কিন্তু ওপর-নিচের padding আর border শুধু আঁকা হয়, জায়গা নেয় না, আর ওপর-নিচের margin-এর কোনো প্রভাবই নেই। কারণ লাইনের উচ্চতা ঠিক করে line box — লেখার line-height — আর inline বাক্স সেই লাইনের ভেতরে লেখার মতোই বসে।
<style>
p { width: 300px; line-height: 1.6; }
.tag {
background: #fde68a;
padding: 12px 6px;
margin: 30px 10px;
border: 2px solid #b45309;
}
</style>
<p>আগামীকাল সকাল দশটায় অফিসে একটি <span class="tag">জরুরি</span>
মিটিং আছে। লাইনটা লম্বা করতে আরও কিছু লেখা দিলাম, যাতে
ওপরে-নিচের লাইনের সাথে ব্যাজটির সম্পর্ক বোঝা যায়।</p>হলুদ “জরুরি” ব্যাজের ওপর-নিচের 12px padding আঁকা হয়েছে ঠিকই — রং ওপরের আর নিচের লাইনের লেখার ওপর উঠে গেছে — কিন্তু লাইনগুলো একটুও সরেনি। 30px-এর ওপর-নিচের margin-এর কোনো চিহ্নই নেই; অথচ বাঁ-ডানের 10px margin শব্দগুলোকে দূরে সরিয়েছে। চেষ্টা করুন: .tag-এ display: inline-block; যোগ করুন — এবার ব্যাজ নিজের উচ্চতার জায়গা দাবি করবে, লাইনগুলো সরে যাবে আর ওপর-নিচের margin-ও কাজ করবে। (একটি ব্যতিক্রম: img-এর মতো replaced element আর button-এর মতো inline-block বাক্স লাইনের ভেতরে থাকলেও পুরো box model মানে।)
পরীক্ষা ও ইন্টারভিউতে — বিশ্ববিদ্যালয়, চাকরি বা ফ্রন্ট-এন্ড ইন্টারভিউর পরীক্ষায় এ ধরনের প্রশ্ন প্রায়ই আসে:
- CSS box model-এর অংশগুলো কী কী? — ভেতর থেকে বাইরে content, padding, border, margin.
- content-box আর border-box-এর পার্থক্য? — content-box-এ width শুধু content-এর মাপ, padding-border বাড়তি যোগ হয়; border-box-এ width-এর ভেতরেই padding আর border ধরা।
- margin আর padding-এর পার্থক্য? — padding border-এর ভেতরে, ব্যাকগ্রাউন্ড দেখায়, ঋণাত্মক হয় না; margin বাইরে, স্বচ্ছ, ঋণাত্মক বা auto হতে পারে এবং ওপর-নিচে মিশে যেতে পারে।
- margin collapsing কী, কীভাবে আটকাবেন? — block লেআউটে গায়ে লাগা ওপর-নিচের margin মিশে বড়টি থাকে; parent-এ padding/border,
display: flow-root, বা flex/grid ব্যবহার করলে মেশে না। - একটি block-কে অনুভূমিকভাবে মাঝখানে আনবেন কীভাবে? — চওড়া (বা max-width) দিয়ে
margin-leftআরmargin-rightauto.
৯ · AI-এর যুগে — box model-এর কাজ AI-কে দিলে কী দেখবেন
“একটা সুন্দর কার্ড বানিয়ে দাও” বললে AI কয়েক সেকেন্ডে CSS দিয়ে দেয়, আর বড় পর্দায় সেটা দেখতে ভালোও লাগে। সমস্যা ধরা পড়ে ফোনে খুললে, লেখা লম্বা হলে, বা কীবোর্ড দিয়ে চালালে। কারণ AI মাপগুলো “চোখের আন্দাজে” মেলায় — box model-এর হিসাব যাচাই করে না। আর ইন্টারনেটের পুরোনো কোড থেকে শেখা বলে পুরোনো অভ্যাসও নিয়ে আসে।
AI সাধারণত যেসব ভুল করে
| AI-এর ভুল | আপনি যা দেখবেন | ঠিক উপায় |
|---|---|---|
box-sizing reset নেই, অথচ width: 100% + padding | ফোনে পাশে স্ক্রল, ডানে বেরোনো বাক্স | শুরুতে universal border-box reset |
সব কিছুর নির্দিষ্ট height | লম্বা বাংলা লেখা বাক্স থেকে উপচে পড়ে | height না দিয়ে padding; দরকারে min-height |
নির্দিষ্ট width: 1200px | ছোট পর্দায় পুরো পাতা পাশে সরে | max-width + margin: 0 auto |
outline: none | Tab চাপলে কোথায় আছেন বোঝা যায় না | outline রাখুন বা স্পষ্ট বিকল্প দিন |
margin collapsing বুঝতে না পেরে padding: 1px, overflow: hidden বা অদ্ভুত negative margin | পরে অন্য কোথাও লেখা কাটা পড়ে | display: flow-root, বা flex/grid-এ gap |
-webkit-box-sizing, -moz-box-sizing | অপ্রয়োজনীয় বাড়তি লাইন | prefix ছাড়া box-sizing |
AI-কে কাজ দেওয়ার সময় box model-এর শর্তগুলো আগেই লিখে দিন। শেষের অংশটি খেয়াল করুন — AI-কে নিজের মাপের হিসাব লিখে দেখাতে বললে তার ভুলও প্রায়ই নিজেই বেরিয়ে আসে।
AI-এর দেওয়া CSS হাতে পেলে — যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলোই আপনাকে CSS লেখক থেকে লেআউট-চিন্তক বানাবে।
প্র ০১IE5-এর box model তো “ভুল” বলা হতো — তাহলে শেষ পর্যন্ত সেটাই জিতল কেন?
“ভুল” কথাটা আসলে নিয়মের দৃষ্টিতে — বাস্তব কাজের দৃষ্টিতে নয়। ১৯৯৬ সালের CSS1 নিয়ম width-কে content-এর মাপ ধরেছিল। এর পেছনে যুক্তিও ছিল: তখন ওয়েব মূলত লেখার দলিল, আর লেখার কলাম কত চওড়া হবে সেটাই আসল প্রশ্ন। কিন্তু Windows-এর Internet Explorer 5 ধরল width মানে border পর্যন্ত পুরো বাক্স। IE তখন বাজারের বেশিরভাগ ব্যবহারকারীর ব্রাউজার, তাই ডেভেলপারদের দুই রকম হিসাবের সাথেই লড়তে হলো। Tantek Çelik-এর “Box Model Hack”-এর মতো কৌশল জন্মাল — CSS-এর এমন একটি জায়গায় অদ্ভুত লেখা রাখা, যা IE5 ভুল পড়ে থেমে যায় আর অন্য ব্রাউজার ঠিক পড়ে এগিয়ে যায়।
কিন্তু বাস্তবের নকশা কীভাবে ভাবা হয়? ডিজাইনার বলেন “এই কার্ড ৩০০ পিক্সেল চওড়া”, “এই বোতাম কলামের অর্ধেক”। তিনি দেয়ালে টাঙানো ফ্রেমের বাইরের মাপের কথা বলছেন, ভেতরের ছবির নয়। কাঠমিস্ত্রি আলমারি বানালে বাইরের মাপ ধরে, দেয়ালে সেটাই জায়গা নেয়। শতাংশ আর রেসপন্সিভ লেআউট আসার পর পার্থক্যটা আরও স্পষ্ট হলো: “দুটি কলাম, প্রতিটি 50%, ভেতরে 20px padding” — content-box-এ এটি দুই কলামকে 100%-এর বেশি বানিয়ে লেআউট ভেঙে দেয়, border-box-এ সহজেই মেলে।
তাই CSS নিয়মটা না বদলে box-sizing দিয়ে দুই পথ খোলা রাখল — পুরোনো সাইট ভাঙা চলবে না, ওয়েবের এটাই মূল নীতি। ডিফল্ট বদলানো এখন আর সম্ভব নয়, কারণ কোটি কোটি পাতা content-box ধরে লেখা। CSS Working Group নিজেদের “CSS-এর নকশায় ভুলের তালিকা”-য় স্বীকারও করেছে যে ডিফল্ট border-box হওয়াই উচিত ছিল। ২০১২ সালে Paul Irish-এর একটি লেখার পর universal reset সবার অভ্যাস হয়ে যায়, আর আজ Bootstrap, Tailwind-এর মতো প্রায় সব CSS framework নিজেরাই এটি দিয়ে শুরু করে।
মূল উপলব্ধি: নিয়ম মানেই সবসময় সেরা নকশা নয়, আর “ভুল” প্রতিদ্বন্দ্বীর কাছ থেকেও ভালো ধারণা আসতে পারে। ওয়েবের মানদণ্ড পুরোনো ভুল মুছে না ফেলে বিকল্প যোগ করে এগোয় — কারণ কোনো পাতা ভাঙা যাবে না।
প্র ০২margin collapsing এত বিভ্রান্তিকর হলে CSS-এ এটা রাখা হলো কেন? আধুনিক CSS এর সাথে কীভাবে মানিয়ে নিচ্ছে?
margin collapsing-এর জন্ম ছাপা বইয়ের টাইপোগ্রাফি থেকে। CSS-এর প্রথম লক্ষ্য ছিল দলিল সাজানো — শিরোনাম, প্যারাগ্রাফ, তালিকা। ছাপাখানার নিয়মে প্রতিটি অংশ বলে “আমার আগে-পরে অন্তত এতটা ফাঁকা চাই”, আর দুই অংশের মাঝে ফাঁক হয় দুটির মধ্যে বড় চাওয়াটি, যোগফল নয়। ব্রাউজারের ডিফল্ট CSS-এ p-এর ওপর-নিচে 1em margin; collapsing না থাকলে প্রতিটি প্যারাগ্রাফের মাঝে 2em ফাঁক হতো, আর পাতার প্রথম প্যারাগ্রাফের ওপরে মাত্র 1em — অসমান দেখাত। আবার একটি <h2>-এর বড় margin আর তার পরের <p>-এর ছোট margin মিশে একটি সুন্দর ফাঁক তৈরি করে, লেখককে কিছু হিসাব করতে হয় না। CSS 2.1-এর নিয়মে এই আচরণ বিস্তারিত লেখা আছে।
সমস্যাটা আসে যখন আমরা দলিল নয়, “কম্পোনেন্ট” বানাই — কার্ড, ব্যানার, মডাল। তখন একটি কার্ডের ভেতরের শিরোনামের margin কার্ডের বাইরে চলে যাওয়া (parent-child collapsing) অদ্ভুত লাগে। তাই আধুনিক CSS কয়েকভাবে মানিয়ে নিচ্ছে। Flexbox আর Grid-এ collapsing নেই, আর তাদের gap property item-দের মাঝে ফাঁক দেয় প্রথম আর শেষ item-এর বাইরে কোনো বাড়তি margin ছাড়াই। display: flow-root এসেছে শুধু একটি পরিষ্কার block formatting context বানানোর জন্য, কোনো পার্শ্বপ্রতিক্রিয়া ছাড়া। অনেক দল নিয়ম করে নিয়েছে “শুধু এক দিকে margin দাও” — যেমন সবসময় শুধু margin-bottom বা শুধু margin-top, যাতে collapsing নিয়ে ভাবতেই না হয়। ২০১৪ সালে Heydon Pickering-এর জনপ্রিয় করা “lobotomized owl” selector * + *-ও একই ভাবনার — শুধু আগে কেউ থাকলে তবেই ওপরে margin. আরেকটি নতুন property margin-trim parent-এর কিনারায় child-দের margin কেটে দিতে পারে, তবে এটি এখনো মূলত Safari-তে আছে, Baseline নয় — Can I use দেখে নিন।
মূল উপলব্ধি: margin collapsing কোনো বাগ নয়, দলিলের জন্য তৈরি একটি সুচিন্তিত নিয়ম। কম্পোনেন্টের যুগে সমস্যা এড়ানোর সবচেয়ে ভালো উপায় হলো নিয়মটা জানা, আর যেখানে দরকার flex/grid-এর gap বা flow-root বেছে নেওয়া।
প্র ০৩padding-top: 50% লিখলে সেটা parent-এর উচ্চতার নয়, চওড়ার অর্ধেক হয় — এই অদ্ভুত নিয়মের পেছনে কী যুক্তি, আর এর ফল কী হয়েছে?
যুক্তিটা লেআউটের হিসাবের ক্রমে লুকানো। সাধারণ block লেআউটে ব্রাউজার আগে চওড়া ঠিক করে — parent কত চওড়া, তা জানা থাকে, কারণ বাইরে থেকে ভেতরের দিকে চওড়া নেমে আসে। কিন্তু উচ্চতা হিসাব হয় উল্টো দিক থেকে: ভেতরের সব জিনিস সাজানো শেষ হলে তবেই parent জানে সে কত উঁচু। এখন ভাবুন, child-এর padding-top যদি parent-এর উচ্চতার শতাংশ হতো — child-এর padding জানতে parent-এর উচ্চতা লাগবে, আর parent-এর উচ্চতা জানতে child-এর padding লাগবে। ডিম আগে না মুরগি আগে! এমন চক্রাকার নির্ভরতা এড়াতে CSS ঠিক করল, চার দিকের padding আর margin-এর শতাংশ — সবই containing block-এর চওড়া (আরও ঠিক করে বললে, লেখার দিক অনুযায়ী inline size) থেকে হিসাব হবে।
এর একটি বড় সুবিধাও হলো: চার দিকে padding: 5% দিলে চার দিকেই সমান ফাঁক পাওয়া যায়, যা উচ্চতা থেকে হিসাব হলে হতো না।
আর এই নিয়ম থেকেই জন্ম নিয়েছিল বিখ্যাত “intrinsic ratio” বা padding hack. বহু বছর ধরে ভিডিও এমবেডকে রেসপন্সিভ রাখার একমাত্র উপায় ছিল একটি wrapper-এ height: 0; padding-bottom: 56.25% দেওয়া (16:9 অনুপাতের জন্য 9 ÷ 16), আর ভেতরের iframe-কে absolute position দিয়ে পুরো জায়গা জুড়ে বসানো। কৌশলটা কাজ করত, কিন্তু পড়তে দুর্বোধ্য — নতুন কেউ দেখলে বুঝতেই পারতেন না 56.25% কোথা থেকে এলো। অনেক বছর পর CSS-এ এসেছে aspect-ratio, যা এখন Baseline Widely available: aspect-ratio: 16 / 9 — কোডই বলে দেয় উদ্দেশ্য কী।
মূল উপলব্ধি: CSS-এর অনেক “অদ্ভুত” নিয়মের পেছনে থাকে লেআউট ইঞ্জিনের হিসাবের ক্রম। নিয়মের কারণ বুঝলে তা মনে রাখাও সহজ হয়, আর পুরোনো কোডের রহস্যময় কৌশলও চিনে নেওয়া যায় — তখন তার আধুনিক, পরিষ্কার বিকল্প বেছে নিতে পারবেন।
প্র ০৪margin-top, margin-left — এগুলো “বাঁ-ডান-ওপর-নিচ” ধরে লেখা। আরবি বা উর্দুর মতো ডান থেকে বাঁয়ে লেখা ভাষায় বা খাড়া লেখায় box model কীভাবে চলে?
এই প্রশ্নটা CSS-কে বহু বছর ভাবিয়েছে। margin-left, padding-right-এর মতো property-দের বলে “physical” property — এরা পর্দার দিক ধরে কথা বলে। বাংলা বা ইংরেজির মতো বাঁ থেকে ডানে লেখা ভাষায় “লেখা শুরুর দিক” মানে বাঁ, তাই margin-left দিয়ে লেখার আগে ফাঁক রাখা যায়। কিন্তু আরবি, উর্দু বা হিব্রুতে লেখা শুরু হয় ডান দিক থেকে (dir="rtl"). একটি বহুভাষী সাইট — যেমন প্রবাসী শ্রমিকদের জন্য বাংলা আর আরবি দুই ভাষার কোনো সেবা — বানাতে গেলে প্রতিটি margin-left-কে আরবি সংস্করণে margin-right-এ উল্টে দিতে হতো। জাপানি বা চীনা ভাষায় আবার ওপর থেকে নিচে খাড়া লেখাও হয়।
CSS-এর উত্তর হলো “logical” property: margin-inline-start মানে “লেখা যেদিক থেকে শুরু হয়”, margin-block-end মানে “লাইনগুলো যেদিকে জমা হয়, তার শেষ দিক”। বাংলায় inline-start = বাঁ, আরবিতে = ডান — একই CSS দুই ভাষাতেই ঠিক কাজ করে। shorthand-ও আছে: margin-inline: auto দিয়ে মাঝখানে বসানো, padding-block: 1rem দিয়ে ওপর-নিচে ফাঁক। Logical property এখন Baseline Widely available, বিস্তারিত পর্ব ৩৫-এ।
মজার ব্যাপার, box model-এর কিছু নিয়ম আগে থেকেই আসলে “logical”. margin collapsing হয় block দিকে — সাধারণ লেখায় ওপর-নিচে, কিন্তু খাড়া লেখায় বাঁ-ডানে! padding আর margin-এর শতাংশও আসলে inline size থেকে হিসাব হয়, যা সাধারণ লেখায় চওড়া। CSS-এর নতুন spec-গুলো তাই “width/height”-এর বদলে প্রায়ই “inline size/block size” ভাষায় লেখা হয়। বাংলাদেশের ডেভেলপাররা যখন মধ্যপ্রাচ্য বা বিশ্ববাজারের ক্লায়েন্টের কাজ করেন, তখন শুরু থেকে logical property-তে ভাবলে পরে পুরো CSS নতুন করে লিখতে হয় না।
মূল উপলব্ধি: “বাঁ” আর “ডান” সব ভাষার জন্য এক নয়। পর্দার দিক নয়, লেখার প্রবাহ ধরে ভাবা শিখলে আপনার CSS পৃথিবীর যেকোনো ভাষার জন্য তৈরি থাকবে।
প্র ০৫focus দেখানোর জন্য ব্রাউজার border নয়, outline ব্যবহার করে — এই নকশার সিদ্ধান্তটা কেন গুরুত্বপূর্ণ, আর অ্যাক্সেসিবিলিটির সাথে এর সম্পর্ক কী?
কল্পনা করুন, Tab চাপলে focus যে বোতামে যায় সেটার চারপাশে 3px border যোগ হলো। border box model-এর অংশ, তাই বোতামটা চার দিকে 3px বড় হবে, পাশের লিংক সরে যাবে, নিচের লাইন নেমে যাবে। প্রতিবার Tab চাপলে পুরো পাতা একটু করে লাফাবে — দেখতে বিরক্তিকর, আর যাঁদের চোখে বা মনোযোগে সমস্যা আছে, তাঁদের জন্য বিভ্রান্তিকর। outline জায়গা নেয় না, তাই সে আসলে-গেলে লেআউট একচুলও নড়ে না, পাতার কোনো হিসাব নতুন করে করতে হয় না। focus-এর মতো ঘন ঘন বদলানো সূচকের জন্য এটাই আদর্শ।
এখানেই অ্যাক্সেসিবিলিটির প্রশ্ন। যাঁরা মাউস ব্যবহার করতে পারেন না — হাতে কাঁপুনি, পক্ষাঘাত, দৃষ্টিপ্রতিবন্ধিতা, বা শুধু ভাঙা মাউস — তাঁরা কীবোর্ডে Tab চেপে পাতা চালান। focus-এর দাগই তাঁদের কাছে মাউসের কার্সর। WCAG 2.2-এর 2.4.7 (Focus Visible, লেভেল AA) বলে focus দৃশ্যমান থাকতে হবে; নতুন যোগ হওয়া 2.4.11 (Focus Not Obscured — Minimum) বলে focus পাওয়া element অন্য কিছুর নিচে পুরো ঢাকা পড়তে পারবে না; আর 2.4.13 (Focus Appearance, লেভেল AAA) দাগ কতটা পুরু আর কতটা contrast-এর হওয়া উচিত তা বলে। outline: none লিখে দাগ মুছে দেওয়া তাই নিছক নকশার পছন্দ নয় — এটি অনেক মানুষের জন্য পাতাটাকে অন্ধকার ঘরে পরিণত করে।
outline-এর দুর্বলতাও ছিল: অনেক বছর ব্রাউজারে outline বাঁকা কোণ মানত না, গোল বোতামের চারপাশে চৌকো দাগ দেখাত — তাই ডিজাইনাররা মুছে ফেলতেন। এখন আধুনিক ব্রাউজারগুলো outline-কে border-radius মেনে আঁকে, আর outline-offset দিয়ে দাগ একটু দূরে রেখে সুন্দর করা যায়। :focus-visible দিয়ে শুধু কীবোর্ড ব্যবহারকারীদের দাগ দেখানোর কৌশল আসবে পর্ব ৩৪ ও ৪৫-এ।
মূল উপলব্ধি: “জায়গা নেয় কি না” — box model-এর এই ছোট্ট প্রশ্নের উত্তরে ঠিক হয় পাতা স্থির থাকবে নাকি লাফাবে। চেহারার জন্য border, সাময়িক সূচকের জন্য outline — আর focus-এর দাগ কখনো শুধু মুছে ফেলবেন না।
অনুশীলন
হাতে হিসাব, DevTools-এ দেখা আর এডিটরে পরীক্ষা — তিনটিই কাজে লাগান।
-
DevTools-এ বাক্স পড়ুন: এই পাতারই যেকোনো একটি প্যারাগ্রাফে ডান-ক্লিক করে Inspect চাপুন। Computed (বা Firefox-এ Layout) ট্যাবের box-model ছবি থেকে content, padding, border আর margin-এর মান লিখে নিন। প্যারাগ্রাফটির চোখে দেখা চওড়া কত হওয়ার কথা হিসাব করুন, তারপর ছবির content অংশে মাউস রেখে মিলিয়ে দেখুন।
সাধারণত দেখবেন প্যারাগ্রাফের padding আর border 0, শুধু ওপরে বা নিচে কিছু margin আছে, আর content-এর চওড়া একটি ভগ্নাংশ-সংখ্যাও হতে পারে (যেমন 712.4). যেহেতু padding আর border নেই, চোখে দেখা চওড়া = content-এর চওড়া। margin-এর অংশে মাউস রাখলে পাতার ওপর কমলা রঙে সেই ফাঁক দেখা যাবে — পাশের প্যারাগ্রাফের margin-এর সাথে মিশে যাচ্ছে কি না, সেটাও চোখে পড়বে। Elements প্যানেলের Styles অংশে margin কোথা থেকে এসেছে (এই সাইটের CSS না ব্রাউজারের ডিফল্ট), তাও লেখা থাকে।
-
হাতে হিসাব: একটি বোতামের CSS —
width: 160px; height: 40px; padding: 8px 16px; border: 2px solid; margin: 10px 4px;(box-sizing ডিফল্ট)। (ক) চোখে দেখা চওড়া ও উচ্চতা কত? (খ) পাতায় অনুভূমিকভাবে কত জায়গা নেয়? (গ)box-sizing: border-boxদিলে content-এর চওড়া ও উচ্চতা কত হবে?(ক) চওড়া = 160 + 16 + 16 + 2 + 2 = 196px; উচ্চতা = 40 + 8 + 8 + 2 + 2 = 60px. খেয়াল করুন, shorthand-এ প্রথম মান 8px ওপর-নিচের, দ্বিতীয় 16px বাঁ-ডানের।
(খ) 196 + 4 + 4 = 204px (margin-এর দ্বিতীয় মান 4px বাঁ-ডানের)।
(গ) চোখে দেখা মাপ এবার 160 × 40. content-এর চওড়া = 160 − 32 − 4 = 124px, উচ্চতা = 40 − 16 − 4 = 20px. লেখার line-height যদি 20px-এর বেশি হয়, লেখা বাক্সের বাইরে উপচে পড়বে — নির্দিষ্ট height দেওয়ার ঝুঁকি এখানেই।
-
রহস্যময় ফাঁক সারান: একজন লিখলেন —
.card { background: #fff; }আর.card h3 { margin-top: 24px; }. তিনি চেয়েছিলেন শিরোনাম কার্ডের ভেতরে একটু নিচে বসুক, কিন্তু দেখলেন শিরোনাম কার্ডের ওপরের কিনারায় লেগে আছে আর পুরো কার্ড নিচে নেমে গেছে। কেন হলো, আর দুটি আলাদা সমাধান কী?এটি parent-child margin collapsing. কার্ডের ওপরে কোনো padding বা border নেই, তাই h3-এর 24px margin কার্ডের নিজের ওপরের margin-এর সাথে মিশে কার্ডের বাইরে চলে গেছে। সমাধান:
/* সমাধান ১: কার্ডকে নতুন block formatting context বানান */ .card { display: flow-root; } /* সমাধান ২ (বেশিরভাগ কার্ডে স্বাভাবিক): ভেতরের ফাঁক padding দিয়ে দিন */ .card { padding: 24px; } .card h3 { margin-top: 0; }দ্বিতীয়টিই সাধারণত ভালো: কার্ডের ভেতরের ফাঁক কার্ডের padding-এর দায়িত্ব, ভেতরের শিরোনামের margin-এর নয়। কার্ডে
display: flex; flex-direction: columnদিলেও collapsing বন্ধ হতো। -
AI অডিট: যেকোনো AI-কে বলুন “একটি রেসপন্সিভ প্রোফাইল কার্ডের HTML আর CSS লেখো।” তারপর অংশ ৯-এর চেকলিস্ট আর ভুলের টেবিল ধরে কোডটি যাচাই করুন। কোন কোন জায়গায় সমস্যা পেলেন?
সাধারণত যা পাওয়া যায়:
- box-sizing reset নেই, অথচ কোথাও
width: 100%আর padding একসাথে — 320px চওড়ায় দেখলে পাশে স্ক্রল আসে। - কার্ডে নির্দিষ্ট
width: 350px— ছোট ফোনে বেরিয়ে যায়;max-widthহওয়া উচিত ছিল। - প্রোফাইল ছবিতে নির্দিষ্ট width-height, কিন্তু
aspect-ratioবাobject-fitনেই — ভিন্ন মাপের ছবিতে চেপ্টা দেখায়। - বোতামে
outline: none— Tab চাপলে কিছুই দেখা যায় না।
প্রতিটি ভুল DevTools-এর box-model ছবি আর device toolbar দিয়ে প্রমাণ করুন, তারপর AI-কে নির্দিষ্ট করে বলুন কী বদলাতে হবে — “আরও ভালো করো” নয়।
- box-sizing reset নেই, অথচ কোথাও
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমএকটি CSS বাক্সের অংশগুলো ভেতর থেকে বাইরের দিকে সাজান (▲▼ চেপে সরান)
- 🖼️ content — লেখা বা ছবি
- 🟩 padding — ভেতরের ফাঁক, ব্যাকগ্রাউন্ড দেখা যায়
- 🟫 border — বাক্সের পাড়
- 🟧 margin — বাইরের স্বচ্ছ ফাঁক
- 🧱 পাশের element
কোনো box-sizing না লিখে একটি div-এ width: 200px; padding: 10px; border: 2px solid; দেওয়া হলো। পর্দায় div-টির চোখে দেখা চওড়া কত?
- 200px
- 212px
- 224px
- 176px
box-sizing: border-box; width: 300px; padding: 20px; border: 5px solid; — এই বাক্সের content-এর চওড়া কত?
- 300px
- 250px
- 350px
- 260px
margin: 10px 20px 30px; লিখলে বাঁ দিকের margin কত হবে?
- 10px
- 20px
- 30px
- 0
সাধারণ block লেআউটে পরপর দুটি div — ওপরেরটির margin-bottom: 40px, নিচেরটির margin-top: 25px, মাঝে আর কিছু নেই। দুটির মাঝে ফাঁক কত?
- 40px
- 65px
- 25px
- 15px
নিচের কোনটি element-এর চারপাশে দাগ আঁকে কিন্তু লেআউটে কোনো জায়গা নেয় না, ফলে পাশের element সরে না?
- border
- padding
- margin
- outline
একটি প্যারাগ্রাফের ভেতরের <span>-এ (display বদলানো হয়নি) margin-top: 30px দেওয়া হলো। কী ঘটবে?
- span-এর লাইনটি 30px নিচে নেমে যাবে
- span নতুন লাইনে চলে যাবে
- লেআউটে কিছুই বদলাবে না
- ব্রাউজার Console-এ error দেখাবে
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- প্রতিটি element একটি বাক্স: ভেতর থেকে content → padding → border → margin — ছবি, ম্যাট, ফ্রেম, দেয়ালের ফাঁকা।
- ডিফল্ট content-box-এ চোখে দেখা চওড়া = width + দুই পাশের padding + দুই পাশের border; margin বাক্সের বাইরে জায়গা নেয়।
- প্রতিটি প্রজেক্টের শুরুতে
*, *::before, *::after { box-sizing: border-box; }— তখন width মানে পুরো বাক্স। - shorthand: ওপর → ডান → নিচ → বাঁ; না লেখা দিক উল্টো দিকের মান নেয়। ওপর-নিচের margin block লেআউটে মিশে যায়, flex/grid-এ নয়।
margin: 0 auto+max-widthদিয়ে মাঝখানে; outline জায়গা নেয় না; inline বাক্সে ওপর-নিচের margin কাজ করে না।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ২০ · একক আর রং — px, rem, %, vw এবং hex, rgb, hsl, oklchপরবর্তী পর্বমাপের একক আর রঙের আধুনিক লেখার নিয়ম।
- HTML ও CSS · কোর্স হোম৫৯টি পর্বপুরো কোর্সের রোডম্যাপ — কোন পর্ব কখন।
- JavaScript · DOM-এর ভিত্তিপাশের ট্র্যাকJavaScript দিয়ে element খুঁজে তার মাপ আর স্টাইল পড়া-বদলানো।
- কম্পিউটার ফান্ডামেন্টালস · প্রথম HTML পেজঝালিয়ে নিনHTML আর CSS-এর একেবারে শুরুর ধারণা, সংক্ষেপে।