সরাসরি পর্বে যান
পর্ব ২৩ · ৫৯-এর মধ্যে · মডিউল ৪

Normal flow, display আর overflow — ব্রাউজার কীভাবে সাজায়

Normal Flow, display & overflow — How the Browser Lays Out a Page

Taught in Bangla, this lesson explains how the browser lays out a page: normal flow, block and inline boxes, the display property and its outer and inner values, six ways to hide content and their effect on screen readers and keyboards, flow-root and block formatting contexts, what float is really for, overflow and scrolling, the viewport and writing-mode, and reading layout in DevTools.

এই পর্বে যা শিখবেন

  • normal flow-এ ব্রাউজার block আর inline বাক্স কোন নিয়মে বসায় — line box, anonymous box আর লেখার দিক (writing mode) সহ
  • display-এর block, inline, inline-block, none, contents আর দুই-শব্দের রূপ (block flex, inline grid)
  • element লুকানোর ছয় উপায়ের পার্থক্য — বিশেষ করে screen reader আর কীবোর্ড ব্যবহারকারীর ওপর প্রভাব
  • block formatting context, flow-root, float-এর আসল কাজ আর clearfix-এর ইতিহাস
  • overflow-এর পাঁচটি মান, ellipsis, line-clamp, scrollbar-gutter, viewport-এর দুই রূপ, block/inline অক্ষ আর DevTools-এ লেআউট পড়া

১ · Normal flow — কিছু না বললেও ব্রাউজার যেভাবে সাজায়

মডিউল ৩-এ আপনি শিখেছেন প্রতিটি element একটি বাক্স (পর্ব ১৯) আর তার মাপ কীভাবে হিসাব হয়। এবার লেআউটের মডিউল — বাক্সগুলো পাতার কোথায় বসবে। প্রথম প্রশ্ন: কোনো লেআউট CSS না লিখলে ব্রাউজার বাক্সগুলো কোথায় বসায়?

উত্তর হলো normal flow — ব্রাউজারের ডিফল্ট সাজানোর নিয়ম। পর্ব ৩ থেকে ১৫-এর সব পাতা এই নিয়মেই সেজেছে। নিয়মটা দুটি ছোট নিয়মের যোগফল:

  • Block বাক্স (block) ওপর থেকে নিচে একটার পর একটা বসে। প্রতিটি নিজের আলাদা সারি নেয়, আর চওড়ায় parent-এর পুরো জায়গা জুড়ে থাকে — নিজের width ছোট করে দিলেও পাশে অন্য block বসে না।
  • Inline বাক্স (inline) লেখার মতো আচরণ করে — বাঁ থেকে ডানে চলে, লাইন ভরে গেলে পরের লাইনে নামে। একটি লম্বা লিংক দুই লাইনে ভেঙেও যেতে পারে।

একটি পরীক্ষার খাতার কথা ভাবুন। প্রশ্নের নম্বর, শিরোনাম, প্রতিটি অনুচ্ছেদ নতুন লাইনে শুরু হয়, ওপর থেকে নিচে জমা হয় — এরা block. অনুচ্ছেদের ভেতরের শব্দগুলো লাইনের ভেতরে বাঁ থেকে ডানে চলে, লাইন ফুরালে পরের লাইনে যায় — এরা inline. ব্রাউজারও ঠিক খাতার মতো লেখে।

নিজের চোখে দেখুন। নিচের পাতায় block বাক্সগুলো নীল দাগে আর inline বাক্সগুলো লাল দাগে ঘেরা:

<style>
  h3, p, div { outline: 2px solid #2563eb; }
  strong, a, span { outline: 2px solid #dc2626; }
</style>
<h3>নতুন অফার</h3>
<p style="width: 230px">আজ <strong>সব রকম চাল</strong> দশ শতাংশ ছাড়ে,
  আর <a href="#d">ঢাকার ভেতরে হোম ডেলিভারি একদম ফ্রি</a> থাকছে।
  অর্ডার করলে <span>চব্বিশ ঘণ্টায়</span> পৌঁছে যাবে।</p>
<div>এটি একটি div</div>
<div style="width: 160px">এটি ছোট div</div>
<div id="d">তবু এটি পাশে বসল না, নিচেই এলো</div>
<span>span এক</span> <span>span দুই</span>

নীল বাক্সগুলো (h3, p, div) একটার নিচে আরেকটা বসেছে। প্যারাগ্রাফকে 230px আর একটি div-কে 160px চওড়া করা হলেও ডান পাশের খালি জায়গায় পরের div ওঠেনি — block বাক্স সারি ভাগ করে না। লাল বাক্সগুলো লেখার সাথেই চলছে; লিংকটি লম্বা, তাই দুই লাইনে ভেঙে গেছে আর তার লাল দাগও দুই টুকরো হয়েছে। শেষ দুটি span একই লাইনে পাশাপাশি। চেষ্টা করুন: প্যারাগ্রাফের width মুছে দিন — লাইনগুলো লম্বা হলো, ভাঙার জায়গা বদলাল। তারপর একটি span-এ style="width: 200px" দিন — কিছুই বদলাবে না; কেন, তা অংশ ২-এ।

এবার ব্রাউজারের মাথার ভেতরে ঢুকি। পাতা আঁকার আগে ব্রাউজার layout ধাপে প্রতিটি বাক্সের জায়গা হিসাব করে — normal flow-এ সেটা হয় কয়েকটি সরল ধাপে:

body — ওপরের বাঁ কোণ থেকে শুরু
h2 · নতুন অফার (পুরো চওড়া)
body
h2 · নতুন অফার
p · নতুন সারিতে, h2-এর নিচে
body
h2 · নতুন অফার
লাইন ১ · আজ সব রকম চাল দশ শতাংশ ছাড়ে, আর
লাইন ২ · ঢাকার ভেতরে হোম ডেলিভারি ফ্রি।
body
h2 · নতুন অফার
লাইন ১ · আজ সব রকম চাল দশ শতাংশ ছাড়ে, আর ঢাকার ভেতরে
লাইন ২ · হোম ডেলিভারি ফ্রি।
div.box
anonymous block · “অফার চলবে”
p · বিস্তারিত শর্ত
anonymous block · “শুক্রবার পর্যন্ত”
  1. প্রথম block বসল। ব্রাউজার parent-এর (এখানে body) content এলাকার ওপরের বাঁ কোণ থেকে শুরু করে। h2 block, তাই পুরো চওড়া নিল — লেখা ছোট হলেও। এই parent-কে বলে containing block: চওড়া কত পাওয়া যাবে, সে-ই ঠিক করে।
  2. দ্বিতীয় block নিচে। p-এর জায়গা h2-এর ঠিক নিচে। মাঝের ডোরাকাটা ফাঁক margin — পর্ব ১৯-এ দেখেছেন, দুই block-এর ওপর-নিচের margin যোগ হয় না, মিশে বড়টি থাকে (margin collapsing). এটাও normal flow-এর নিয়ম।
  3. ভেতরের লেখা লাইনে লাইনে। p-এর ভেতরে শুধু লেখা আর inline element. ব্রাউজার প্রতিটি লাইনের জন্য একটি অদৃশ্য আয়তক্ষেত্র বানায় — line box. লাইন ভরে গেলে পরের line box শুরু হয়।
  4. Inline বাক্স ভেঙে যায়। লিংকটি একটি inline element. লাইনের শেষে জায়গা ফুরিয়েছে, তাই সে দুই টুকরো হলো, প্রতিটি আলাদা line box-এ। DevTools-এ এমন লিংকে মাউস রাখলে দুটি আলাদা আয়তক্ষেত্র দেখবেন। block বাক্স কখনো এভাবে ভাঙে না।
  5. খোলা লেখার জন্য অদৃশ্য বাক্স। একটি div-এর ভেতরে লেখা, তারপর একটি p, তারপর আবার লেখা। একই parent-এ block আর খোলা লেখা পাশাপাশি থাকতে পারে না, তাই ব্রাউজার খোলা লেখাকে নামহীন block-এ মুড়িয়ে নেয় — anonymous block box. এর কোনো element নেই, তাই CSS দিয়ে সরাসরি বাছা যায় না।

একটি কথা বলে রাখি। “ওপর থেকে নিচে”, “বাঁ থেকে ডানে” বাংলা আর ইংরেজির জন্য সত্য। আরবিতে লাইন চলে ডান থেকে বাঁয়ে, আর জাপানি বই অনেক সময় খাড়া লেখা হয়। তাই CSS-এর আসল নিয়মটা দিক দিয়ে নয়, লেখার প্রবাহ দিয়ে বলা: block বাক্স জমা হয় “block দিকে”, inline বাক্স চলে “inline দিকে”। লেখার দিক বদলায় writing-mode property — অংশ ৮-এ হাতে-কলমে দেখবেন।

মূল ধারণা

Normal flow কোনো “লেআউট নেই” অবস্থা নয় — এটি নিজেই একটি পূর্ণ লেআউট পদ্ধতি। ভালো CSS-এর প্রথম নিয়ম: normal flow-এর সাথে লড়বেন না; যেখানে সে কাজ করে না, শুধু সেখানে Flexbox, Grid বা positioning আনুন।

২ · display — বাক্সটা কেমন আচরণ করবে

কোন element block আর কোনটা inline, সেটা HTML ঠিক করে না — ঠিক করে CSS-এর display property. ব্রাউজারের নিজস্ব CSS-এ (user-agent stylesheet) লেখা আছে p, div, h1, ul … { display: block; }; আর যে element-এর জন্য কিছু লেখা নেই (যেমন span, strong, a), তার ডিফল্ট মান inline. তাই আপনি চাইলে যেকোনো element-এর আচরণ বদলে দিতে পারেন — তার অর্থ (semantics) না বদলেই। একটি <a>-কে block বানালেও সে লিংকই থাকে।

প্রতিদিনের কাজে চারটি মান সবচেয়ে বেশি লাগে। নিচের এডিটরে দুটি “ট্যাগ” লেবেল আছে, যাদের width, height, padding আর margin সব দেওয়া — শুধু display বদলে দেখুন কোনটা কাজ করে:

p {
  width: 320px;
  line-height: 1.6;
}
.tag {
  display: inline;   /* block, inline-block, none করে দেখুন */
  width: 110px;
  height: 36px;
  padding: 6px 8px;
  margin: 14px 4px;
  background: #fef3c7;
  border: 2px solid #d97706;
}

inline-এ ট্যাগ দুটি লেখার সাথেই আছে; width আর height-এর কোনো প্রভাব নেই, ওপর-নিচের margin-ও কাজ করছে না, আর ওপর-নিচের padding-এর হলুদ রং পাশের লাইনের ওপর চড়ে বসেছে — কিন্তু লাইনগুলো সরেনি। এবার inline-block লিখুন: ট্যাগ এখনো লাইনের ভেতরেই, কিন্তু 110 × 36-এর পুরো বাক্স হয়ে গেছে, আর লাইনের উচ্চতা তাকে জায়গা দিতে বেড়ে গেছে। block লিখলে প্রতিটি ট্যাগ লেখা ভেঙে নিজের সারিতে চলে যায়। none-এ ট্যাগ দুটি নেই — লেখা জোড়া লেগে গেছে, যেন কোনোদিন ছিলই না। শেষে চেষ্টা করুন display: inline flow-root — ফল হুবহু inline-block-এর মতো; কেন, তা অংশ ৪-এ।

মাননতুন সারি?width / heightওপর-নিচের marginডিফল্ট যাদের
blockহ্যাঁ, পুরো চওড়া নেয়কাজ করেকাজ করে (এবং মিশতে পারে)p, div, h1–h6, ul, section…
inlineনা, লাইনে থাকে, ভাঙতে পারেউপেক্ষিতউপেক্ষিতspan, a, strong, em, code…
inline-blockনা, লাইনে থাকে, কিন্তু ভাঙে নাকাজ করেকাজ করে, লাইন বড় হয়button, input, select (প্রায় এমন)
noneকোনো বাক্সই নেই——head, script, style, [hidden]

inline-block বোতাম, ব্যাজ আর ছোট লেবেলের প্রিয় মান — বাইরে inline (লাইনে বসে), ভেতরে block (নিজের মাপ রাখে)। একটি ছোট অভ্যাস জেনে রাখুন: পাশাপাশি দুটি inline-block-এর মাঝে HTML-এর স্পেস বা লাইন-ভাঙা থেকে একটি শব্দ-ফাঁক থাকে। পাশাপাশি সাজানোর কাজ আজ Flexbox-এর gap দিয়ে হয় (পর্ব ২৫), সেখানে এই ঝামেলা নেই।

একটি সাধারণ ভুল: “লিংকটা বড় করতে চাই” ভেবে a { height: 48px; } লেখা। inline লিংকে height কাজ করে না। আঙুলে চাপার মতো বড় জায়গা চাইলে লিংকে display: inline-block (বা block) দিয়ে padding দিন। WCAG 2.2-এর নতুন নিয়ম 2.5.8 (Target Size — Minimum) বলে চাপার জায়গা সাধারণত অন্তত 24 × 24 CSS পিক্সেল হওয়া উচিত (কিছু ব্যতিক্রম আছে, যেমন লেখার ভেতরের লিংক) — ফোনে বোতাম মিস করা বিরক্তিকর, আর হাতে কাঁপুনি থাকলে প্রায় অসম্ভব।

৩ · লুকানোর ছয় উপায় — চোখ, জায়গা, screen reader আর কীবোর্ড

display: none দেখে মনে হতে পারে লুকানোর কাজ শেষ। কিন্তু একটি পাতা শুধু চোখে দেখা হয় না। screen reader পাতা পড়ে শোনায়, কীবোর্ড ব্যবহারকারী Tab চেপে এক বোতাম থেকে আরেক বোতামে যান। তাই “লুকানো” বলতে চারটি আলাদা প্রশ্ন: চোখে দেখা যায় কি? জায়গা দখল করে কি? screen reader পড়ে কি? Tab-এ focus যায় কি? নিচের এডিটরে প্রতিটি সারিতে “আগে” আর “পরে”-র মাঝে একটি বোতাম আছে, প্রতিটি আলাদা উপায়ে লুকানো:

<style>
  .slot { display: inline-block; padding: 4px; background: #fde68a; }
  .none { display: none; }
  .vis  { visibility: hidden; }
  .op   { opacity: 0; }
</style>
<p>display: none → আগে<span class="slot none"><button>বোতাম ১</button></span>পরে</p>
<p>visibility: hidden → আগে<span class="slot vis"><button>বোতাম ২</button></span>পরে</p>
<p>opacity: 0 → আগে<span class="slot op"><button>বোতাম ৩</button></span>পরে</p>
<p>hidden attribute → আগে<span class="slot" hidden><button>বোতাম ৪</button></span>পরে</p>
<p>লুকানো নয় → আগে<span class="slot"><button>বোতাম ৫</button></span>পরে</p>
<script>
  document.querySelectorAll('button').forEach(function (b) {
    b.addEventListener('click', function () { console.log('ক্লিক হলো: ' + b.textContent); });
    b.addEventListener('focus', function () { console.log('focus পেল: ' + b.textContent); });
  });
</script>

প্রথম সারিতে “আগেপরে” জোড়া লেগে গেছে — বাক্সই নেই। দ্বিতীয় আর তৃতীয় সারিতে মাঝে ফাঁকা জায়গা — বাক্স আছে, শুধু দেখা যাচ্ছে না। এবার প্রিভিউর ভেতরে একবার ক্লিক করে বারবার Tab চাপুন আর নিচের লগ দেখুন: বোতাম ৩ (opacity: 0) focus পায়! অদৃশ্য অবস্থায় তার জায়গায় মাউসে ক্লিক করলেও “ক্লিক হলো: বোতাম ৩” আসবে। আর চতুর্থ সারিতে অবাক কাণ্ড — hidden দেওয়া থাকলেও বোতাম ৪ দেখা যাচ্ছে! কারণ .slot ক্লাসের display: inline-block ব্রাউজারের [hidden] { display: none } নিয়মকে হারিয়ে দিয়েছে। চেষ্টা করুন: <style>-এর শেষে [hidden] { display: none !important; } যোগ করুন — বোতাম ৪ এবার সত্যিই লুকাল।

উপায়চোখে দেখা যায়?জায়গা নেয়?screen reader পড়ে?Tab / ক্লিক কাজ করে?কখন ব্যবহার করবেন
display: noneনানানানামেনু বা ট্যাব বন্ধ থাকলে — সবার কাছ থেকে লুকাতে
hidden attributeনানানানাHTML-এই বলে দেওয়া “এখন প্রাসঙ্গিক নয়”; CSS-এর display যেন উল্টে না দেয়
visibility: hiddenনাহ্যাঁনানাজায়গা ধরে রেখে লুকাতে, যাতে লেআউট না লাফায়
opacity: 0নাহ্যাঁহ্যাঁহ্যাঁশুধু animation-এর মাঝপথে; একা লুকানোর উপায় হিসেবে বিপজ্জনক
aria-hidden="true"হ্যাঁহ্যাঁনাহ্যাঁশুধু সাজসজ্জার আইকন; ভেতরে বোতাম বা লিংক থাকলে কখনো নয়
visually-hidden ক্লাসনাপ্রায় নাহ্যাঁহ্যাঁশুধু screen reader-এর জন্য লেখা, যেমন আইকন-বোতামের নাম

আরও তিনটি কথা। visibility: hidden child-এ উত্তরাধিকারে যায়, কিন্তু child নিজে visibility: visible লিখলে আবার দেখা দেয় — display: none-এর ভেতর থেকে কেউ এভাবে বেরোতে পারে না। aria-hidden="true"-এর ভেতরে focus পাওয়ার মতো কিছু থাকলে screen reader ব্যবহারকারী Tab চেপে এমন বোতামে পৌঁছান, যার নাম বা কাজ কিছুই শোনা যায় না — পরীক্ষার টুলগুলো একে গুরুতর ত্রুটি ধরে। আর পুরো অংশ দেখা গেলেও “অচল” করতে আছে inert attribute (পর্ব ১১)।

visually-hidden ক্লাসটি দেখতে এমন — এখানে position ব্যবহার হয়েছে, যার বিস্তারিত পরের পর্বে:

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

hidden attribute-এর একটি নতুন রূপ আছে — hidden="until-found". এতে অংশটি লুকানো থাকে, কিন্তু ব্যবহারকারী ব্রাউজারের “Find in page” (Ctrl+F) দিয়ে ভেতরের কোনো শব্দ খুঁজলে বা সেই অংশের লিংকে গেলে ব্রাউজার নিজেই খুলে দেয় — লম্বা FAQ বা অ্যাকর্ডিয়নের জন্য চমৎকার। তবে এটি সব প্রধান ব্রাউজারে সম্প্রতি এসেছে বা আসছে, তাই এখনো Baseline Widely available নয়; যে ব্রাউজার চেনে না, সেখানে অংশটি সাধারণ hidden-এর মতো লুকানো থাকে। ব্যবহারের আগে Can I use দেখে নিন। একই কাজের জন্য সব ব্রাউজারে চলা উপায় হলো <details> (পর্ব ১১)।

৪ · display-এর দুই মুখ — বাইরের আচরণ আর ভেতরের সাজ

এতক্ষণ যা দেখলেন, তার ভেতরে একটি কাঠামো আছে। প্রতিটি বাক্সের আসলে দুটি চরিত্র:

  • বাইরের আচরণ (outer display): প্রতিবেশীদের সাথে বাক্সটি কীভাবে বসবে — block-এর মতো নিজের সারিতে, নাকি inline-এর মতো লাইনের ভেতরে।
  • ভেতরের সাজ (inner display): বাক্সটি নিজের ভেতরের child-দের কীভাবে সাজাবে — normal flow-এ (flow), নতুন আলাদা এলাকা বানিয়ে (flow-root), Flexbox-এ (flex), Grid-এ (grid), নাকি টেবিলের নিয়মে (table).

বাজারের একটি দোকানের কথা ভাবুন। বাইরে থেকে দোকানটা সারির অন্য দোকানের পাশে বসেছে, নাকি আলাদা কোনো কোণে — এটা তার বাইরের আচরণ। আর দোকানের ভেতরে তাকগুলো কীভাবে সাজানো — এক সারিতে, নাকি সারি-কলামের ছকে — এটা ভেতরের সাজ। একটি দোকান বাইরে থেকে সারির মাঝে থেকেও ভেতরে ছক কেটে সাজাতে পারে। দুটো আলাদা সিদ্ধান্ত।

CSS-এর আধুনিক নিয়মে আপনি দুটোই একসাথে লিখতে পারেন — একে বলে দুই-শব্দের display (multi-keyword syntax). আর পুরোনো এক-শব্দের মানগুলো আসলে এদেরই সংক্ষিপ্ত রূপ:

এক শব্দে (পরিচিত)দুই শব্দে (পূর্ণ রূপ)বাইরেভেতরে
blockblock flowblocknormal flow
inlineinline flowinlinenormal flow
inline-blockinline flow-rootinlineনতুন BFC
flow-rootblock flow-rootblockনতুন BFC
flex / inline-flexblock flex / inline flexblock / inlineFlexbox
grid / inline-gridblock grid / inline gridblock / inlineGrid
list-itemblock flow list-itemblocknormal flow + বুলেট

টেবিলটা দেখলেই একটি রহস্য খোলে: inline-flex বাইরে inline, ভেতরে flex. display: flex দেওয়া element নিজে block-এর মতো সারি নেয় — flex নিয়মে সাজে তার child-রা। পর্ব ২৫ আর ২৭-এ এই ভাবনাটাই কাজে লাগবে।

দুই-শব্দের রূপ ২০২৩ সাল থেকে সব প্রধান ব্রাউজারে চলে, অর্থাৎ Baseline. তবু বাস্তবে এক-শব্দের রূপই বেশি চলে — পুরোনো ব্রাউজারেও নিরাপদ, ফলও একই। দুই-শব্দের রূপের আসল মূল্য বোঝার কাঠামোয়: “বাইরে আর ভেতরে” ভাবলে প্রতিটি display মান নিজেই ব্যাখ্যা হয়ে যায়।

display: contents — নিজের বাক্স মুছে, child-দের ওপরে তুলে দেওয়া

একটি বিশেষ মান হলো display: contents. এটি element-এর নিজের বাক্স তৈরি করে না, কিন্তু তার child-দের বাক্স ঠিকই তৈরি হয় — যেন element-টির জায়গায় সরাসরি তার child-রা বসে আছে। কাজে লাগে যখন একটি wrapper element (যেমন semantic কারণে রাখা <ul> বা কোনো component-এর বাড়তি div) Flexbox বা Grid-এর পথে বাধা দেয়, আর আপনি চান ভেতরের item-রা সরাসরি বাইরের grid-এর অংশ হোক।

অ্যাক্সেসিবিলিটির সতর্কতা: ব্রাউজার সাপোর্ট বহু বছরের, কিন্তু দীর্ঘ সময় ধরে প্রধান ব্রাউজারগুলোতে একটি গুরুতর বাগ ছিল — display: contents দেওয়া element accessibility tree থেকেও হারিয়ে যেত, ফলে তালিকা আর তালিকা থাকত না, শিরোনাম বা বোতাম তার role হারাত। সাম্প্রতিক সংস্করণগুলোতে এর বড় অংশ ঠিক করা হয়েছে, কিন্তু সব ক্ষেত্রে, সব ব্রাউজারে সমানভাবে নয়। তাই নিরাপদ নিয়ম: বোতাম, লিংক, ফর্ম কন্ট্রোল, টেবিলের অংশ বা heading-এ display: contents দেবেন না; সাধারণ div-এ দিলেও যেখানে অর্থ জরুরি, সেখানে screen reader দিয়ে পরীক্ষা করুন। বাক্স নেই বলে এর নিজের border, background, padding — কিছুই আঁকা হয় না।

আরও গভীরে: ব্রাউজার DOM আর CSS মিলিয়ে একটি আলাদা গাছ বানায় — spec-এর ভাষায় box tree (পর্ব ১-এর render tree-র আধুনিক নাম অনেকটা এটাই)। DOM-এর একটি element থেকে শূন্য, এক বা একাধিক বাক্স তৈরি হতে পারে: display: none হলে শূন্য, display: contents হলে নিজের শূন্য কিন্তু child-দের আছে, list-item হলে মূল বাক্সের সাথে বুলেটের জন্য আরেকটি (::marker), আর অংশ ১-এর anonymous box-রা DOM ছাড়াই জন্মায়। Layout ধাপ চলে এই box tree-র ওপর, DOM-এর ওপর নয় — এজন্যই display: none দেওয়া element-এর মাপ JavaScript দিয়ে পড়লে 0 আসে। আর inline-block-এর মতো বাক্সকে CSS বলে atomic inline: লাইনের ভেতরে সে একটি অক্ষরের মতো অবিভাজ্য, তাই কখনো দুই লাইনে ভাঙে না।

৫ · flow-root আর block formatting context — নিজের এলাকা নিজের নিয়মে

অংশ ১-এ বলেছিলাম, block বাক্সগুলো একটি “সাজানোর এলাকার” ভেতরে ওপর থেকে নিচে বসে। এই এলাকার নাম block formatting context (BFC). পুরো পাতা — <html> element — একটি বড় BFC. কিন্তু কিছু element নিজের ভেতরে একটি নতুন, আলাদা BFC খোলে। নতুন BFC-র তিনটি বড় নিয়ম:

  1. ভেতরের float এর বাইরে বেরোয় না — BFC float-কে পুরোপুরি ধরে রাখে, উচ্চতায়ও।
  2. ভেতরের child-এর margin BFC-র নিজের margin-এর সাথে মেশে না — বাইরে পালায় না।
  3. বাইরের কোনো float BFC-র বাক্সের ওপর চড়ে বসে না — BFC float-এর পাশে সরে জায়গা নেয়।

এক সময় নতুন BFC বানাতে মানুষ overflow: hidden লিখত — কারণ এটিও BFC তৈরি করে। কিন্তু তার পার্শ্বপ্রতিক্রিয়া আছে: বাইরে ছড়ানো ছায়া বা dropdown কেটে যায়। তাই CSS একটি মান যোগ করেছে, যার একমাত্র কাজ পরিষ্কার একটি BFC বানানো: display: flow-root. এটি এখন Baseline Widely available — বহু বছর ধরে সব আধুনিক ব্রাউজারে চলে। ধাপে ধাপে দেখুন সে কোন দুটি সমস্যা সারায় (নিচের ছবিগুলো আসল CSS দিয়ে আঁকা):

ইলিশ — ৳১৬০০/কেজি
ইলিশ — ৳১৬০০/কেজি
পরের কার্ড — এর লেখা ছবির পাশ ঘেঁষে বসেছে, যেন ছবিটা এই কার্ডেরই
ইলিশ — ৳১৬০০/কেজি
display: flow-root
পরের কার্ড — এবার নিজের জায়গায়
শিরোনাম · margin-top: 28px
কার্ডের লেখা
শিরোনাম · margin-top: 28px
কার্ডের লেখা · display: flow-root
  1. float ঝুলে আছে। একটি অনলাইন দোকানের পণ্য-কার্ডে ছবিটি float: left, পাশে নাম আর দাম। float দেওয়া বাক্স normal flow থেকে আংশিক বেরিয়ে যায় — parent তার উচ্চতা হিসাব করার সময় float-কে গোনে না। তাই নীল কার্ডটি শুধু এক লাইন লেখার সমান উঁচু, আর হলুদ ছবি নিচে ঝুলে পড়েছে।
  2. পরের element বিপদে। কার্ডের নিচে আরেকটি অংশ এলো। ঝুলে থাকা float তার লেখাকেও পাশে ঠেলে দিচ্ছে — float-এর নিয়মই হলো আশপাশের লাইনগুলো তার পাশ দিয়ে ঘুরবে। পাতাটা দেখতে ভাঙা লাগে। float দিয়ে লেআউট বানানোর যুগে এটাই ছিল প্রতিদিনের মাথাব্যথা।
  3. display: flow-root. কার্ডটি এখন নিজের ভেতরে নতুন BFC — নিয়ম ১ অনুযায়ী float-কে পুরোপুরি ধরে রাখে। কার্ড ছবির সমান উঁচু হলো, পরের অংশ নিজের জায়গায় নিচে নামল। আগের যুগের “clearfix” কৌশলের পুরো কাজটা এই এক লাইনে (অংশ ৬-এ ইতিহাস)।
  4. পালিয়ে যাওয়া margin. এবার আরেকটি পরিচিত বাগ (পর্ব ১৯-এ দেখেছেন): কার্ডে কোনো border বা padding নেই, ভেতরের শিরোনামে margin-top: 28px. শিরোনামের margin কার্ডের margin-এর সাথে মিশে কার্ডের ওপরে চলে গেছে — ফাঁকটা ধূসর, অর্থাৎ কার্ডের বাইরে। শিরোনাম কার্ডের ওপরের কিনারায় লেগে আছে।
  5. নতুন BFC margin আটকায়। কার্ডে display: flow-root দিতেই নিয়ম ২ কাজ করল — শিরোনামের margin আর বাইরে মেশে না, ফাঁকটা এখন নীল, কার্ডের ভেতরে। খেয়াল করুন, BFC-র ভেতরের দুই ভাইবোনের মাঝের margin কিন্তু এখনো মিশতে পারে; BFC শুধু parent আর child-এর সীমানায় দেয়াল তোলে।

এবার নিজের হাতে। নিচের কার্ডে ছবিটি float, আর কার্ড নিচে ঝুলে থাকা ছবিকে ধরে রাখতে পারছে না:

.card {
  border: 3px solid #0369a1;
  background: #e0f2fe;
  /* display: flow-root; */
}
.photo {
  float: left;
  width: 90px;
  height: 90px;
  margin: 8px;
  background: #fbbf24;
  font-size: 48px;
  text-align: center;
}
.card p { margin: 8px; }
.next { margin: 0; background: #fee2e2; }

নীল কার্ডের দাগ শুধু লেখার চারপাশে, মাছের হলুদ বাক্স নিচে ঝুলছে, আর গোলাপি “পরের অংশ”-এর লেখা ছবির পাশ দিয়ে ঘুরে গেছে। চেষ্টা করুন: /* display: flow-root; */ লাইনের মন্তব্যের চিহ্ন দুটো মুছে দিন — কার্ড ছবিসহ পুরোটা ঘিরে ফেলল। তারপর flow-root-এর বদলে overflow: hidden লিখে দেখুন — একই ফল, কিন্তু ছায়া বা বাইরে বেরোনো কিছু থাকলে কেটে যেত। আরেকটি পথ: .next-এ clear: left দিন — পরের অংশ ছবির নিচে নামল, কিন্তু কার্ড এখনো ছবিকে ঘিরল না।

নতুন BFC আর কারা বানায়, জেনে রাখুন — অনেক “অদ্ভুত” আচরণের ব্যাখ্যা এখানেই: inline-block, float, position: absolute/fixed, visible বা clip ছাড়া অন্য overflow, টেবিলের ঘর, Flexbox ও Grid-এর item, আর contain: layout. Flex বা Grid container-এর ভেতরে margin মেশে না — কারণ সেটা block লেআউটই নয়।

৬ · float — আসলে যে কাজের জন্য তৈরি

পত্রিকার পাতা খুলুন। একটি ছবি বাঁ দিকে বসানো, আর খবরের লেখা ছবির ডান পাশ দিয়ে নেমে ছবি শেষ হলে আবার পুরো চওড়ায় ছড়িয়ে গেছে। ছাপাখানায় একে বলে text wrap. float ঠিক এই কাজের জন্য তৈরি — একটি বাক্সকে বাঁ (left) বা ডান (right) কিনারায় ভাসিয়ে দেওয়া, যাতে আশপাশের লেখা তার চারপাশ দিয়ে বয়ে যায়। নতুন লেখার দিক-নিরপেক্ষ মান inline-start আর inline-end-ও আছে। আর float-এর পাশে না বসে তার নিচে নামতে চাইলে clear: left | right | both.

আধুনিক CSS float-কে একটি সুন্দর বন্ধুও দিয়েছে — shape-outside, যা বলে লেখা কোন আকৃতি ধরে ঘুরবে। এটি Baseline Widely available. নিচে একটি গোল চাঁদ, আর কবিতার লাইন তার বাঁক ধরে বইছে:

.page {
  width: 340px;
  font: 16px/1.6 sans-serif;
}
.moon {
  float: left;
  width: 130px;
  height: 130px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fef9c3, #facc15);
  shape-outside: circle(50%);
  margin: 0 14px 6px 0;
}
p { margin: 0; }

লেখার লাইনগুলোর বাঁ মাথা চাঁদের গোল কিনারা ধরে একটু একটু করে সরে গেছে, আর চাঁদের নিচে এসে লেখা আবার বাঁ কিনারায় ফিরেছে। চেষ্টা করুন: shape-outside লাইনটি মুছে দিন — লেখা এবার চাঁদের চারপাশের চৌকো বাক্স ধরে ঘুরবে, গোলাই নয়। তারপর float: left-কে right করুন, আর margin-এর ডান-বাঁ মান অদলবদল করুন — চাঁদ ডানে উঠে গেল।

float এসেছিল ১৯৯৬ সালের প্রথম CSS নিয়ম CSS1-এ, তারও আগে Netscape-এর <img align="left">-এর অনুকরণে — উদ্দেশ্য শুধু ছবির পাশে লেখা ঘোরানো। কিন্তু তখন পাতার কলাম বানানোর একমাত্র উপায় ছিল <table> (পর্ব ৭-এ দেখেছেন, কেন সেটা খারাপ)। ২০০৩ সালের দিকে Dave Shea-র “CSS Zen Garden” দেখাল, শুধু CSS বদলে একই HTML-এর সম্পূর্ণ ভিন্ন নকশা সম্ভব — আর সেই যুগের CSS লেআউটের প্রধান হাতিয়ার হয়ে উঠল float. সমস্যা ছিল অংশ ৫-এর ঝুলে পড়া float; তা সারাতে জন্ম নিল “clearfix” — parent-এর শেষে একটি অদৃশ্য ::after বাক্স বসিয়ে তাতে clear: both দেওয়া। ২০০০-এর দশক জুড়ে এর অনেক রূপ ঘুরেছে, আর ২০১১ সালে Nicolas Gallagher-এর “micro clearfix” প্রায় সব প্রজেক্টে ঢুকে পড়ে। Bootstrap 3-এর মতো জনপ্রিয় framework-এর grid-ও ভেতরে float-এ চলত; Bootstrap 4 Flexbox-এ চলে যায়। আজ পাতার লেআউটে float-এর কোনো জায়গা নেই — কলামের জন্য Grid, এক সারিতে সাজাতে Flexbox, আর ঝুলে পড়া float ধরতে flow-root. float ফিরে গেছে তার আসল কাজে: লেখার ভেতরে ছবি।

পুরোনো কোড বা AI-এর উত্তরে নিচের মতো clearfix দেখলে চিনে নিন — আর নতুন কোডে এর বদলে display: flow-root লিখুন:

/* ইতিহাস — নতুন কোডে লিখবেন না */
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}

/* আজকের সমাধান */
.card { display: flow-root; }

৭ · overflow — বাক্সে না আঁটলে কী হবে

বাক্সের মাপ নির্দিষ্ট আর ভেতরের জিনিস তার চেয়ে বড় হলে তাকে বলে উপচে পড়া — overflow. বাংলায় এটা প্রায়ই ঘটে, কারণ ইংরেজি বোতামের লেখা অনুবাদে লম্বা হয়ে যায়। CSS-এর ডিফল্ট সিদ্ধান্ত “কিছু লুকাব না” — তথ্য হারানোর চেয়ে কুৎসিত দেখানো ভালো। আচরণ বদলাতে overflow-এর পাঁচটি মান — নিচের বাক্সগুলো আসল CSS দিয়ে আঁকা:

overflow: visible — ঢাকা থেকে কক্সবাজার বাসে প্রায় দশ ঘণ্টা, পথে কুমিল্লার রসমালাই আর চট্টগ্রামের মেজবানি।
বাক্সের নিচের লেখা
overflow: hidden — ঢাকা থেকে কক্সবাজার বাসে প্রায় দশ ঘণ্টা, পথে কুমিল্লার রসমালাই আর চট্টগ্রামের মেজবানি।
বাক্সের নিচের লেখা
overflow: scroll — ঢাকা থেকে কক্সবাজার বাসে প্রায় দশ ঘণ্টা, পথে কুমিল্লার রসমালাই আর চট্টগ্রামের মেজবানি।
বাক্সের নিচের লেখা
overflow: auto — ঢাকা থেকে কক্সবাজার বাসে প্রায় দশ ঘণ্টা, পথে কুমিল্লার রসমালাই আর চট্টগ্রামের মেজবানি।
বাক্সের নিচের লেখা
overflow: clip — ঢাকা থেকে কক্সবাজার বাসে প্রায় দশ ঘণ্টা, পথে কুমিল্লার রসমালাই আর চট্টগ্রামের মেজবানি।
বাক্সের নিচের লেখা
  1. visible — ডিফল্ট। লেখা বাক্সের নিচ দিয়ে বেরিয়ে লাল লেখার ওপর চড়েছে। নিচের লেখা সরেনি — লেআউটের হিসাবে বাক্স এখনো 66px উঁচু; উপচে পড়া অংশ শুধু আঁকা হয়, জায়গা নেয় না।
  2. hidden — কেটে ফেলা। বাইরের অংশ দেখা যায় না, স্ক্রলবারও নেই। কিন্তু বাক্সটি একটি scroll container: JavaScript দিয়ে বা ভেতরের লিংকে focus গেলে লুকানো অংশে স্ক্রল হতে পারে, অথচ ব্যবহারকারী নিজে স্ক্রল করে কাটা লেখা পড়তে পারেন না।
  3. scroll — সবসময় স্ক্রলবার। দরকার না থাকলেও স্ক্রলবারের জায়গা থাকে। ফোন বা Mac-এর মতো ভেসে থাকা স্ক্রলবারের সিস্টেমে স্ক্রল না করা পর্যন্ত বার দেখা যায় না। বাস্তবে কমই লাগে।
  4. auto — দরকার হলে তবেই। জিনিস আঁটলে কিছু নেই, না আঁটলে স্ক্রলবার। প্রায় সব ক্ষেত্রে এটাই ঠিক — চওড়া টেবিল (পর্ব ৭-এর wrapper), কোড ব্লক, চ্যাটের বার্তার তালিকা।
  5. clip — শুধু কাটা, আর কিছু না। চোখে hidden-এর মতো, কিন্তু scroll container নয়, নতুন BFC-ও নয় — তাই position: sticky (পর্ব ২৪) নষ্ট করে না, যা hidden প্রায়ই করে। overflow-clip-margin দিয়ে কাটার রেখা একটু বাইরে সরানো যায়। ২০২২ সাল থেকে সব প্রধান ব্রাউজারে আছে, এখন Baseline.

নিজে বদলে দেখুন — আর সাথে একটি ছোট নতুন property:

.box {
  width: 230px;
  height: 70px;
  padding: 8px;
  border: 2px solid #475569;
  background: #f1f5f9;
  overflow: visible;      /* hidden, scroll, auto, clip */
  scrollbar-gutter: auto; /* stable করে দেখুন */
}
p { color: #b91c1c; }

শুরুতে লেখা বাক্স থেকে বেরিয়ে লাল লাইনের ওপর পড়েছে। overflow-কে একে একে hidden, auto, clip করুন — লাল লাইন কখনো নড়ে না, কারণ বাক্সের উচ্চতা বদলায়নি। এবার auto রেখে লেখাটা ছোট করার কথা ভাবুন: স্ক্রলবার এলে-গেলে ভেতরের লেখার চওড়া একটু বদলায় আর লেখা লাফায়। সেই লাফ থামাতে scrollbar-gutter: stable লিখুন — স্ক্রলবার না থাকলেও তার জায়গা খালি রাখা হয় (ভেসে থাকা স্ক্রলবারের সিস্টেমে, যেমন অনেক ফোনে, এর প্রভাব দেখা যায় না)।

scrollbar-gutter তুলনামূলক নতুন — ২০২৪ সালের শেষে শেষ প্রধান ব্রাউজারটিও যোগ দেওয়ায় এটি Baseline Newly available. পুরোনো ব্রাউজারে লাইনটা উপেক্ষিত হয়, তাই নিরাপদ। মডাল খুলে পেছনের স্ক্রল বন্ধ করলে পুরো পাতা পাশে লাফানোর চেনা সমস্যার পরিষ্কার সমাধান html { scrollbar-gutter: stable; }.

overflow-x, overflow-y আর একটি অবাক করা নিয়ম

দুই দিক আলাদা করেও বলা যায়: overflow-x আর overflow-y, বা shorthand-এ overflow: hidden auto (প্রথমটি x). কিন্তু একটি নিয়ম প্রায় সবাইকে বিপদে ফেলে: এক দিক visible আর অন্য দিক hidden, scroll বা auto হলে, ব্রাউজার visible-কে auto বানিয়ে দেয়। তাই “অনুভূমিক দিকে স্ক্রল, কিন্তু dropdown নিচে বাইরে বেরোক” — এমন বাক্স overflow দিয়ে হয় না; scroll container দুই দিকেই scroll container. (clip আর visible-এর জোড়া ব্যতিক্রম।)

এক লাইনে “…” আর কয়েক লাইনে কাটা

অনলাইন দোকানের পণ্যের তালিকায় লম্বা নামগুলো সব কার্ডে সমান জায়গা নিক, বাকিটা “…” দিয়ে বোঝানো হোক — এটি খুব প্রচলিত চাহিদা। এক লাইনের জন্য text-overflow: ellipsis একা কাজ করে না; তিনটি লাইন একসাথে লাগে। আর কয়েক লাইনের জন্য আছে line-clamp:

p {
  width: 260px;
  padding: 0 6px;
  border: 1px solid #cbd5e1;
  font: 16px/1.5 sans-serif;
}
.one {
  white-space: nowrap;      /* ১. লাইন ভাঙবে না */
  overflow: hidden;         /* ২. বাইরের অংশ কাটা */
  text-overflow: ellipsis;  /* ৩. কাটার জায়গায় … */
}
.clamp {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;    /* ৩ বা ৪ করে দেখুন */
  overflow: hidden;
}

প্রথম লাইনটি বাক্সের শেষে “…” দিয়ে থেমেছে; দ্বিতীয় প্যারাগ্রাফ ঠিক দুই লাইন দেখিয়ে শেষে “…” দিয়েছে। চেষ্টা করুন: .one থেকে white-space: nowrap মুছুন — লেখা কয়েক লাইনে ভেঙে গেল, ellipsis-এর আর প্রয়োজনই রইল না। এবার overflow: hidden মুছুন — লেখা বাক্স থেকে বেরিয়ে গেল, “…”-ও নেই, কারণ ellipsis শুধু কাটা জায়গায় বসে। শেষে -webkit-line-clamp-কে 3 করুন। একটি সাবধানতা: line-clamp-এর বাক্সে ওপর-নিচে padding দিলে পরের লাইনের মাথা padding-এর জায়গায় উঁকি দিতে পারে — তাই এখানে padding শুধু দুই পাশে।

line-clamp এমন একটি বিরল জায়গা, যেখানে আজও -webkit- prefix দেওয়া রূপটিই লিখতে হয় — Firefox-সহ সব প্রধান ব্রাউজার ঠিক এই prefix-ওয়ালা তিন লাইন বোঝে, তাই এটি কার্যত Baseline Widely available. prefix ছাড়া line-clamp property-র নতুন নিয়ম লেখা হচ্ছে, কিন্তু এখনো Baseline নয়। আর মনে রাখবেন, কাটা লেখা screen reader পুরোটাই পড়ে, কিন্তু চোখে দেখা ব্যবহারকারী বাকিটা পড়তে পারেন না — জরুরি তথ্য (দাম, শর্ত) কখনো কাটবেন না, আর পূর্ণ বিবরণের পাতায় যাওয়ার পথ রাখুন।

৮ · viewport আর writing-mode — পাতার জানালা আর লেখার দিক

দুই রকম viewport

সবচেয়ে বাইরের বাক্স ব্রাউজারের জানালা — viewport (পুরো গল্প পর্ব ৩০-এ)। ফোনে চিমটি কেটে (pinch zoom) বড় করলে লেআউট বদলায় না — শুধু চোখের সামনের জানালাটা ম্যাগনিফাইং গ্লাসের মতো ছোট একটা অংশে সরে আসে। লেআউট যে জানালার মাপে হিসাব হয়, তা layout viewport; এই মুহূর্তে চোখে যা দেখা যাচ্ছে, তা visual viewport. zoom করলে বা ফোনের কীবোর্ড উঠলে visual viewport ছোট হয়, layout viewport প্রায়ই একই থাকে। position: fixed বাক্স layout viewport ধরে বসে, তাই zoom অবস্থায় “নিচে আটকানো” বোতাম চোখের বাইরে যেতে পারে। JavaScript-এ window.visualViewport চোখে দেখা অংশের মাপ দেয়; address bar-এর জন্য তৈরি svh, lvh, dvh একক পর্ব ২০-এ দেখেছেন।

writing-mode — block অক্ষ আর inline অক্ষ

অংশ ১-এ বলেছিলাম, normal flow-এর নিয়ম আসলে দিক নয়, লেখার প্রবাহ দিয়ে বলা। এবার সেটা কাজে লাগাই। CSS দুটি অক্ষ ধরে ভাবে — inline অক্ষ: একটি লাইনের ভেতরে শব্দ যেদিকে চলে; আর block অক্ষ: নতুন লাইন বা নতুন block যেদিকে জমা হয়। বাংলায় inline অক্ষ বাঁ থেকে ডানে, block অক্ষ ওপর থেকে নিচে। writing-mode এই অক্ষগুলো ঘুরিয়ে দেয়:

  • horizontal-tb — ডিফল্ট; লাইন অনুভূমিক, block জমে ওপর থেকে নিচে (tb = top to bottom).
  • vertical-rl — লাইন খাড়া, ওপর থেকে নিচে; লাইনগুলো জমে ডান থেকে বাঁয়ে। প্রচলিত জাপানি ও চীনা বইয়ের ধরন।
  • vertical-lr — লাইন খাড়া, কিন্তু জমে বাঁ থেকে ডানে। ঐতিহ্যবাহী মঙ্গোলীয় লিপি এভাবে লেখা হয়।

বাংলা কখনো খাড়া লেখা হয় না, তবু নকশায় কাজে লাগে — দোকানের খাড়া সাইনবোর্ডের মতো ব্যানার, টেবিলের সরু কলামের শিরোনাম, বইয়ের পিঠের নাম। নিচে একই সাইনবোর্ড দুইবার, দ্বিতীয়টি খাড়া। সাইনবোর্ডের CSS-এ ইচ্ছা করেই width/height নয়, inline-size আর padding-inline-এর মতো logical property ব্যবহার হয়েছে:

.sign {
  display: inline-block;
  vertical-align: top;
  inline-size: 170px;            /* লাইনের দিকের মাপ */
  padding-block: 8px;            /* block দিকের দুই পাশে */
  padding-inline: 16px;          /* inline দিকের দুই পাশে */
  border: 3px solid #166534;
  border-inline-start-width: 14px; /* লেখা শুরুর দিকে মোটা দাগ */
  margin: 8px;
  background: #dcfce7;
  font: 700 22px sans-serif;
}
.v { writing-mode: vertical-rl; }

প্রথম সাইনবোর্ড অনুভূমিক — মোটা সবুজ দাগ বাঁ দিকে, কারণ বাংলায় লেখা শুরু হয় বাঁ থেকে। দ্বিতীয়টি খাড়া, লেখা ৯০ ডিগ্রি ঘুরে ওপর থেকে নিচে চলেছে। খেয়াল করুন, একই CSS থেকে সে 170px উঁচু হয়েছে, আর মোটা দাগ উঠে গেছে ওপরে — কারণ খাড়া লেখায় “লাইনের দিক” মানে ওপর-নিচ, আর লেখা শুরু হয় ওপর থেকে। চেষ্টা করুন: .v-তে text-orientation: upright; যোগ করুন — অক্ষরগুলো এবার সোজা দাঁড়িয়ে একটার নিচে একটা বসবে (বাংলার যুক্তাক্ষর এভাবে একটু অদ্ভুত দেখায়, তাই সাবধানে ব্যবহার করুন)। তারপর inline-size-কে width করে দেখুন — খাড়া সাইনবোর্ড এবার 170px চওড়া হয়ে যাবে, কারণ width সবসময় পর্দার অনুভূমিক মাপ।

এই অক্ষের ভাবনা জরুরি, কারণ Flexbox, Grid আর logical property — সবাই “বাঁ-ডান” নয়, inline-block অক্ষে কথা বলে। flex-direction: row মানে “inline অক্ষ বরাবর”, তাই আরবি পাতায় নিজে থেকেই ডান থেকে বাঁয়ে চলে। Logical property-র পুরো তালিকা পর্ব ৩৫-এ।

৯ · DevTools-এ লেআউট পড়া — badge, Layout প্যানেল আর Computed

লেআউটের বাগ খুঁজতে অনুমানের চেয়ে DevTools অনেক দ্রুত। Chrome, Edge আর Firefox — তিনটিতেই লেআউট দেখার বিশেষ সুবিধা আছে। নিচের চার ধাপ যেকোনো পাতায় কাজ করে:

  1. Inspectডান-ক্লিকelement বেছে নেওয়া
  2. Badgeflex · grid · scrollElements-এ লেবেল
  3. Layout প্যানেলoverlayরেখা আঁকা ছক
  4. Computeddisplay: …শেষ পর্যন্ত কী মান
  1. Inspect. সন্দেহজনক অংশে ডান-ক্লিক করে “Inspect” চাপুন। Elements প্যানেলে মাউস নাড়ালে পাতার ওপর বাক্সটি রঙে দেখা দেয় — content নীল, padding সবুজ, margin কমলা। পুরো debugging-এর কৌশল পর্ব ৪৭-এ।
  2. Badge পড়ুন। Chrome আর Edge-এর Elements প্যানেলে কিছু element-এর পাশে ছোট লেবেল বসে — flex, grid, subgrid, container, আর সাম্প্রতিক সংস্করণে স্ক্রল হওয়া বাক্সে scroll. Firefox-এ এগুলোর সাথে আছে একটি দারুণ কাজের badge — overflow: যে element তার scroll container থেকে বেরিয়ে গেছে, তার পাশে বসে। “পাতা পাশে স্ক্রল হচ্ছে কেন?” — এই badge প্রায়ই দোষীকে সরাসরি দেখায়।
  3. Layout প্যানেল। Elements-এর পাশের “Layout” ট্যাবে (Firefox-এ Inspector-এর ভেতরে) পাতার সব Flexbox আর Grid container-এর তালিকা থাকে; চেকবক্স বা badge-এ ক্লিক করলে পাতার ওপর সারি-কলাম আর ফাঁকের রেখা আঁকা হয়। পর্ব ২৫–২৯-এ এটি নিত্যসঙ্গী।
  4. Computed দেখুন। Computed ট্যাব বলে শেষ পর্যন্ত কোন মান জিতেছে (পর্ব ১৮)। “hidden দিলাম, তবু দেখা যাচ্ছে কেন?” — Computed-এ display খুঁজে পাশের তীর চাপলে দেখাবে কোন নিয়ম display: flex বসিয়ে hidden-কে হারিয়েছে। overflow, float, writing-mode-ও এখানে এক নজরে মেলে।

পরীক্ষা ও ইন্টারভিউতে — বিশ্ববিদ্যালয়, চাকরি বা ফ্রন্ট-এন্ড ইন্টারভিউর পরীক্ষায় এ ধরনের প্রশ্ন প্রায়ই আসে:

  • block আর inline element-এর পার্থক্য? — block নতুন সারিতে পুরো চওড়া নেয়, width-height ও ওপর-নিচের margin মানে; inline লাইনের ভেতরে থাকে, ভাঙতে পারে, width-height মানে না।
  • inline আর inline-block-এর পার্থক্য? — দুটোই লাইনে বসে, কিন্তু inline-block width, height আর ওপর-নিচের margin-padding পুরো মানে, আর দুই লাইনে ভাঙে না।
  • display: none বনাম visibility: hidden? — প্রথমটি বাক্সই মুছে দেয়, জায়গা নেয় না; দ্বিতীয়টি জায়গা রেখে অদৃশ্য করে। দুটোই screen reader আর Tab থেকে লুকায়; opacity: 0 লুকায় না।
  • BFC কী, আর কীভাবে বানাবেন? — নিজের ভেতরের block-দের আলাদা লেআউট এলাকা, যা float ধরে রাখে আর parent-child margin মিশতে দেয় না; সবচেয়ে পরিষ্কার উপায় display: flow-root.
  • এক লাইনের ellipsis-এর CSS? — white-space: nowrap; overflow: hidden; text-overflow: ellipsis; আর বাক্সের চওড়া সীমিত থাকতে হবে।

১০ · AI-এর যুগে — লেআউটের কাজ AI-কে দিলে কী দেখবেন

“দুই কলামের পাতা বানিয়ে দাও” বা “লম্বা নামে … দেখাও” — AI কয়েক সেকেন্ডে কোড দেয়, প্রথম দেখায় ঠিকও লাগে। কিন্তু AI শিখেছে দুই দশকের কোড থেকে, যার বড় অংশ float-clearfix যুগের। আর “চোখে ঠিক দেখাচ্ছে” আর “সবার জন্য ঠিক কাজ করছে”-র মধ্যে AI প্রায়ই প্রথমটাতেই থামে।

AI সাধারণত যেসব ভুল করে

AI-এর ভুলআপনি যা দেখবেনঠিক উপায়
কলাম বানাতে float + clearfixলম্বা লেখায় কলাম ভাঙে, ফোনে এলোমেলোGrid বা Flexbox (পর্ব ২৫–২৯)
পাশের স্ক্রল লুকাতে body { overflow-x: hidden }কিছু অংশ কাটা পড়ে, অনেক সময় sticky হেডার কাজ করে নাDevTools-এ দোষী বাক্সটি খুঁজে তার মাপ ঠিক করা
মেনু লুকাতে শুধু opacity: 0অদৃশ্য লিংকে Tab চলে যায়, screen reader পড়েdisplay: none, hidden বা visibility: hidden
hidden attribute, কিন্তু একই element-এ display: flexলুকানোর কথা, তবু দেখা যায়[hidden] { display: none !important; }
বোতাম, তালিকা বা টেবিলে display: contentsকিছু ব্রাউজারে screen reader-এ role হারায়শুধু অর্থহীন wrapper div-এ, পরীক্ষা করে
নির্দিষ্ট height + overflow: hiddenলম্বা বাংলা লেখা চুপচাপ কাটা পড়েheight না দেওয়া, বা overflow: auto
ellipsis-এ white-space: nowrap বা overflow ভুলে যাওয়া“…” আসে নাতিনটি লাইন একসাথে

AI-কে কাজ দেওয়ার সময় শর্তগুলো আগেই লিখে দিন — বিশেষ করে লুকানো আর কাটার নিয়ম। শেষের অংশটি খেয়াল করুন: AI-কে নিজের পছন্দের কারণ লিখতে বললে পুরোনো অভ্যাস প্রায়ই নিজেই ধরা পড়ে।

তুমি একজন অভিজ্ঞ ফ্রন্ট-এন্ড ডেভেলপার। আমার অনলাইন দোকানের পণ্য-তালিকার জন্য একটি কার্ডের HTML আর CSS লেখো: বাঁয়ে ছবি, ডানে নাম, দাম আর দুই লাইনের বিবরণ, নিচে "আরও দেখুন" বোতাম যা বাকি বিবরণ খোলে। শর্ত: ১. float বা clearfix ব্যবহার করবে না; ছবি আর লেখা পাশাপাশি রাখতে Flexbox বা Grid নেবে। ২. নাম এক লাইনে "…" দিয়ে কাটবে (white-space, overflow, text-overflow); বিবরণ line-clamp দিয়ে দুই লাইনে। ৩. দাম কখনো কাটা পড়বে না। ৪. লুকানো অংশের জন্য hidden attribute বা display: none নেবে, opacity: 0 নয়; বোতামে aria-expanded রাখবে। ৫. body বা html-এ overflow-x: hidden দেবে না; ৩২০px চওড়ায়ও পাশে স্ক্রল হবে না। ৬. কোনো -webkit- prefix শুধু তখনই দেবে, যখন সেটা ছাড়া কাজ হয় না — কেন দরকার, এক লাইনে লিখবে। শেষে প্রতিটি display আর overflow মান কেন বেছে নিলে, এক লাইনে করে ব্যাখ্যা দাও।

AI-এর দেওয়া লেআউট হাতে পেলে — যাচাইয়ের চেকলিস্ট

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলোই আপনাকে CSS লেখক থেকে লেআউট-চিন্তক বানাবে।

প্র ০১float তৈরি হয়েছিল ছবির পাশে লেখা ঘোরানোর জন্য — তাহলে প্রায় পনেরো বছর ধরে পুরো পাতার লেআউট float দিয়ে হলো কেন, আর শেষ পর্যন্ত বদলাল কীভাবে?

কারণটা সহজ: অন্য কোনো উপায় ছিল না। ১৯৯০-এর দশকের শেষে পাতায় কলাম বানানোর প্রচলিত পথ ছিল <table> — বাইরে একটি বড় টেবিল, ভেতরে মেনু আর লেখার ঘর, ফাঁক রাখতে স্বচ্ছ “spacer GIF” ছবি। এতে HTML-এর অর্থ নষ্ট হতো, কোড বিশাল হতো, আর নকশা বদলাতে প্রতিটি পাতার HTML বদলাতে হতো। অথচ CSS1 আর CSS2-তে কলাম বানানোর কোনো property ছিল না।

ডেভেলপাররা হাতে যা ছিল, তাই দিয়ে কাজ চালালেন: দুটি বাক্সকেই float দিলে তারা পাশাপাশি বসে! ২০০৩ সালের দিকে CSS Zen Garden দেখাল, শুধু CSS বদলে একই HTML-এর সম্পূর্ণ ভিন্ন নকশা সম্ভব, আর এরপর table থেকে CSS লেআউটে বড় স্থানান্তর ঘটে — মূল হাতিয়ার float. কিন্তু এটা ছিল একটি টুলকে ভুল কাজে লাগানো। parent উচ্চতা হারাত, তাই clearfix লাগত; সমান উচ্চতার কলাম বানাতে ব্যাকগ্রাউন্ড ছবির কৌশল (“faux columns”) লাগত; কলামের ক্রম HTML-এর ক্রমে বাঁধা থাকত; আর শতাংশের সামান্য গোলমালে শেষ কলাম নিচে পড়ে যেত।

পরিবর্তন এলো ধাপে ধাপে। ২০১০-এর দশকের মাঝামাঝি Flexbox সব ব্রাউজারে পাকা জায়গা পেল, আর Bootstrap 4 তার grid float থেকে Flexbox-এ সরিয়ে নিল। ২০১৭ সালে প্রধান ব্রাউজারগুলো প্রায় একই সময়ে CSS Grid চালু করল — প্রথমবার সত্যিকারের দুই-দিকের লেআউট পদ্ধতি। আর display: flow-root clearfix-কেও অবসরে পাঠাল।

মূল উপলব্ধি: ওয়েবে প্রয়োজন আগে আসে, সঠিক টুল পরে; মাঝের সময়টা ভরে থাকে চতুর কিন্তু ভঙ্গুর কৌশলে। AI বা পুরোনো টিউটোরিয়ালে float-লেআউট দেখলে বুঝবেন সেটা সেই মাঝের যুগের স্মৃতি — আর তার জায়গায় তৈরি-উদ্দেশ্যের টুল বেছে নেবেন।

প্র ০২কোনো কিছু লুকানোর সময় “কার কাছ থেকে লুকাচ্ছি?” — এই প্রশ্নটা কেন আসল প্রশ্ন? শুধু চোখ থেকে, শুধু screen reader থেকে, আর দুটো থেকেই লুকানোর ঠিক উপায় কী?

একটি পাতা কয়েক রকম মানুষ কয়েকভাবে “পড়েন”। কেউ চোখে দেখে মাউস চালান; কেউ দেখেন, কিন্তু হাতের সমস্যায় শুধু কীবোর্ড চালান; কেউ দৃষ্টিপ্রতিবন্ধী — NVDA বা ফোনের TalkBack-এর মতো screen reader পাতা পড়ে শোনায়, ব্রাউজারের বানানো accessibility tree থেকে। প্রতিটি লুকানোর উপায় এই তিন পথের কোনটা বন্ধ করে, তা আলাদা — তাই শুধু “লুকাও” বলা অসম্পূর্ণ নির্দেশ।

দুটো থেকেই লুকানো — বন্ধ ড্রপডাউন, অন্য ট্যাবের লেখা, না খোলা মডাল: এখন কারও জন্যই প্রাসঙ্গিক নয়। এখানে display: none, hidden, বা জায়গা রাখতে visibility: hidden. সবচেয়ে বড় ভুল শুধু opacity: 0 দিয়ে মেনু লুকানো: চোখে কিছু নেই, অথচ Tab চাপলে focus অদৃশ্য লিংকে ঘোরে, আর WCAG 2.2-এর 2.4.7 (Focus Visible)-এর মতো নিয়ম ভাঙে।

শুধু চোখ থেকে লুকানো — বোতামে শুধু 🔍 আইকন থাকলে screen reader-এর জন্য “খুঁজুন” লেখাটা দরকার। তখন visually-hidden ক্লাসে লেখা রাখা হয় (বা aria-label, পর্ব ১২)। skip link-ও এভাবে লুকানো থাকে, focus পেলে দেখা দেয়।

শুধু screen reader থেকে লুকানো — সাজসজ্জার আইকন বা বারবার আসা একই লেখা। তখন aria-hidden="true", কিন্তু এর ভেতরে কখনো focus পাওয়ার মতো কিছু নয় — নইলে screen reader ব্যবহারকারী Tab চেপে এমন বোতামে পৌঁছান, যার কিছুই শোনা যায় না।

মূল উপলব্ধি: লুকানো একটি নয়, তিনটি সিদ্ধান্ত — চোখ, কীবোর্ড আর screen reader. কোড লেখার আগে জিজ্ঞেস করুন “কার কাছ থেকে?”, তারপর মেলে এমন উপায় বেছে Tab চেপে নিজে যাচাই করুন।

প্র ০৩display: contents শুধু চেহারার লেআউট বদলানোর কথা — তাহলে এটা screen reader-এর অভিজ্ঞতা নষ্ট করল কীভাবে? এ থেকে CSS আর HTML-এর সম্পর্ক নিয়ে কী শেখার আছে?

নীতিগতভাবে CSS শুধু চেহারা বদলায়, অর্থ বদলায় HTML. একটি <ul>-কে যতই সাজান, সে তালিকাই থাকার কথা। display: contents-এর প্রতিশ্রুতিও ছিল এমন — “এই element-এর বাক্স আঁকো না, কিন্তু element-টি থাকুক।” প্রয়োজনটা আসে মূলত Grid থেকে: semantic কারণে পণ্যের তালিকা <ul>-এ রাখতে চান, কিন্তু চান প্রতিটি <li> বাইরের grid-এর ঘরে সরাসরি বসুক।

সমস্যাটা ব্রাউজারের ভেতরের নির্মাণে। অনেক বছর ব্রাউজারগুলো accessibility tree বানাতে লেআউটের বাক্স-গাছের তথ্যও ব্যবহার করত। display: contents-এর element-এর বাক্স নেই, তাই অনেক ব্রাউজারে সে accessibility tree থেকেও উধাও হতো — screen reader আর “তালিকা, পাঁচটি আইটেম” বলত না, বোতাম role হারাত, টেবিলের সারি বিচ্ছিন্ন হতো। একটি CSS লাইন HTML-এর অর্থ মুছে দিচ্ছিল। অ্যাক্সেসিবিলিটি বিশেষজ্ঞরা বছরের পর বছর এ নিয়ে লিখেছেন, আর ব্রাউজারগুলো ধাপে ধাপে ঠিক করেছে; সাধারণ ক্ষেত্রগুলো এখন অনেক ভালো, কিন্তু interactive element আর টেবিলে ভিন্ন আচরণ এখনো পাওয়া যেতে পারে।

শিক্ষা দুটি। spec যা বলে আর ব্রাউজার যা করে, তার মাঝে ফাঁক থাকতে পারে — তাই DevTools-এর Accessibility প্যানেল আর আসল screen reader দিয়ে দেখুন। আর CSS অর্থের ওপরও প্রভাব ফেলতে পারে — যেমন Safari ঐতিহাসিকভাবে list-style: none দেওয়া কিছু তালিকাকে screen reader-এ তালিকা হিসেবে ঘোষণা করে না। অর্থপূর্ণ element-এ display: contents-এর বদলে দরকারে subgrid (পর্ব ২৮) ভাবুন।

মূল উপলব্ধি: “CSS চেহারা, HTML অর্থ” ভালো নীতি, কিন্তু ব্রাউজারের বাস্তব নির্মাণে দুটো জড়িয়ে থাকে। অচেনা CSS কৌশল শুধু চোখে নয়, কীবোর্ড আর screen reader দিয়েও পরীক্ষা করুন।

প্র ০৪ফোনে পাতা পাশে নড়ছে — সবচেয়ে সহজ সমাধান মনে হয় body { overflow-x: hidden }. এটাকে খারাপ অভ্যাস বলা হয় কেন, আর পেশাদাররা আসলে কী করেন?

কারণ এটা রোগ নয়, উপসর্গ লুকায়। পাতা পাশে নড়ে কারণ কোনো একটি বাক্স viewport-এর চেয়ে চওড়া — হয়তো width: 400px-এর ছবি, padding-সহ width: 100% (পর্ব ১৯), না ভাঙা লম্বা URL, বা ভুলে থাকা negative margin. overflow-x: hidden সেই বাক্স ঠিক করে না, শুধু বেরিয়ে থাকা অংশ কেটে দেয় — লেখার শেষ অক্ষর বা বোতামের অর্ধেক চুপচাপ অদৃশ্য হয়, কেউ টেরও পায় না।

দ্বিতীয় সমস্যা লুকানো। overflow-x: hidden যে বাক্সে বসে, সেটি scroll container হয়ে যায়, আর অংশ ৭-এর নিয়মে অন্য দিকটাও auto হয়। (শুধু body-তে দিলে ব্রাউজার মানটি সাধারণত পুরো জানালায় পাঠিয়ে দেয়; কিন্তু html-এও overflow থাকলে, বা কোনো wrapper div-এ দিলে, সেই বাক্স নিজেই scroll container হয়।) ভেতরের position: sticky হেডার তখন পুরো পাতার স্ক্রলের সাথে আটকে থাকে না — পর্ব ২৪-এ দেখবেন, sticky সবচেয়ে কাছের scroll container ধরে কাজ করে। “হেডার sticky হচ্ছে না কেন” প্রশ্নের বড় অংশের উত্তর এই লুকানো overflow.

তৃতীয়ত অ্যাক্সেসিবিলিটি। WCAG-এর 1.4.10 Reflow চায়, ৩২০ CSS পিক্সেল চওড়ায় সাধারণ লেখা পাশে স্ক্রল ছাড়াই পড়া যাবে এবং কোনো তথ্য হারাবে না. কেটে লুকালে দ্বিতীয় শর্তটি ভাঙে।

পেশাদাররা DevTools-এ ৩২০px চওড়ায় পাতা খোলেন, Firefox-এর overflow badge দিয়ে দোষী বাক্স খোঁজেন, তারপর কারণটা সারান — ছবিতে max-width: 100%, লম্বা শব্দে overflow-wrap: anywhere, box-sizing reset, width-এর বদলে max-width. সাজসজ্জার কোনো অংশ ইচ্ছা করেই কাটতে হলে body-তে নয়, শুধু তার parent-এ overflow: clip — যা sticky ভাঙে না।

মূল উপলব্ধি: লেআউটের বাগ চাপা দিলে সেটা অন্য জায়গায় অন্য রূপে ফিরে আসে। উপসর্গ নয়, কারণ খুঁজুন।

প্র ০৫নতুন CSS spec-গুলো কেন “width/height” বা “বাঁ/ডান”-এর বদলে “inline size/block size” আর “start/end” ভাষায় লেখা হয়? বাংলাদেশের একজন ডেভেলপারের জন্য এর বাস্তব মূল্য কী?

CSS-এর শুরুর দিনগুলো ছিল ইংরেজি দলিলের জন্য — লেখা বাঁ থেকে ডানে, লাইন ওপর থেকে নিচে, তাই width, margin-left, float: left স্বাভাবিক নাম মনে হয়েছিল। কিন্তু আরবি, ফারসি, উর্দু আর হিব্রু লেখা হয় ডান থেকে বাঁয়ে; জাপানি, চীনা আর কোরিয়ান প্রচলিতভাবে খাড়াও লেখা হয়; আর ঐতিহ্যবাহী মঙ্গোলীয় লিপি খাড়া হয়ে বাঁ থেকে ডানে জমে। margin-left দিয়ে “লেখার আগে ফাঁক” রাখলে আরবি পাতায় ফাঁকটা ভুল দিকে পড়ে।

তাই CSS Writing Modes spec একটি সাধারণ ভাষা তৈরি করল: inline অক্ষ আর block অক্ষ, প্রতিটির start আর end. Flexbox আর Grid শুরু থেকেই এই ভাষায় — justify-content: start আরবিতে মানে ডান। তারপর এলো logical property: margin-inline-start, padding-block, inline-size — একই CSS যেকোনো লেখার দিকে ঠিক কাজ করে। Box model-এর পুরোনো নিয়মও আসলে logical ছিল: margin collapsing হয় block দিকে, padding-এর শতাংশ আসে inline size থেকে।

বাংলাদেশের ডেভেলপারের জন্য এটা তাত্ত্বিক নয়। প্রবাসী বাংলাদেশিদের বড় অংশ মধ্যপ্রাচ্যে কাজ করেন, আর রেমিট্যান্স, নিয়োগ বা ভিসা-সেবার সাইট প্রায়ই বাংলা, ইংরেজি আর আরবিতে চলে; ফ্রিল্যান্সিং মার্কেটপ্লেসে RTL সাইটের কাজও নিয়মিত আসে। শুরু থেকে logical property-তে লিখলে dir="rtl" দিলেই পাতা উল্টে যায়; physical property-তে লিখলে প্রায় পুরো CSS আবার লিখতে হয়।

মূল উপলব্ধি: “বাঁ-ডান” পর্দার ভাষা, “start-end” লেখার ভাষা। লেখার ভাষায় ভাবলে আপনার CSS পৃথিবীর যেকোনো লিপির জন্য তৈরি থাকে — পুরো কাঠামো পর্ব ৩৫-এ।

অনুশীলন

অনুমান, DevTools-এ দেখা আর এডিটরে পরীক্ষা — তিনটিই কাজে লাগান।

  1. Badge শিকার: এই পাতাটি বা যেকোনো বড় ওয়েবসাইট (যেমন একটি অনলাইন পত্রিকা) Chrome/Edge-এ খুলে Elements প্যানেলে flex, grid আর scroll badge খুঁজুন। একটি grid badge-এ ক্লিক করুন — পাতায় কী দেখলেন? তারপর Firefox-এ খুলে কোনো overflow badge আছে কি না দেখুন।

    বেশিরভাগ আধুনিক সাইটে হেডার আর নেভিগেশনে flex badge, আর খবরের তালিকা বা কার্ডের সারিতে grid badge পাবেন — অর্থাৎ পাতার বড় কাঠামো আজ Flexbox আর Grid-এ, normal flow থাকে লেখার ভেতরে। grid badge-এ ক্লিক করলে পাতার ওপর বেগুনি রেখায় সারি-কলাম আর ফাঁক আঁকা হয়, সাথে লাইন নম্বর। scroll badge সাধারণত পাশের মেনু, কোড ব্লক বা চওড়া টেবিলের wrapper-এ থাকে। Firefox-এ overflow badge পেলে সেটাই সম্ভাব্য বাগ — element-টি তার scroll container থেকে বেরিয়ে গেছে; সাইটটি ৩২০px চওড়ায় খুলে দেখুন পাশে স্ক্রল হয় কি না।

  2. ফল অনুমান করুন: একটি প্যারাগ্রাফের ভেতরে তিনটি span, প্রতিটিতে width: 100px; height: 50px; margin: 20px; background: gold;. প্রথমটির display ডিফল্ট, দ্বিতীয়টির inline-block, তৃতীয়টির block. পাতায় কী দেখবেন? আগে লিখে নিন, তারপর অংশ ২-এর এডিটরে মিলিয়ে দেখুন।

    প্রথম span (inline): শুধু নিজের লেখার মাপে সোনালি রং; width-height উপেক্ষিত, বাঁ-ডানে 20px ফাঁক আছে কিন্তু ওপর-নিচে নেই, লাইনের উচ্চতা বদলায় না।

    দ্বিতীয় span (inline-block): একই লাইনে 100 × 50-এর পুরো সোনালি বাক্স, চারদিকে 20px margin; লাইনটি উঁচু হয়ে তাকে জায়গা দেয়। বাক্সটি ডিফল্টে লাইনের baseline-এ বসে, তাই লেখার সাথে নিচের দিকে মেলে।

    তৃতীয় span (block): প্যারাগ্রাফের লেখা ভেঙে নিজের আলাদা সারিতে 100 × 50 বাক্স, বাকি লেখা তার নিচে নতুন লাইনে। এখানে ব্রাউজার প্যারাগ্রাফের ভেতরের লেখাকে anonymous block-এ মুড়িয়ে নেয় — অংশ ১-এর স্টেপারের শেষ ধাপ।

  3. লুকায় না কেন? একজন ডেভেলপার লিখলেন .modal { display: flex; }, আর HTML-এ <div class="modal" hidden>. পাতা খুলতেই মডাল দেখা যাচ্ছে। কেন হলো, আর দুটি সমাধান কী?

    hidden attribute নিজে কিছু লুকায় না — সে কাজটা করে ব্রাউজারের ডিফল্ট CSS-এর [hidden] { display: none; } নিয়ম। আপনার stylesheet-এর নিয়ম cascade-এ ব্রাউজারের ডিফল্টের চেয়ে এগিয়ে থাকে (পর্ব ১৮), তাই .modal-এর display: flex জিতে গেছে।

    /* সমাধান ১: সব প্রজেক্টের reset-এ একবার */
    [hidden] { display: none !important; }
    
    /* সমাধান ২: শুধু খোলা অবস্থায় flex */
    .modal:not([hidden]) { display: flex; }

    প্রথমটি সবচেয়ে প্রচলিত — অনেক CSS reset-এ এটি থাকে। আর মডালের জন্য সবচেয়ে ভালো হলো HTML-এর নিজস্ব <dialog> (পর্ব ১১), যা খোলা-বন্ধ, focus আর Esc চাপা নিজেই সামলায়।

  4. AI অডিট: যেকোনো AI-কে বলুন “একটি পণ্য-কার্ডের HTML-CSS লেখো, যেখানে লম্বা নাম ‘…’ দিয়ে কাটবে আর একটি বোতাম চাপলে বিস্তারিত দেখাবে।” তারপর অংশ ১০-এর চেকলিস্ট আর ভুলের টেবিল ধরে কোডটি যাচাই করুন। কী কী পেলেন?

    প্রায়ই যা পাওয়া যায়:

    • বিস্তারিত অংশ opacity: 0 বা height: 0 দিয়ে লুকানো — Tab চাপলে ভেতরের লিংকে অদৃশ্য focus যায়।
    • বোতামে aria-expanded নেই, বা বোতামের বদলে ক্লিকযোগ্য <div> — কীবোর্ডে চলেই না।
    • ellipsis-এর তিন লাইনের একটি বাদ, অথবা নামের সাথে দামও একই বাক্সে কেটে গেছে।
    • ছবি আর লেখা পাশাপাশি রাখতে float, সাথে clearfix — Flexbox-এ দুই লাইনের কাজ।

    প্রতিটি সমস্যা DevTools (Computed-এ display, Tab চেপে focus) দিয়ে প্রমাণ করে AI-কে নির্দিষ্ট করে বলুন কী বদলাতে হবে — “আরও ভালো করো” নয়।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমHTML থেকে পর্দার ছবি পর্যন্ত ব্রাউজারের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. 📄 HTML পড়ে DOM গাছ তৈরি
  2. 🎨 CSS মিলিয়ে প্রতিটি element-এর display সহ সব মান হিসাব
  3. 📦 box tree তৈরি — display: none-এর element বাদ, anonymous box যোগ
  4. 📐 layout — normal flow, float, overflow মেনে প্রতিটি বাক্সের জায়গা ও মাপ
  5. 🖌️ paint — পর্দায় রং, লেখা আর ছবি আঁকা

display বদলানো হয়নি এমন একটি <span>-এ width: 200px; height: 60px; দেওয়া হলো। কী ঘটবে?

  • span ঠিক 200 × 60 মাপের হবে
  • span নতুন সারিতে চলে যাবে, কিন্তু উচ্চতা বদলাবে না
  • মাপের কোনো পরিবর্তন হবে না
  • ব্রাউজার Console-এ error দেখাবে

কোন উপায়ে লুকানো একটি বোতাম চোখে দেখা যায় না, কিন্তু screen reader তা পড়ে আর Tab চাপলে তাতে focus-ও যায়?

  • display: none
  • visibility: hidden
  • hidden attribute
  • opacity: 0

দুই-শব্দের display নিয়মে display: inline-block-এর সমান কোনটি?

  • inline flow
  • inline flow-root
  • block flow-root
  • inline flex

একটি কার্ডের ভেতরের ছবি float: left, আর কার্ড ছবির চেয়ে খাটো হয়ে যাচ্ছে — ছবি নিচে ঝুলে থাকছে। আধুনিক CSS-এ সবচেয়ে পরিষ্কার সমাধান কোনটি?

  • কার্ডে display: flow-root
  • কার্ডে overflow: hidden
  • কার্ডে ছবির সমান নির্দিষ্ট height
  • কার্ডের শেষে <div style="clear:both"> যোগ করা

একটি বাক্সে width: 200px; overflow: hidden; text-overflow: ellipsis; দেওয়া হলো, কিন্তু লম্বা লেখার শেষে “…” আসছে না, লেখা কয়েক লাইনে ভেঙে যাচ্ছে। কী বাদ পড়েছে?

  • display: inline
  • overflow: scroll
  • white-space: nowrap
  • -webkit-line-clamp: 1

একটি বাক্সে overflow-x: hidden; দেওয়া, আর overflow-y লেখা হয়নি (ডিফল্ট visible). ব্রাউজারের হিসাবে overflow-y-এর মান কী হবে?

  • visible
  • auto
  • hidden
  • clip

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. Normal flow: block বাক্স block অক্ষে (বাংলায় ওপর থেকে নিচে) জমে, inline বাক্স line box-এ inline অক্ষে চলে আর দরকারে ভাঙে।
  2. display-এর দুই মুখ — বাইরে block/inline, ভেতরে flow/flow-root/flex/grid; inline-block = inline flow-root, flex = block flex.
  3. লুকানোর আগে জিজ্ঞেস করুন “কার কাছ থেকে?” — display: none/hidden সবার কাছ থেকে, visibility: hidden জায়গা রেখে, opacity: 0 শুধু চোখ থেকে। [hidden]-কে CSS-এর display যেন না হারায়।
  4. display: flow-root নতুন BFC — float ধরে রাখে, margin পালাতে দেয় না। float শুধু লেখার ভেতরে ছবির জন্য; লেআউট Flexbox আর Grid-এ।
  5. overflow: auto প্রায় সবসময় ঠিক; clip scroll container বানায় না। এক লাইনে “…” = nowrap + hidden + ellipsis; কয়েক লাইনে -webkit-line-clamp. পাশের স্ক্রল লুকাবেন না — দোষী বাক্স খুঁজুন।

পরের পর্বে: আজ দেখলেন বাক্সগুলো স্বাভাবিক প্রবাহে কোথায় বসে। এবার শিখব প্রবাহ থেকে বাক্স তুলে নিজের পছন্দের জায়গায় বসানো — position-এর relative, absolute, fixed আর sticky, আর কোন বাক্স কার ওপরে থাকবে, সেই z-index.

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান