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

CSS Grid — সারি আর কলামে দুই দিকের লেআউট

CSS Grid Layout — Tracks, the fr Unit, Grid Lines, Auto-placement & Alignment

Taught in Bangla, this lesson introduces CSS Grid: grid containers and items, track sizing with px, percentages, auto, the fr unit and repeat(), grid lines and line numbers, placing items with grid-column, grid-row and span, explicit versus implicit grids, alignment properties, overlapping items, choosing between Flexbox and Grid, and inspecting grids in DevTools.

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

  • কেন দুই দিকের লেআউটের জন্য আলাদা পদ্ধতি দরকার, আর Grid আসার আগে ওয়েব কীভাবে চলত
  • grid container, item, track, line, cell — পরিভাষাগুলো, আর fr দিয়ে জায়গা ভাগের আসল হিসাব
  • লাইন নম্বর (ধনাত্মক ও ঋণাত্মক) আর span দিয়ে item-কে ঠিক জায়গায় বসানো
  • explicit আর implicit grid, grid-auto-rows, grid-auto-flow আর dense-এর অ্যাক্সেসিবিলিটি ঝুঁকি
  • Grid-এ সারিবদ্ধ করার ছয়টি property, একই ঘরে একাধিক item, DevTools-এর grid overlay, আর Flexbox না Grid — সিদ্ধান্তের গাইড

১ · কেন Grid — এক দিক যথেষ্ট নয় যখন

আগের দুই পর্বে আপনি Flexbox শিখেছেন — জিনিসগুলোকে একটি লাইন ধরে সাজানোর পদ্ধতি। navbar-এর লিংক, বোতামের ভেতরের আইকন আর লেখা, কার্ডের নিচের দাম আর “কিনুন” বোতাম — এগুলো সব এক দিকের সমস্যা। কিন্তু এবার একটি অনলাইন দোকানের হোমপেজ ভাবুন। ওপরে হেডার, বাঁ দিকে ক্যাটাগরির তালিকা, মাঝে পণ্যের কার্ড — চারটি করে পাশাপাশি, কয়েক সারি — আর নিচে ফুটার। এখানে আপনি একই সাথে দুটি জিনিস চান: কার্ডগুলো আড়াআড়ি কলামে মিলে থাকুক, আবার খাড়া সারিতেও মিলে থাকুক।

Flexbox-এ flex-wrap দিয়ে কার্ডগুলোকে কয়েক লাইনে ভাঙা যায় ঠিকই, কিন্তু প্রতিটি লাইন নিজের মতো করে জায়গা ভাগ করে। শেষ লাইনে দুটি কার্ড থাকলে সেগুলো টেনে বড় হয়ে যায়, বা ওপরের কলামের সাথে মেলে না। কারণ Flexbox-এর কাছে প্রতিটি লাইন আলাদা — ওপরের লাইনের কোন কার্ড কোথায়, নিচের লাইন তা জানে না। এই সমস্যার সমাধানের জন্যই তৈরি CSS Grid Layout.

পরীক্ষার খাতার মার্কশিট বা স্কুলের রুটিনের কথা ভাবুন। কাগজে আগে ছক কাটা হয় — খাড়া দাগ আর আড়াআড়ি দাগ। তারপর প্রতিটি তথ্য বসে কোনো একটি ঘরে; কোনো বিষয়ের ক্লাস দুই পিরিয়ড লম্বা হলে সেটি দুই ঘর জুড়ে লেখা হয়। Grid ঠিক এভাবে চিন্তা করে: আগে ছক, তারপর ছকের ঘরে জিনিস। আর Flexbox হলো দোকানের তাকে জিনিস সাজানোর মতো — এক তাকে যতটা ধরে, বাকিটা পরের তাকে; প্রতিটি তাক আলাদা।

Flexbox — এক দিক

একটি প্রধান দিক (সারি বা কলাম) ধরে জিনিস সাজায়। প্রতিটি লাইন নিজের মতো জায়গা ভাগ করে। জিনিসের নিজের মাপ থেকে লেআউট গড়ে ওঠে।

navbar, বোতামের সারি, কার্ডের ভেতর

Grid — দুই দিক

সারি আর কলামের একটি ছক আগে তৈরি হয়, তারপর জিনিস ঘরে বসে। এক সারির কলাম নিচের সারির কলামের সাথে মিলে থাকে।

পুরো পাতার কাঠামো, গ্যালারি, ড্যাশবোর্ড

প্রায় দুই দশক ওয়েবে সত্যিকারের লেআউট পদ্ধতি ছিল না। ১৯৯০-এর দশকে পাতা সাজানো হতো <table> দিয়ে (পর্ব ৭-এ দেখেছেন, কেন সেটা ভুল), তারপর এলো float — যা আসলে লেখার পাশে ছবি ভাসানোর জন্য তৈরি, পুরো পাতার কাঠামোর জন্য নয়। Grid-এর পথে প্রথম বড় পদক্ষেপ নেয় Microsoft: ২০১১ সালে তারা W3C-তে একটি Grid Layout প্রস্তাব জমা দেয়, আর ২০১২ সালে Internet Explorer 10-এ -ms-grid নামে তার একটি প্রাথমিক রূপ চালু করে। এরপর স্পেসিফিকেশন অনেকবার নতুন করে লেখা হয়। শেষে ২০১৭ সালের মার্চে মাত্র কয়েক সপ্তাহের ব্যবধানে Firefox, Chrome আর Safari নতুন Grid চালু করে, আর বছরের শেষে Microsoft Edge. এর পেছনে বড় ভূমিকা ছিল Rachel Andrew-এর (যিনি বছরের পর বছর উদাহরণ, লেখা আর বক্তৃতায় ডেভেলপারদের Grid শিখিয়েছেন) আর তখন Mozilla-য় কর্মরত Jen Simmons-এর, যাঁর উৎসাহে Firefox সবার আগে DevTools-এ grid দেখার টুল আনে।

আজ Grid সব আধুনিক ব্রাউজারে আছে — ভাষায় বললে Baseline Widely available, বহু বছর ধরে। তাই এই পর্বের মূল অংশ কোনো fallback ছাড়াই নিশ্চিন্তে ব্যবহার করতে পারেন।

২ · Grid container আর grid item — প্রথম grid

Grid-এ দুই রকম ভূমিকা। যে element-এ display: grid লেখেন, সে হয় grid container — ছক কাটা কাগজ। তার সরাসরি সন্তানরা হয় grid item — ঘরে বসানো জিনিস। নাতি-নাতনিরা (সন্তানের ভেতরের element) grid item নয়; তারা নিজের parent-এর ভেতরে সাধারণ নিয়মেই থাকে। Flexbox-এও ঠিক এমনই ছিল।

ছকের ভাষাটাও চিনে নিন, কারণ CSS-এর property-র নামগুলো এই শব্দ দিয়েই তৈরি:

শব্দমানেরুটিনের ছকে
trackএকটি পুরো সারি বা পুরো কলাম“রবিবার”-এর পুরো সারি, বা “১ম পিরিয়ড”-এর পুরো কলাম
grid linetrack-গুলোর মাঝের (আর দুই কিনারার) দাগকলম দিয়ে টানা খাড়া আর আড়াআড়ি দাগ
cellএকটি সারি আর একটি কলামের মিলনের ঘররবিবার, ১ম পিরিয়ড — একটি ঘর
grid areaচারটি লাইন দিয়ে ঘেরা যেকোনো আয়তাকার অংশ (এক বা একাধিক ঘর)দুই পিরিয়ড জুড়ে লেখা ব্যবহারিক ক্লাস
gaptrack-এর মাঝের ফাঁকা জায়গা (gutter)ঘরগুলোর মাঝে রাখা ফাঁক

এবার প্রথম grid. নিচের এডিটরে ছয়টি নম্বর-দেওয়া বাক্স আছে (বাক্সের রং আর দাগ আগে থেকেই দেওয়া, যাতে আপনি শুধু লেআউটে মন দিতে পারেন)। CSS-এ কলাম তিনটি, প্রতিটি 120px, আর সারি দুটি, প্রতিটি 60px:

.g {
  display: grid;                             /* ছক কাটা শুরু */
  grid-template-columns: 120px 120px 120px;  /* ৩টি কলাম */
  grid-template-rows: 60px 60px;             /* ২টি সারি */
  gap: 10px;                                 /* ঘরের মাঝে ফাঁক */
}

ছয়টি বাক্স তিন কলাম আর দুই সারির ছকে বসেছে — ১, ২, ৩ ওপরের সারিতে, ৪, ৫, ৬ নিচে। আপনি কোনো বাক্সকে বলেননি কোথায় বসতে হবে; ব্রাউজার HTML-এর ক্রম ধরে বাঁ থেকে ডানে, ওপর থেকে নিচে ঘর ভরিয়েছে। একে বলে auto-placement. খেয়াল করুন, ছকটা 120 × 3 + 10 × 2 = 380px চওড়া, কিন্তু ধূসর ড্যাশ দাগের container পুরো লাইন জুড়ে আছে — container block-ই থাকে, শুধু ভেতরটা ছক হয়। চেষ্টা করুন: grid-template-columns-এ চতুর্থ একটি 120px যোগ করুন — বাক্সগুলো ৪ + ২ হয়ে গেল। তারপর display: grid লাইনটি মুছে দিন — সব বাক্স আবার নিচে নিচে, পুরো চওড়া।

গাছের কাঠামো নিয়ে একটি কথা: grid item নিজে আবার display: grid বা display: flex হতে পারে। পণ্যের কার্ডগুলো বাইরের grid-এর item, আবার প্রতিটি কার্ডের ভেতরটা নিজস্ব flex. বাস্তবের পাতায় এই মিশ্রণই সবচেয়ে বেশি দেখা যায়।

grid item হওয়ার সাথে সাথে কয়েকটি পুরোনো নিয়ম বদলে যায়। inline element (যেমন <span> বা <a>) item হলে block-এর মতো আচরণ করে — একে বলে blockification. item-এ float দিলে কোনো কাজ হয় না। আর item-দের ওপর-নিচের margin মিশে যায় না (margin collapsing শুধু সাধারণ block লেআউটের ব্যাপার, পর্ব ১৯-এ দেখেছেন)।

৩ · কলাম আর সারির মাপ — px, %, auto, fr আর repeat()

grid-template-columns-এ প্রতিটি মান একটি কলামের মাপ, ফাঁকা জায়গা দিয়ে আলাদা করা। grid-template-rows একই কাজ করে সারির জন্য। মাপ লেখার কয়েকটি উপায়:

  • নির্দিষ্ট মাপ — 200px, 12rem: যা লিখবেন তাই।
  • শতাংশ — 25%: container-এর চওড়ার ভাগ। কিন্তু সাবধান — gap এর সাথে যোগ হয়, তাই 25% 25% 25% 25% আর gap: 10px একসাথে দিলে ছক container থেকে 30px বেরিয়ে যায়।
  • auto — ভেতরের জিনিসের মাপ অনুযায়ী; অন্য কোনো কলাম জায়গা না চাইলে বাড়তি জায়গাও নিয়ে নেয়।
  • fr — Grid-এর নিজস্ব একক, “fraction” বা ভগ্নাংশের সংক্ষেপ।

fr বোঝার সবচেয়ে ভালো উপায় একটি পরিবারের মাসের বাজেট। বেতন এলে আগে বাড়িভাড়া আর বিদ্যুৎ বিল — এগুলো নির্দিষ্ট, বাদ দিতেই হবে। তারপর যা থাকে, সেটা অনুপাতে ভাগ হয় — বাজারে দুই ভাগ, সঞ্চয়ে এক ভাগ। ব্রাউজারও ঠিক এভাবে হিসাব করে: আগে নির্দিষ্ট মাপের কলাম আর gap সরিয়ে রাখে, তারপর বাকি জায়গা (free space) fr-এর অনুপাতে ভাগ করে। নিচের ডায়াগ্রামে একটি 600px চওড়া container ধরে হিসাবটি ধাপে ধাপে দেখুন:

container · 600px
200px
বাকি 400px
200px
free space 360px
200px
1 ভাগ
1 ভাগ
1 ভাগ
200px
1fr = 120
2fr = 240px
  1. পুরো জায়গা। container-এর ভেতরের চওড়া 600px. এটাই মাসের পুরো বেতন। এখনো কিছু ভাগ হয়নি।
  2. নির্দিষ্ট মাপ আগে। প্রথম কলাম 200px — বাড়িভাড়ার মতো, এটা আগে কেটে রাখতে হবে। বাকি থাকল 400px. যদি কোনো কলাম auto হতো, তার জিনিসের মাপও এই ধাপেই আলাদা করা হতো।
  3. gap-ও নির্দিষ্ট খরচ। তিনটি কলামের মাঝে দুটি gap, প্রতিটি 20px — মোট 40px বাদ। এখন যা থাকল, সেটাই free space: 360px. ডোরাকাটা অংশগুলো gap.
  4. ভাগ গোনা। 1fr আর 2fr মিলে মোট ৩ ভাগ। তাই এক ভাগ = 360 ÷ 3 = 120px. শতাংশের সাথে এখানেই পার্থক্য: fr হিসাব হয় gap আর নির্দিষ্ট কলাম বাদ দেওয়ার পরে, তাই কখনো container থেকে বেরিয়ে যায় না।
  5. ফল। দ্বিতীয় কলাম 120px, তৃতীয় 240px — ঠিক দ্বিগুণ। container ছোট-বড় হলে প্রথম কলাম 200px-ই থাকবে, বাকি দুটি অনুপাত ঠিক রেখে বাড়বে-কমবে। এই কারণেই সাইডবার + মূল অংশের লেআউটে 250px 1fr এত জনপ্রিয়।

একই মাপ বারবার লিখতে না হলে repeat() আছে: repeat(4, 1fr) মানে 1fr 1fr 1fr 1fr. প্যাটার্নও পুনরাবৃত্তি করা যায় — repeat(2, 100px 1fr) মানে 100px 1fr 100px 1fr. নিচে নিজে মিশিয়ে দেখুন:

.g {
  display: grid;
  grid-template-columns: 150px 1fr 2fr;
  gap: 10px;
}

/* একটি করে বসিয়ে দেখুন:
   repeat(3, 1fr)
   auto 1fr auto
   25% 25% 50%         ← gap থাকায় বেরিয়ে যাবে!
   repeat(2, 80px 1fr)
*/

প্রথমে লোগো 150px, আর বাকি জায়গার এক ভাগ পেল খোঁজার ঘর, দুই ভাগ পেল লগইন। এবার auto 1fr auto বসান — লোগো আর লগইন শুধু নিজের লেখার মাপ নিল, খোঁজার ঘর বাকি সব জায়গা নিয়ে নিল। দোকানের হেডারের জন্য এটাই আদর্শ প্যাটার্ন। তারপর 25% 25% 50% বসিয়ে দেখুন — ডান দিকের বাক্স ধূসর ড্যাশ দাগ পেরিয়ে বেরিয়ে গেছে, কারণ ১০০% + দুটি gap = ১০০% + 20px. শতাংশের বদলে fr ব্যবহারের এটাই বড় কারণ।

ব্রাউজার আসলে কত px হিসাব করল, সেটা JavaScript দিয়েও পড়া যায়। getComputedStyle() দিয়ে gridTemplateColumns পড়লে fr-এর বদলে আসল px মান ফেরত আসে। নিচে একটি 600px চওড়া grid-এ তিনটি ভিন্ন প্যাটার্ন মেপে দেখানো হলো:

const grid = document.querySelector('.g');

(function measure() {
  if (!document.body.offsetWidth) return setTimeout(measure, 50);
  const tracks = () => getComputedStyle(grid).gridTemplateColumns;

  console.log('200px 1fr 2fr  →', tracks());

  grid.style.gridTemplateColumns = 'repeat(3, 1fr)';
  console.log('repeat(3, 1fr) →', tracks());

  grid.style.gridTemplateColumns = '1fr 3fr';
  console.log('1fr 3fr        →', tracks());
})();

প্রথম লাইনে আসবে 200px 120px 240px — ডায়াগ্রামের হিসাবের সাথে হুবহু মিল। repeat(3, 1fr)-এ (600 − 40) ÷ 3, প্রায় 186.667px করে; আর 1fr 3fr-এ gap একটি, তাই (600 − 20) ÷ 4 = 145px আর 435px. চেষ্টা করুন: শেষ প্যাটার্নটিকে '100px auto 1fr' করুন — auto কলাম শুধু “B” অক্ষর আর তার padding-এর মাপ নেবে, বাকিটা পাবে 1fr. DevTools-এর Computed প্যানেলেও এই একই px মান দেখা যায়।

আরও গভীরে: স্পেসিফিকেশনে 1fr আসলে minmax(auto, 1fr) — অর্থাৎ কলাম কখনো তার ভেতরের জিনিসের ন্যূনতম মাপের (min-content) চেয়ে ছোট হবে না। তাই একটি কলামে খুব লম্বা একটি URL বা ভাঙা যায় না এমন শব্দ থাকলে 1fr 1fr-এর দুই কলাম আর সমান থাকে না; সমান রাখতে চাইলে লিখুন minmax(0, 1fr). ব্রাউজার এই হিসাবটি করে স্পেসিফিকেশনের “track sizing algorithm” দিয়ে — আগে প্রতিটি track-এর ন্যূনতম আর সর্বোচ্চ মাপ ঠিক করে, তারপর ধাপে ধাপে জায়গা বাড়িয়ে শেষে fr-গুলোকে বাকি জায়গা দেয়। minmax() আর auto-fit দিয়ে মিডিয়া কোয়েরি ছাড়াই রেসপন্সিভ কলাম বানানো হবে পর্ব ২৮-এ।

gap নিয়ে শেষ কথা: gap: 10px সারি আর কলাম দুই দিকেই ফাঁক দেয়; আলাদা চাইলে gap: 20px 10px (আগে সারির ফাঁক, পরে কলামের) বা row-gap আর column-gap. gap শুধু track-এর মাঝে বসে, কিনারায় নয় — বাইরের ফাঁকের জন্য container-এর padding. পুরোনো কোডে grid-gap, grid-row-gap দেখবেন; এগুলো আগের নাম, এখনো কাজ করে, কিন্তু নতুন কোডে gap লিখুন — একই property এখন Flexbox-এও চলে।

৪ · Grid line আর লাইন নম্বর — ছকের ঠিকানা

ঘর ভরানোর ব্যাপারটা ব্রাউজারের হাতে ছেড়ে না দিয়ে নিজে বলতে চাইলে প্রথমে ঠিকানা লাগবে। Grid-এ ঠিকানা দেওয়া হয় ঘর দিয়ে নয়, দাগ দিয়ে। প্রতিটি grid line-এর একটি নম্বর আছে, ১ থেকে শুরু। সহজ সূত্র: n টি track মানে n + 1 টি লাইন — ৩টি কলাম হলে খাড়া লাইন ৪টি, ২টি সারি হলে আড়াআড়ি লাইন ৩টি। ঠিক যেমন রুটিনের ছকে তিনটি কলাম কাটতে চারটি খাড়া দাগ টানতে হয়।

1234
1234
123
1234
123
-3-2-1
-4-3-2-1
1234
123
1 / 3
1234
123
span
2
1 / -2
  1. খাড়া লাইন — কলামের ঠিকানা। তিনটি কলাম কাটতে চারটি খাড়া দাগ লাগে: বাঁ কিনারা ১, তারপর ২, ৩, আর ডান কিনারা ৪. খেয়াল করুন, কিনারার দাগও লাইন — এটাই নতুনদের সবচেয়ে বড় ভুলের জায়গা (“৩ কলাম, তাহলে শেষ লাইন ৩” — না, ৪)।
  2. আড়াআড়ি লাইন — সারির ঠিকানা। একই নিয়মে দুটি সারির জন্য তিনটি আড়াআড়ি লাইন: ওপরের কিনারা ১, মাঝের দাগ ২, নিচের কিনারা ৩. gap থাকলে লাইনটা gap-এর মাঝখানে নয় — gap-কেই একটি মোটা লাইন ভাবুন।
  3. ঋণাত্মক নম্বর — উল্টো দিক থেকে গোনা। প্রতিটি লাইনের একটি ঋণাত্মক নামও আছে: শেষ দিক থেকে −১, −২… তাই -1 সবসময় শেষ লাইন, কলাম যতই হোক। grid-column: 1 / -1 মানে “প্রথম দাগ থেকে শেষ দাগ” — অর্থাৎ পুরো চওড়া; হেডার, ফুটার বা ব্যানারের জন্য খুব কাজের। একটি সূক্ষ্ম কথা: ঋণাত্মক নম্বর গোনা হয় শুধু আপনার নিজে বানানো (explicit) ছকের শেষ থেকে — অংশ ৬-এ এর মানে পরিষ্কার হবে।
  4. লাইন দিয়ে item বসানো। হলুদ item-কে বলা হয়েছে grid-column: 1 / 3 — “খাড়া লাইন ১ থেকে শুরু, ৩-এ শেষ”, অর্থাৎ প্রথম দুটি কলাম জুড়ে। /-এর আগে শুরুর লাইন, পরে শেষের লাইন। শেষের লাইন না দিলে item এক ঘর জুড়ে থাকে।
  5. span আর ঋণাত্মক একসাথে। সবুজ item: grid-column: 3 (তৃতীয় কলামে) আর grid-row: 1 / span 2 — “লাইন ১ থেকে শুরু করে দুই ঘর জুড়ে”, শেষ লাইন গোনার ঝামেলা নেই। বেগুনি item: grid-column: 1 / -2 — প্রথম লাইন থেকে শেষের আগের লাইন পর্যন্ত, তাই প্রথম দুটি কলাম। একই জায়গা 1 / 3 বা 1 / span 2 লিখেও পাওয়া যেত — Grid-এ একই কাজের কয়েকটি লেখার উপায় থাকে।

৫ · item বসানো — grid-column, grid-row আর span

ডায়াগ্রামে যা দেখলেন, এবার নিজে লিখুন। grid-column আসলে দুটি property-র shorthand: grid-column-start আর grid-column-end; grid-row-ও তেমনি। লেখার ধরনগুলো:

লেখামানে
grid-column: 2লাইন ২ থেকে শুরু, এক ঘর (দ্বিতীয় কলাম)
grid-column: 1 / 3লাইন ১ থেকে লাইন ৩ পর্যন্ত — দুই কলাম
grid-column: 2 / span 3লাইন ২ থেকে শুরু, তিন ঘর জুড়ে
grid-column: span 2দুই ঘর জুড়ে, কিন্তু কোথায় — সেটা ব্রাউজার ঠিক করবে
grid-column: 1 / -1প্রথম থেকে শেষ লাইন — পুরো চওড়া

নিচের এডিটরে চারটি সমান কলাম, আর তিনটি বাক্সকে নিজে বসানো হয়েছে। বাকিগুলো খালি ঘর খুঁজে নিজেরাই বসবে:

.g {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 60px;
  gap: 8px;
}
.b1 { grid-column: 1 / 3; }          /* লাইন ১ থেকে ৩: দুই কলাম */
.b2 { grid-column: 3;                /* তৃতীয় কলাম, */
      grid-row: 1 / span 2; }        /* দুই সারি উঁচু */
.b7 { grid-column: 1 / -1; }         /* পুরো চওড়া */

১ নম্বর বাক্স প্রথম দুই কলাম জুড়ে, ২ নম্বর তৃতীয় কলামে দুই সারি উঁচু, আর ৭ নম্বর নিচে পুরো চওড়া। ৩, ৪, ৫, ৬ নিজেরাই খালি ঘরে বসেছে — ৩ গেছে ওপরের সারির শেষ ঘরে, বাকিরা দ্বিতীয় সারিতে ২-এর দুই পাশে। (grid-auto-rows লাইনটির কথা পরের অংশে।) চেষ্টা করুন: .b7-কে grid-column: 2 / -1 করুন — বাঁ দিকে একটি ঘর খালি থাকল। তারপর .b1-কে grid-column: 1 / span 2 লিখুন — চেহারা একটুও বদলাবে না, কারণ দুটোর মানে এক।

লাইন নম্বর দিয়ে item-কে অন্য জায়গায় সরানো সহজ — ধরুন HTML-এ শেষে থাকা “বিজ্ঞাপন” বাক্সকে grid-row: 1 দিয়ে ওপরে তুলে আনলেন। চোখে সে ওপরে, কিন্তু screen reader তাকে পড়বে সবার শেষে, আর Tab চাপলে কীবোর্ড focus-ও যাবে HTML-এর ক্রমে। তাই নিয়ম: অর্থের ক্রম HTML-এ ঠিক রাখুন, Grid দিয়ে শুধু চেহারা সাজান। এ নিয়ে বিস্তারিত পরের অংশে।

৬ · Explicit আর implicit grid — grid-auto-rows আর grid-auto-flow

grid-template-columns আর grid-template-rows দিয়ে আপনি যে ছক নিজে কাটেন, তার নাম explicit grid. কিন্তু item যদি ছকের ঘরের চেয়ে বেশি হয়? ধরুন ছক বানালেন ৪ × ২ = ৮ ঘরের, অথচ পণ্য এলো ১০টি। Grid তখন জিনিস ফেলে দেয় না — প্রয়োজনমতো নতুন সারি নিজেই যোগ করে নেয়। এই আপনা-আপনি তৈরি অংশের নাম implicit grid. বিয়েবাড়িতে অতিথি বেশি এলে বাড়তি চেয়ার পেতে দেওয়ার মতো — চেয়ারগুলো আগে থেকে পরিকল্পনায় ছিল না, কিন্তু দরকারে এসে গেল।

নতুন সারিগুলোর মাপ কত হবে? ডিফল্ট হলো auto — ভেতরের জিনিস যতটা চায়। নিজে ঠিক করতে চাইলে grid-auto-rows (আর কলামের জন্য grid-auto-columns). আর item-রা কোন দিকে ঘর ভরাবে — সারি ধরে না কলাম ধরে — সেটা ঠিক করে grid-auto-flow. নিচের ডায়াগ্রামে ব্রাউজারের ঘর-ভরানোর প্রক্রিয়াটি ধাপে ধাপে দেখুন। ৪ নম্বর item দুই ঘর চওড়া (span 2):

1
2
3
1
2
3
ফাঁকা
4 (span 2)
1
2
3
ফাঁকা
4 (span 2)
5
6
7
1
2
3
4 (span 2)
5
6
7
  1. খালি explicit ছক। grid-template-columns: repeat(4, 1fr) আর grid-template-rows: 44px 44px — আটটি ঘর। ব্রাউজার একটি কাল্পনিক “cursor” (পড়ার আঙুলের মতো) নিয়ে ওপরের বাঁ কোণ থেকে শুরু করবে।
  2. সারি ধরে ভরানো। ডিফল্ট grid-auto-flow: row — ১, ২, ৩ বাঁ থেকে ডানে বসল, HTML-এর ক্রমে। cursor এখন সারি ১-এর চতুর্থ ঘরে।
  3. জায়গা না পেলে পরের সারিতে। ৪ নম্বর item দুই ঘর চওড়া, কিন্তু সারি ১-এ বাকি মাত্র একটি ঘর। ব্রাউজার item ভাঙে না, তাকে পাঠিয়ে দেয় সারি ২-এ। ফলে সারি ১-এর শেষ ঘরটি খালি থেকে যায় — ডিফল্ট পদ্ধতি (sparse) cursor-কে কখনো পেছনে নেয় না, যাতে HTML-এর ক্রম চোখের ক্রমেও থাকে।
  4. Implicit সারি। ৫ আর ৬ সারি ২-এর বাকি দুই ঘরে বসল। এবার ৭-এর জন্য explicit ছকে আর কোনো ঘর নেই। ব্রাউজার নতুন সারি ৩ তৈরি করল — এটাই implicit grid (বেগুনি ড্যাশ দাগ)। তার উচ্চতা এসেছে grid-auto-rows: 44px থেকে; না দিলে হতো auto.
  5. dense — ফাঁক ভরানো। grid-auto-flow: row dense দিলে প্রতিটি item-এর জন্য ব্রাউজার আবার শুরু থেকে খালি ঘর খোঁজে। ৫ (লাল) পেছনের ফাঁকা ঘরটি পেয়ে গেল, ৬ আর ৭ সারি ২-এ উঠে এলো, তৃতীয় সারি আর লাগল না। দেখতে গোছানো — কিন্তু চোখে এখন ক্রম ১, ২, ৩, ৫, তারপর ৪, ৬, ৭. HTML-এ ক্রম কিন্তু আগের মতোই ১ থেকে ৭.

এবার explicit আর implicit অংশ নিজে আলাদা করে দেখুন। এখানে explicit ছক ২ × ২, অথচ বাক্স আটটি:

.g {
  display: grid;
  grid-template-columns: 1fr 1fr;   /* explicit: ২টি কলাম */
  grid-template-rows: 70px 70px;    /* explicit: ২টি সারি */

  grid-auto-rows: 35px;             /* বাড়তি সারির মাপ */
  grid-auto-columns: 60px;          /* বাড়তি কলামের মাপ */
  gap: 8px;
}

১–৪ বসেছে 70px উঁচু explicit সারিতে, আর ৫–৮-এর জন্য ব্রাউজার দুটি নতুন 35px উঁচু implicit সারি বানিয়েছে। grid-auto-columns এখনো কাজে লাগেনি, কারণ সারি ধরে ভরালে নতুন কলাম লাগে না। চেষ্টা করুন: ব্লকের ভেতরে grid-auto-flow: column; যোগ করুন — এবার ১, ২ প্রথম কলামের ওপর-নিচে, ৩, ৪ দ্বিতীয় কলামে, আর ৫–৮-এর জন্য ডানে দুটি 60px চওড়া implicit কলাম তৈরি হলো। তারপর grid-auto-rows-কে minmax(35px, auto) করে কোনো বাক্সে লম্বা লেখা লিখুন — সারিটি দরকারমতো উঁচু হবে, কিন্তু 35px-এর নিচে নামবে না।

একটি গুরুত্বপূর্ণ খুঁটিনাটি: ঋণাত্মক লাইন নম্বর গোনা হয় শুধু explicit grid-এর শেষ থেকে। উপরের এডিটরে কোনো বাক্সকে grid-row: 1 / -1 দিলে সে শুধু দুটি explicit সারি জুড়বে, implicit সারিগুলো পর্যন্ত যাবে না। তাই “পুরো উচ্চতা জুড়ে সাইডবার” বানাতে 1 / -1 তখনই কাজ করে, যখন সারিগুলো grid-template-rows-এ লেখা থাকে।

dense — সুন্দর, কিন্তু সাবধানে

ছবির গ্যালারি বা ড্যাশবোর্ডে, যেখানে কিছু item বড় আর কিছু ছোট, dense ফাঁকগুলো ভরিয়ে দেয়। কিন্তু চোখের ক্রম আর HTML-এর ক্রম আলাদা হয়ে যায়। নিচের বাক্সগুলো বোতাম, তাই কীবোর্ড দিয়ে চালানো যায়:

.g {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 50px;
  gap: 8px;
  grid-auto-flow: row;     /* এখানে row dense লিখে দেখুন */
}
.wide { grid-column: span 2; }
button:focus-visible { outline: 3px solid #dc2626; outline-offset: 2px; }

এখন ওপরের সারির শেষে একটি ফাঁকা ঘর, ঠিক ডায়াগ্রামের মতো। row-কে row dense করুন — ৫ লাফিয়ে ফাঁকা ঘরে উঠে গেল। এবার প্রিভিউর ভেতরে ১ নম্বর বোতামে ক্লিক করে বারবার Tab চাপুন: লাল focus দাগ যাবে ১ → ২ → ৩ → ৪ → ৫ — অর্থাৎ নিচের সারির চওড়া ৪ থেকে হঠাৎ ওপরে ৫-এ লাফ দেবে। কীবোর্ড ব্যবহারকারীর কাছে পাতাটা এলোমেলো লাগবে।

অ্যাক্সেসিবিলিটির নিয়ম: কীবোর্ড focus আর screen reader সবসময় DOM-এর (HTML-এর) ক্রম মানে, Grid-এর চোখের ক্রম নয়। WCAG 2.2-এর দুটি নিয়ম এখানে প্রাসঙ্গিক — 1.3.2 “Meaningful Sequence” (অর্থ বুঝতে ক্রম জরুরি হলে সেই ক্রম যন্ত্রও যেন পায়) আর 2.4.3 “Focus Order” (focus-এর ক্রম যেন অর্থ আর ব্যবহার ঠিক রাখে)। তাই dense ব্যবহার করুন শুধু সেখানে, যেখানে ক্রমের কোনো অর্থ নেই — যেমন সাজানোর ছবির গ্যালারি। ধাপে ধাপে নির্দেশনা, খবরের তালিকা বা ফর্মে নয়। CSS-এ reading-flow নামে একটি নতুন property আসছে, যা focus-এর ক্রম চোখের ক্রমের সাথে মেলাতে পারবে; এটি কেবল Chromium-ভিত্তিক ব্রাউজারে এসেছে, এখনো Baseline নয় — তাই এর ওপর ভরসা না করে HTML-এর ক্রমই ঠিক রাখুন।

৭ · Grid-এ সারিবদ্ধ করা — items, content আর self

Grid-এ দুটি আলাদা প্রশ্ন আছে, আর সেগুলো গুলিয়ে ফেলাই সবচেয়ে সাধারণ ভুল। এক: প্রতিটি ঘরের ভেতরে item কোথায় বসবে — ঘর ভরে, নাকি বাঁয়ে, মাঝে, ডানে? দুই: পুরো ছকটা যদি container-এর চেয়ে ছোট হয়, তাহলে ছকটাই container-এর কোথায় বসবে? প্রথমটি *-items আর *-self-এর কাজ, দ্বিতীয়টি *-content-এর।

একটি মুদি দোকানের তাক ভাবুন। তাকের প্রতিটি খোপে একটি করে বয়াম। items হলো প্রতিটি খোপের ভেতরে বয়াম কোথায় রাখবেন — বাঁ কোণে, মাঝে, নাকি পুরো খোপ জুড়ে। content হলো পুরো তাকটা দেয়ালের কোথায় বসাবেন — দেয়াল বড়, তাক ছোট হলে বাঁয়ে, মাঝে নাকি ডানে। আর self হলো কোনো একটি বিশেষ বয়ামকে আলাদা নির্দেশ।

দিকের নামও মনে রাখুন: justify- মানে লেখা চলার দিক (inline axis) — বাংলা বা ইংরেজিতে আড়াআড়ি; align- মানে block-এর দিক (block axis) — খাড়া। Flexbox-এ flex-direction বদলালে দিক উল্টে যায়, কিন্তু Grid-এ এই দুই দিক স্থির। এই পুরো ব্যবস্থার নাম CSS Box Alignment — Flexbox আর Grid একই property ভাগ করে নেয়।

কাকে সরায়আড়াআড়ি (inline)খাড়া (block)দুটো একসাথে
সব item, নিজের ঘরের ভেতরে (container-এ লিখুন)justify-itemsalign-itemsplace-items
একটি item, নিজের ঘরের ভেতরে (item-এ লিখুন)justify-selfalign-selfplace-self
পুরো ছক, container-এর ভেতরে (container-এ লিখুন)justify-contentalign-contentplace-content

ডিফল্ট মান stretch-এর মতো আচরণ করে — item পুরো ঘর ভরে থাকে। এজন্যই আগের এডিটরগুলোতে সব বাক্স ঘরের সমান ছিল। start, center, end দিলে item নিজের মাপে ফিরে যায় আর ঘরের ভেতরে সরে। নিচের এডিটরে ঘর বড়, ছকও container-এর চেয়ে ছোট — তাই সব property-র প্রভাব একসাথে দেখা যায়:

.g {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(2, 70px);
  gap: 8px;
  height: 220px;              /* container ছকের চেয়ে বড় */

  justify-items: start;       /* ঘরের ভেতরে: আড়াআড়ি */
  align-items: center;        /* ঘরের ভেতরে: খাড়া */

  justify-content: center;    /* পুরো ছক: আড়াআড়ি */
  align-content: end;         /* পুরো ছক: খাড়া */
}
.b5 { justify-self: stretch; align-self: end; }

পুরো ছকটা container-এর মাঝখানে আর নিচের দিকে সরে গেছে (justify-content: center, align-content: end). ছকের প্রতিটি ঘরের ভেতরে বাক্সগুলো ছোট হয়ে বাঁ দিকে, খাড়াভাবে মাঝখানে বসেছে। শুধু ৫ নম্বর নিজের নিয়ম মেনেছে — ঘরের পুরো চওড়া জুড়ে, ঘরের তলায়। চেষ্টা করুন: justify-items আর align-items লাইন দুটির বদলে একটি লাইন লিখুন place-items: center; — সব বাক্স ঘরের ঠিক মাঝখানে। আর justify-content-কে space-between করুন — কলামগুলো ছড়িয়ে গিয়ে মাঝের ফাঁক বেড়ে গেল।

একটি বিখ্যাত কৌশল এখান থেকেই আসে: কোনো কিছু ঠিক মাঝখানে বসাতে container-এ শুধু দুই লাইন — display: grid; place-items: center;. বহু বছর ওয়েব ডেভেলপারদের রসিকতা ছিল “CSS-এ জিনিস খাড়াভাবে মাঝখানে আনা যায় না”; Flexbox আর Grid সেই রসিকতার অবসান ঘটিয়েছে। place-items-এ দুটি মান দিলে প্রথমটি align (খাড়া), দ্বিতীয়টি justify (আড়াআড়ি) — উল্টো ক্রম নয়, মনে রাখুন।

৮ · একই ঘরে একাধিক item — overlap আর z-index

Grid-এর একটি অসাধারণ সুবিধা: দুই বা ততোধিক item-কে একই ঘরে বসানো যায়, আর তারা একে অপরের ওপর স্তরে স্তরে থাকে। পর্ব ২৪-এ এই কাজ করেছেন position: absolute দিয়ে — কিন্তু absolute item স্বাভাবিক flow থেকে বেরিয়ে যায়, তার মাপ parent জানে না। Grid-এ overlap করা item-রা ছকের ভেতরেই থাকে; সবচেয়ে বড়টির মাপে ঘর বাড়ে, কিছু উপচে পড়ে না।

কে কার ওপরে থাকবে? ডিফল্টে HTML-এ যে পরে আসে, সে ওপরে আঁকা হয়। বদলাতে চাইলে z-index — আর মজার কথা, grid item-এ z-index কাজ করে position ছাড়াই (সাধারণ block-এ যা করে না)। নিচে একটি পণ্যের কার্ড — ছবি, ছাড়ের ব্যাজ আর নাম, তিনটিই একই ঘরে:

.card {
  display: grid;
  width: 260px;
  font: 700 17px system-ui, sans-serif;
}
.card > * {
  grid-row: 1;            /* সবাই সারি ১-এ */
  grid-column: 1;         /* সবাই কলাম ১-এ — একই ঘর */
}
.photo { height: 170px; border-radius: 12px;
         background: linear-gradient(135deg, #f59e0b, #b91c1c); }
.badge { justify-self: end; align-self: start; margin: 10px;
         background: #111; color: #fff; padding: 4px 10px;
         border-radius: 99px; }
.name  { align-self: end; margin: 0; padding: 12px; color: #fff; }

তিনটি item একই ঘরে: ছবি পুরো ঘর জুড়ে, ব্যাজ ঘরের ওপর-ডান কোণে (justify-self: end; align-self: start), আর নাম তলায়। কোনো position লাগেনি। খেয়াল করুন, span একটি inline element, তবু grid item হওয়ায় block-এর মতো margin আর padding নিয়েছে। চেষ্টা করুন: .photo-তে z-index: 1; যোগ করুন — ছবি ওপরে উঠে ব্যাজ আর নাম ঢেকে দিল। এবার .name-এ z-index: 2; দিন — নামটি আবার ছবির ওপরে দেখা যাবে, ব্যাজ কিন্তু চাপা পড়েই থাকবে।

এখানে দুটি অ্যাক্সেসিবিলিটির খুঁটিনাটিও খেয়াল করুন। ছবিটি একটি div-এর ব্যাকগ্রাউন্ড, তাই তার অর্থ বোঝাতে role="img" আর aria-label দেওয়া হয়েছে (আসল ছবি হলে <img alt="…"> ভালো)। আর ছবির ওপর সাদা লেখা বসালে রঙের contrast যথেষ্ট কি না, যাচাই করতে হয় — উজ্জ্বল ছবিতে লেখার নিচে একটু গাঢ় gradient রাখাই নিরাপদ।

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

  • Flexbox আর Grid-এর মূল পার্থক্য কী? — Flexbox এক দিকের (one-dimensional) লেআউট; Grid সারি আর কলাম দুই দিক একসাথে (two-dimensional) নিয়ন্ত্রণ করে।
  • fr একক কী? — নির্দিষ্ট মাপের track আর gap বাদ দেওয়ার পর বাকি জায়গার একটি ভাগ; শতাংশের মতো container থেকে বেরিয়ে যায় না।
  • ৪টি কলামে কয়টি খাড়া grid line থাকে, আর grid-column: 1 / -1 মানে কী? — ৫টি; প্রথম থেকে শেষ লাইন, অর্থাৎ পুরো চওড়া।
  • explicit আর implicit grid-এর পার্থক্য? — template দিয়ে নিজে বানানো ছক explicit; বাড়তি item-এর জন্য ব্রাউজারের তৈরি সারি-কলাম implicit, যার মাপ দেয় grid-auto-rows/grid-auto-columns.
  • justify-items আর justify-content-এর পার্থক্য? — প্রথমটি প্রতিটি ঘরের ভেতরে item সরায়; দ্বিতীয়টি ছক container-এর চেয়ে ছোট হলে পুরো ছকটি সরায়।

৯ · Flexbox না Grid? DevTools-এ grid দেখা, আর সামনে যা আসছে

“Grid এসেছে, তাহলে কি Flexbox বাদ?” — একেবারেই না। দুটি দুই রকম চিন্তার টুল। Rachel Andrew-এর একটি বহুল উদ্ধৃত ব্যাখ্যা সবচেয়ে কাজের: Flexbox কাজ করে content-out — জিনিসগুলোর নিজের মাপ থেকে লেআউট তৈরি হয়, আপনি শুধু বলেন কীভাবে জায়গা ভাগাভাগি করবে। Grid কাজ করে layout-in — আগে আপনি ছক ঠিক করেন, তারপর জিনিসগুলো সেই ছকে বসে। নিজেকে প্রশ্ন করুন: “আমি কি জিনিসগুলোকে সাজাতে দিচ্ছি, নাকি জিনিসগুলোর জন্য জায়গা ঠিক করে দিচ্ছি?”

পরিস্থিতিসাধারণত ভালোকেন
navbar-এর লিংক, ট্যাগের সারি, বোতাম আর আইকনFlexboxএক লাইন; প্রতিটির মাপ নিজের লেখা থেকে
পুরো পাতার কাঠামো — হেডার, সাইডবার, মূল অংশ, ফুটারGridসারি আর কলাম দুটোই নিয়ন্ত্রণ দরকার
পণ্যের কার্ডের গ্যালারি, যেখানে কলাম মিলে থাকতে হবেGridশেষ সারিতেও কার্ডগুলো ওপরের কলামে থাকে
কার্ডের ভেতরে: ছবি, লেখা, তলায় বোতামFlexbox (কলাম)এক দিকে সাজানো, বোতাম নিচে ঠেলা
লেখা যত লম্বা, ট্যাগ তত চওড়া — যতগুলো ধরে এক লাইনেFlexbox (wrap)content-out — আগে থেকে ছক নেই
ছবির ওপর লেখা বা ব্যাজGrid (একই ঘরে)position ছাড়াই overlap
কোনো কিছু ঠিক মাঝখানেদুটোইplace-items: center বা flex-এ দুই center

বাস্তবে সবচেয়ে ভালো ফল আসে দুটো মিলিয়ে — পাতার কাঠামো Grid, প্রতিটি অংশের ভেতর Flexbox. এগুলো নিয়ে বাস্তব নকশা — sidebar, holy grail, dashboard — পর্ব ২৯-এ।

DevTools-এ grid চোখে দেখা

Grid-এর লাইনগুলো পাতায় অদৃশ্য, তাই ভুল ধরতে DevTools-এর grid overlay অপরিহার্য। Chrome বা Edge-এ কোনো পাতায় ডান-ক্লিক করে “Inspect” চাপুন; Elements প্যানেলে grid container-এর পাশে ছোট একটি grid ব্যাজ দেখবেন। সেটাতে চাপলে পাতার ওপর ছকটি রঙিন দাগে আঁকা হয়। পাশের Layout ট্যাবে কয়েকটি কাজের বিকল্প আছে — লাইন নম্বর দেখানো (ধনাত্মক, ঋণাত্মক বা দুটোই), প্রতিটি track-এর মাপ দেখানো, আর লাইনগুলো পাতার কিনারা পর্যন্ত টেনে দেওয়া। Firefox-এ Inspector-এর Layout প্যানেলের Grid অংশে একই রকম সুবিধা — আর ঐতিহাসিকভাবে Firefox-ই এমন grid inspector সবার আগে এনেছিল।

মূল ধারণা

Grid-এ কিছু ভুল জায়গায় বসলে আন্দাজে লাইন নম্বর বদলাবেন না। আগে overlay চালু করে লাইন নম্বর দেখুন — বেশিরভাগ সময় দেখবেন শেষ লাইন ৪-এর বদলে ৩ লিখেছেন, বা একটি implicit সারি তৈরি হয়েছে যা আপনি চাননি।

পর্ব ২৮-এ যা আসছে

এই পর্বে Grid-এর ভিত্তি শেষ হলো। পরের পর্বে তিনটি শক্তিশালী কৌশল, এখানে শুধু এক ঝলক:

/* ১. নাম দিয়ে ছক আঁকা — grid-template-areas */
.page { grid-template-areas: "head head" "side main"; }

/* ২. মিডিয়া কোয়েরি ছাড়াই যত কলাম ধরে — auto-fit + minmax() */
.gallery { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

/* ৩. ভেতরের grid বাইরের ছকের লাইন মানবে — subgrid */
.card { grid-row: span 3; display: grid; grid-template-rows: subgrid; }

subgrid ২০২৩ সাল থেকে সব প্রধান ব্রাউজারে আছে; এর সাহায্যে আলাদা আলাদা কার্ডের শিরোনাম, লেখা আর বোতাম সব কার্ডে একই উচ্চতায় মেলানো যায় — যা এতদিন প্রায় অসম্ভব ছিল।

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

“একটা পণ্যের গ্যালারি বানিয়ে দাও” বললে AI কয়েক সেকেন্ডে কোড দেয়, আর প্রথম দেখায় সেটা ঠিকঠাকই লাগে। কিন্তু AI শিখেছে ইন্টারনেটের বহু বছরের কোড থেকে — যার বড় অংশ Grid আসার আগের। তাই প্রায়ই সে float, Bootstrap-এর row/col div, অদরকারি wrapper-এর স্তূপ (div-soup) বা পুরোনো prefix নিয়ে আসে। আর চোখের ক্রম বদলালে কীবোর্ড ব্যবহারকারীর কী হয়, সেটা সে নিজে থেকে প্রায় কখনো ভাবে না।

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

AI-এর ভুলআপনি যা দেখবেনঠিক উপায়
float: left; width: 33.33% আর clearfixউচ্চতা অসমান হলে কার্ড আটকে যায়, লেআউট ভাঙেdisplay: grid + repeat(3, 1fr)
repeat(4, 25%) সাথে gapডানে বেরোনো ছক, ফোনে পাশে স্ক্রলশতাংশের বদলে 1fr
-ms-grid, grid-gap, -webkit- prefixঅপ্রয়োজনীয় পুরোনো লাইনprefix ছাড়া display: grid আর gap
dense বা লাইন নম্বর দিয়ে item-এর ক্রম উল্টানোTab চাপলে focus এলোমেলো লাফায়HTML-এর ক্রম ঠিক রাখা; ক্রমহীন গ্যালারিতেই শুধু dense
overlay-র জন্য position: absolute আর নির্দিষ্ট heightলম্বা লেখা কার্ড থেকে উপচে পড়েএকই ঘরে grid item আর align-self
প্রতিটি সারির জন্য আলাদা wrapper divকলাম মেলে না, HTML ভারীএকটি container, সব item সরাসরি সন্তান

AI-কে কাজ দেওয়ার সময় শর্তগুলো আগেই লিখে দিন। শেষ অনুরোধটি খেয়াল করুন — লাইন নম্বরের হিসাব লিখে দেখাতে বললে AI-এর নিজের ভুলও প্রায়ই নিজেই বেরিয়ে আসে, আর আপনি DevTools-এর overlay-র সাথে মিলিয়ে নিতে পারেন।

তুমি একজন অভিজ্ঞ ফ্রন্ট-এন্ড ডেভেলপার। আমার অনলাইন দোকানের হোমপেজের জন্য HTML আর CSS লেখো: ওপরে হেডার, বাঁয়ে ২৫০px সাইডবার, ডানে পণ্যের কার্ডের গ্যালারি (চারটি সমান কলাম), নিচে পুরো চওড়া ফুটার। শর্ত: ১. পাতার কাঠামোর জন্য CSS Grid, কার্ডের ভেতরের জন্য Flexbox. float, table, Bootstrap বা কোনো framework নয়। ২. header, nav, main, footer-এর মতো semantic element; প্রতিটি সারির জন্য বাড়তি wrapper div নয়। ৩. কলামের মাপে শতাংশ নয়, fr; gap দিয়ে ফাঁক; -ms- বা -webkit- prefix নয়, grid-gap নয়। ৪. dense বা order দিয়ে HTML-এর ক্রম বদলাবে না — কীবোর্ডের Tab-এর ক্রম আর চোখের ক্রম এক থাকবে। ৫. প্রতিটি grid item কোন লাইন থেকে কোন লাইন পর্যন্ত বসেছে (যেমন grid-column: 1 / -1), একটি ছোট তালিকায় লিখে দেখাও।

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

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

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

প্র ০১ওয়েব শুরু ১৯৯০-এর দশকে, অথচ সত্যিকারের লেআউট পদ্ধতি Grid এলো ২০১৭ সালে। এত দেরি কেন, আর মাঝের বছরগুলোতে মানুষ কীভাবে কাজ চালাত?

শুরুতে ওয়েব ছিল বিজ্ঞানীদের নথি ভাগাভাগির মাধ্যম — শিরোনাম, প্যারাগ্রাফ, লিংক। “পাতার নকশা” ধারণাটাই সেখানে ছিল না। ব্যবসা যখন ওয়েবে এলো, ডিজাইনাররা চাইলেন পত্রিকার মতো কলাম। তখন হাতের কাছে যা ছিল, তা-ই দিয়ে কাজ চালানো হলো:

  • Table layout (১৯৯০-এর দশক): পুরো পাতা একটি বিশাল <table>, ফাঁকা জায়গার জন্য স্বচ্ছ ছোট ছবি (spacer GIF). দেখতে কাজ করত, কিন্তু screen reader পুরো পাতাকে তথ্যের টেবিল ভেবে পড়ত, আর একটু বদলাতে গেলেই পুরো টেবিল নতুন করে লিখতে হতো।
  • Float layout (২০০০-এর দশক): CSS আসার পর float দিয়ে কলাম বানানো হলো — যদিও float তৈরি হয়েছিল লেখার পাশে ছবি ভাসানোর জন্য। ফলে “clearfix” নামের কৌশল, সমান উচ্চতার কলামের জন্য নানা হ্যাক, আর এক পিক্সেলের ভুলে কলাম নিচে নেমে যাওয়া। এই সময়েই 960 Grid System বা পরে Bootstrap-এর মতো framework জনপ্রিয় হয় — তারা float-এর ঝামেলা class-এর আড়ালে লুকিয়ে রাখত।
  • Flexbox (২০১০-এর দশক): প্রথম সত্যিকারের লেআউট টুল, কিন্তু এক দিকের। তার স্পেসিফিকেশন তিনবার বড় রকম বদলায়, আর ব্রাউজারগুলো মাঝপথের সংস্করণ prefix দিয়ে চালু করে ফেলায় বছরের পর বছর তিন রকম syntax লিখতে হতো।

Grid-এর দেরির কারণ অনেকটা এই শিক্ষাই। Microsoft-এর প্রাথমিক রূপ (IE 10-এর -ms-grid) আগেই এসেছিল, কিন্তু তাতে auto-placement বা gap ছিল না — প্রতিটি item-কে নিজে সারি-কলাম বলে দিতে হতো, নইলে সবাই প্রথম ঘরে স্তূপ হয়ে থাকত। এরপর নতুন Grid-কে ব্রাউজারগুলো বছরের পর বছর “পরীক্ষামূলক” সেটিংয়ের আড়ালে রাখে, যাতে স্পেসিফিকেশন পাকা হওয়ার আগে কেউ তার ওপর নির্ভর না করে। Chrome আর Safari-তে বড় অংশের কাজ করে Igalia নামের একটি প্রতিষ্ঠান, Bloomberg-এর অর্থায়নে। ফল — ২০১৭ সালের মার্চে কয়েক সপ্তাহের মধ্যে প্রায় একই রকম Grid সব প্রধান ব্রাউজারে এলো, prefix ছাড়াই।

মূল উপলব্ধি: ওয়েবের মানদণ্ড ধীরে আসে কারণ একবার চালু হলে তা প্রায় কখনো ফেরানো যায় না — কোটি কোটি পাতা তার ওপর নির্ভর করে। Grid-এর “দেরি” আসলে সাবধানতার দাম, আর সেই দামেই আজ আপনি কোনো hack ছাড়া একই কোড সব ব্রাউজারে চালাতে পারেন।

প্র ০২Grid দিয়ে চোখের ক্রম বদলানো এত সহজ — তাহলে HTML-এর ক্রম নিয়ে মাথা ঘামানোর দরকার কী? কার ক্ষতি হয়?

পাতা সবাই চোখে দেখে না, আর সবাই মাউস দিয়েও চালায় না। ব্রাউজার যে accessibility tree বানায়, সেটি তৈরি হয় DOM-এর ক্রমে; Grid শুধু ছবি আঁকার সময় জিনিসগুলো সরায়। তাই ক্রমের অমিলে কয়েক রকম মানুষ সরাসরি ভোগেন:

  • Screen reader ব্যবহারকারী: দৃষ্টিপ্রতিবন্ধী একজন পাঠক শুনবেন HTML-এর ক্রমে। চোখে প্রথমে “ধাপ ১, ধাপ ২” থাকলেও HTML-এ উল্টো থাকলে তিনি নির্দেশনা উল্টো ক্রমে শুনবেন।
  • কীবোর্ড ব্যবহারকারী: হাতে সমস্যা আছে, বা দ্রুত কাজের জন্য যাঁরা Tab দিয়ে চলেন, তাঁদের focus পাতার এক কোণ থেকে আরেক কোণে লাফাবে। পর্দা বড় করে (zoom করে) দেখা কম-দৃষ্টির মানুষের কাছে এটা আরও বিভ্রান্তিকর — focus হঠাৎ পর্দার বাইরে চলে যায়।
  • সবার জন্যই: Reader mode, অনুবাদ টুল, সার্চ ইঞ্জিন, এমনকি copy-paste — সবাই DOM-এর ক্রম নেয়।

WCAG 2.2 এজন্যই দুটি “Level A” নিয়ম রেখেছে — 1.3.2 Meaningful Sequence আর 2.4.3 Focus Order. Level A মানে একেবারে ন্যূনতম শর্ত; অনেক দেশের সরকারি ওয়েবসাইটের নির্দেশিকা WCAG মানতে বলে, আর সেখানে এই স্তর বাদ দেওয়ার সুযোগ নেই।

CSS-এর স্পেসিফিকেশন নিজেই সতর্ক করে যে Grid-এর placement আর order শুধু চেহারার জন্য, অর্থের ক্রম বদলানোর জন্য নয়। সমস্যার স্থায়ী সমাধান হিসেবে CSS Working Group reading-flow নামে একটি property নিয়ে কাজ করছে, যা ব্রাউজারকে বলবে focus আর পড়ার ক্রম চোখের ক্রম মেনে চলুক। এটি এখনো সব ব্রাউজারে আসেনি।

মূল উপলব্ধি: “দেখতে ঠিক আছে” আর “ঠিক আছে” এক কথা নয়। HTML-এর ক্রম হলো পাতার অর্থের মেরুদণ্ড; CSS শুধু পোশাক। পোশাক বদলাতে গিয়ে মেরুদণ্ড বাঁকাবেন না।

প্র ০৩1fr 1fr লিখলেন, অথচ দুই কলাম সমান হলো না — একটি অনেক চওড়া। fr কি তাহলে মিথ্যা বলে?

না, fr ঠিক কথাই বলে — শুধু ছোট হরফের শর্তটা আমরা পড়ি না। স্পেসিফিকেশনে একা 1fr লেখা মানে আসলে minmax(auto, 1fr): “বাকি জায়গার এক ভাগ নাও, কিন্তু ভেতরের জিনিসের ন্যূনতম মাপের চেয়ে ছোট হবে না।” সাধারণ লেখায় ন্যূনতম মাপ হলো সবচেয়ে লম্বা শব্দের চওড়া (min-content). তাই একটি কলামে যদি থাকে ভাঙা যায় না এমন কিছু — লম্বা URL, ইমেইল ঠিকানা, <pre>-এর কোড, একটি নির্দিষ্ট চওড়ার ছবি বা টেবিল — সেই কলাম ওই মাপের নিচে নামবে না, আর বাকি জায়গা কম পাবে অন্য কলাম।

উদাহরণ: 600px container, 1fr 1fr, বাঁ কলামে একটি 450px চওড়া টেবিল। আদর্শ হিসাবে দুই কলাম 300px করে হওয়ার কথা, কিন্তু বাঁ কলাম 450px-এর নিচে নামতে পারবে না। তখন ব্রাউজার fr-কে আর সমান রাখতে পারে না — বাঁ কলাম 450px, ডান কলাম বাকি 150px.

সমাধান নির্ভর করে আপনি কী চান তার ওপর:

  • কলাম সমান থাকুক, ভেতরের জিনিস নিজে সামলাক: repeat(2, minmax(0, 1fr)), আর ভেতরে overflow-wrap: anywhere বা টেবিলের জন্য স্ক্রল হওয়া wrapper. বড় কোড-ব্লক বা টেবিল থাকা ব্লগে এটাই প্রচলিত।
  • জিনিস ঠিক থাকুক, কলাম মানিয়ে নিক: ডিফল্ট 1fr-ই যথেষ্ট — অনেক সময় এটাই ব্যবহারকারীর জন্য ভালো, কারণ কিছু কাটা পড়ে না।

এর পেছনের নকশা-চিন্তাটা গুরুত্বপূর্ণ। CSS-এর একটি মৌলিক নীতি হলো “data loss এড়াও” — লেখা অদৃশ্য হয়ে যাওয়ার চেয়ে লেআউট একটু খারাপ দেখানো ভালো। flex item-এর min-width: auto-ও (পর্ব ২৫-এ দেখেছেন) একই কারণে। এই ডিফল্টের জন্য প্রথমবার অবাক হতে হয়, কিন্তু এটা অজান্তে তথ্য হারানো থেকে বাঁচায়।

মূল উপলব্ধি: CSS-এর অনেক “অদ্ভুত” আচরণ আসলে নিরাপত্তার জাল। ডিফল্ট কেন এমন, সেটা বুঝলে কখন তা বদলাতে হবে (minmax(0, 1fr)) আর কখন রেখে দিতে হবে — সেই সিদ্ধান্ত আপনি নিজেই নিতে পারবেন।

প্র ০৪Grid দিয়েই তো এক সারিতে জিনিস সাজানো যায় — তাহলে Flexbox কি এখন শুধু পুরোনো অভ্যাস?

Grid দিয়ে navbar বানানো অবশ্যই যায় — grid-auto-flow: column দিলেই সব লিংক এক সারিতে। কিন্তু “যায়” আর “মানানসই” আলাদা কথা। দুটির মৌলিক পার্থক্য দিকের সংখ্যায় নয়, কে মাপ ঠিক করে তাতে।

  • Flexbox (content-out): প্রতিটি item-এর নিজের মাপ আগে, তারপর বাড়তি বা কম জায়গা flex-grow/flex-shrink দিয়ে ভাগ। লাইন ভাঙলে (wrap) প্রতিটি লাইন স্বাধীন। ফলে ট্যাগের সারি — “শাড়ি”, “পাঞ্জাবি”, “বাচ্চাদের জামা” — যার যতটুকু লাগে, ততটুকুই নেয়, যতগুলো ধরে এক লাইনে।
  • Grid (layout-in): আগে track-এর মাপ ঠিক হয়, item তার মধ্যে বসে। এক সারির কলাম অন্য সারির কলামের সাথে বাঁধা। ট্যাগের সারি Grid-এ বানালে হয় সব ট্যাগ সমান চওড়া হবে, নয়তো প্রতিটির জন্য আলাদা track ভাবতে হবে।

একটি সহজ পরীক্ষা: শেষ লাইনে একটি জিনিস একা পড়ে গেলে আপনি কী চান? যদি চান সেটি ওপরের কলামের সাথে মিলে থাকুক — Grid. যদি চান সে নিজের মাপে থাকুক বা পুরো লাইন জুড়ে বাড়ুক — Flexbox.

পারফরম্যান্স নিয়েও একটা ভুল ধারণা আছে যে Grid “ভারী”। সাধারণ পাতায় দুটির কোনোটিই চোখে পড়ার মতো ধীর নয়; অনেক গভীর nesting বা হাজার হাজার item-এ তবেই পার্থক্য মাপার মতো হয়, আর তখনও আসল কারণ সাধারণত অন্য কিছু। তাই সিদ্ধান্ত নিন নকশার প্রয়োজন দেখে, গতির গুজব দেখে নয়।

ইতিহাসও একই কথা বলে: Grid আসার পরের বছরগুলোতে Flexbox-এর ব্যবহার কমেনি — বড় বড় সাইটের কোডে দেখা যায় দুটি পাশাপাশি, পাতার কাঠামো Grid আর ছোট উপাদানের ভেতরে Flexbox. CSS Working Group-ও দুটোকে প্রতিদ্বন্দ্বী নয়, পরিপূরক হিসেবে নকশা করেছে — সেজন্যই gap আর alignment-এর property দুটোতে এক।

মূল উপলব্ধি: টুলবক্সে হাতুড়ি আর স্ক্রু-ড্রাইভার দুটোই থাকে। প্রশ্নটা “কোনটা নতুন?” নয়, “এই নকশায় মাপ ঠিক করবে কে — জিনিস, না ছক?”

প্র ০৫Bootstrap-এর মতো framework-এর ১২ কলামের grid system কেন এত জনপ্রিয় হয়েছিল? CSS Grid আসার পর সেটা কি অপ্রয়োজনীয়?

১২ সংখ্যাটা কোনো দুর্ঘটনা নয়। ১২-কে ২, ৩, ৪ আর ৬ দিয়ে সমান ভাগ করা যায় — তাই একই ছকে দুই কলাম (৬ + ৬), তিন কলাম (৪ + ৪ + ৪), চার কলাম (৩ × ৪) বা সাইডবার + মূল অংশ (৩ + ৯) সবই সম্ভব। ছাপা পত্রিকার নকশাকাররা বহু আগে থেকেই এমন কলাম-ছক ব্যবহার করতেন; ওয়েবে ২০০৮ সালের দিকে 960 Grid System সেটা জনপ্রিয় করে, পরে Bootstrap তাকে বিশ্বজুড়ে ছড়িয়ে দেয়।

কিন্তু তখনকার CSS-এ সত্যিকারের ছক ছিল না, তাই framework-গুলো ছক বানাত HTML দিয়ে: প্রতিটি সারির জন্য একটি row div, প্রতিটি কলামের জন্য col-md-4 জাতীয় class. ফলে লেআউটের সিদ্ধান্ত চলে যেত HTML-এ। ফোনে কলাম বদলাতে HTML-এ আরও class যোগ করতে হতো, আর সারির wrapper থাকায় এক সারির item অন্য সারিতে সরানো যেত না। Bootstrap পরে float ছেড়ে Flexbox-এ যায়, আর পরের সংস্করণে CSS Grid-ও ঐচ্ছিকভাবে যোগ করে।

CSS Grid-এ ছকটা থাকে CSS-এ: grid-template-columns: repeat(12, 1fr) লিখে item-কে grid-column: span 4 দিলেই সেই পুরোনো ১২ কলাম। কিন্তু অনেক সময় ১২ কলামের দরকারই পড়ে না — 250px 1fr বা পর্ব ২৮-এর auto-fit সরাসরি নকশাটা বলে দেয়, কোনো সারির wrapper ছাড়া। HTML থাকে পরিষ্কার, আর লেআউট বদলাতে শুধু CSS ছুঁতে হয় — separation of concerns-এর আদর্শ উদাহরণ।

তাহলে framework কি অপ্রয়োজনীয়? পুরোপুরি নয়। বড় দলে সবাই একই নিয়ম মানলে কাজ দ্রুত হয়, আর Tailwind-এর মতো utility class framework এখন সরাসরি CSS Grid-এর ওপরই class দেয় (যেমন grid-cols-4). অর্থাৎ framework-ও এখন ভেতরে ভেতরে আসল Grid ব্যবহার করে। এ নিয়ে বিস্তারিত পর্ব ৫১-এ।

মূল উপলব্ধি: framework অনেক সময় ভাষার একটি ঘাটতি পূরণ করতে জন্মায়। ভাষা নিজে সেই ক্ষমতা পেলে framework-এর ভূমিকা বদলে যায় — তখন বুঝতে হয় framework আসলে কোন সমস্যার সমাধান করত, আর সেই সমস্যা এখনো আছে কি না।

অনুশীলন

বেশিরভাগ কাজে কাগজ-কলম আর DevTools-ই যথেষ্ট — হিসাব করা আর চোখে মিলিয়ে দেখাই আসল দক্ষতা।

  1. fr-এর হিসাব: একটি container-এর ভেতরের চওড়া 900px. CSS: grid-template-columns: 100px 1fr 3fr; gap: 20px; — তিনটি কলামের চওড়া কত হবে? container 500px হলে?

    900px: নির্দিষ্ট কলাম 100px আর দুটি gap 40px বাদ দিলে free space = 900 − 100 − 40 = 760px. মোট ভাগ ১ + ৩ = ৪, তাই 1fr = 190px. কলাম: 100px, 190px, 570px.

    500px: free space = 500 − 140 = 360px, 1fr = 90px. কলাম: 100px, 90px, 270px. প্রথম কলাম বদলায়নি — নির্দিষ্ট মাপ নির্দিষ্টই থাকে, শুধু fr-গুলো ছোট-বড় হয়। চাইলে অংশ ৩-এর JavaScript এডিটরে এই মানগুলো বসিয়ে যাচাই করুন।

  2. লাইন নম্বরের ধাঁধা: একটি grid-এ ৫টি কলাম আর ৩টি সারি (দুটোই template-এ লেখা)। (ক) খাড়া আর আড়াআড়ি লাইন কয়টি? (খ) grid-column: 2 / -1 কয়টি কলাম জুড়বে? (গ) grid-column: -3 / -1 কোন কোন কলাম? (ঘ) grid-row: 2 / span 2 কোন লাইনে শেষ হবে?

    (ক) খাড়া ৬টি (১–৬), আড়াআড়ি ৪টি (১–৪)।

    (খ) −১ মানে শেষ খাড়া লাইন, অর্থাৎ ৬. লাইন ২ থেকে ৬ = ৪টি কলাম (দ্বিতীয় থেকে পঞ্চম)।

    (গ) −৩ হলো লাইন ৪, −১ হলো লাইন ৬ — তাই শেষ দুটি কলাম (চতুর্থ আর পঞ্চম)। কলাম যতই বাড়ুক-কমুক, এটা সবসময় শেষ দুটি — ঋণাত্মক নম্বরের এটাই সুবিধা।

    (ঘ) লাইন ২ থেকে দুই ঘর — শেষ হবে লাইন ৪-এ, অর্থাৎ দ্বিতীয় আর তৃতীয় সারি জুড়ে।

  3. মাসের ক্যালেন্ডার: সাত কলামের একটি ক্যালেন্ডার বানান — ওপরে রবি থেকে শনি, নিচে তারিখ। মাসটা শুরু হয়েছে বুধবারে। কোনো ফাঁকা div না বসিয়ে ১ তারিখকে বুধবারের কলামে আনবেন কীভাবে?

    শুধু প্রথম তারিখকে বলুন কোন কলামে শুরু করবে: grid-column-start: 4 (রবি ১, সোম ২, মঙ্গল ৩, বুধ ৪)। পরের তারিখগুলো auto-placement-এ নিজেরাই পাশে পাশে বসবে, আর সারি শেষ হলে পরের সারিতে যাবে। নিচে চালিয়ে দেখুন; 4-কে 6 করলে মাস শুক্রবারে শুরু হবে।

    .cal {
      display: grid;
      grid-template-columns: repeat(7, 1fr);
      gap: 4px;
      font: 15px system-ui, sans-serif;
      text-align: center;
    }
    .cal > * { padding: 8px 2px; background: #eef2ff; border-radius: 4px; }
    .cal b { background: #c7d2fe; }
    .cal .first { grid-column-start: 4; }   /* মাস শুরু বুধবারে */

    ১ তারিখ বুধবারের নিচে, তার আগের তিনটি ঘর ফাঁকা, আর ৪ তারিখ শনিবারে পৌঁছে ৫ তারিখ নতুন সারিতে রবিবারে গেছে — কোনো ফাঁকা HTML ছাড়াই। আসল ক্যালেন্ডারে অর্থ বোঝাতে <table> বা উপযুক্ত ARIA নিয়েও ভাবতে হবে (পর্ব ৭ আর ১২); এখানে শুধু লেআউটের কৌশলটি দেখানো হলো।

  4. বাস্তব সাইটে grid খোঁজা: যেকোনো বড় খবরের সাইট বা অনলাইন দোকানের হোমপেজ খুলে DevTools-এর Elements প্যানেলে grid ব্যাজ খুঁজুন। একটি grid-এর overlay চালু করে লাইন নম্বর আর track-এর মাপ দেখুন। কলামগুলো কি fr-এ, px-এ, নাকি কোনো minmax()-এ লেখা? implicit সারি আছে কি?

    প্রায় সব আধুনিক সাইটে অন্তত কয়েকটি grid পাবেন — সাধারণত পণ্য বা খবরের কার্ডের তালিকায় আর পাতার মূল কাঠামোয়। Styles প্যানেলে grid-template-columns-এ লেখা মান দেখবেন (যেমন repeat(auto-fill, minmax(220px, 1fr))), আর overlay-তে দেখবেন ব্রাউজার শেষ পর্যন্ত কত px হিসাব করেছে। কার্ডের সংখ্যা ঠিক করা না থাকলে সারিগুলো প্রায়ই implicit — template-এ শুধু কলাম লেখা, সারি আসে grid-auto-rows বা auto থেকে। খেয়াল করুন, ঋণাত্মক লাইন নম্বর (−১) তখন শুধু explicit অংশের শেষে বসে। ব্রাউজারের জানালা ছোট-বড় করে দেখুন কোন track বদলায় আর কোনটা স্থির থাকে।

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

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

ক্রমgrid-template-columns: 200px 1fr 2fr-এ ব্রাউজার কলামের মাপ যে ক্রমে হিসাব করে, সেভাবে সাজান (▲▼ চেপে সরান)

  1. container-এর ভেতরের চওড়া নেওয়া
  2. নির্দিষ্ট মাপের কলাম (200px) বাদ দেওয়া
  3. সব gap বাদ দিয়ে free space বের করা
  4. free space-কে মোট fr (১ + ২ = ৩) দিয়ে ভাগ করে এক ভাগের মাপ বের করা
  5. প্রতিটি fr কলামকে তার ভাগের সংখ্যা অনুযায়ী মাপ দেওয়া

600px চওড়া একটি grid container-এ grid-template-columns: 1fr 2fr; gap: 30px; লেখা। দ্বিতীয় কলামের চওড়া কত?

  • 400px
  • 380px
  • 190px
  • 285px

৩টি কলামের একটি grid-এ grid-column: 1 / -1 দেওয়া item কতটা জায়গা নেবে?

  • শুধু প্রথম কলাম
  • প্রথম দুটি কলাম
  • তিনটি কলাম জুড়ে, পুরো চওড়া
  • কিছুই না — ঋণাত্মক মান অবৈধ

একটি grid-এ grid-template-rows: 100px 100px লেখা, কিন্তু item এত বেশি যে আরও দুটি সারি দরকার। নতুন সারিগুলোর উচ্চতা কোথা থেকে আসবে?

  • শেষ explicit সারির মাপ (100px) থেকে
  • বাড়তি item দেখাবেই না
  • grid-template-columns থেকে
  • grid-auto-rows থেকে; না দিলে auto (ভেতরের জিনিসের মাপে)

container-এর উচ্চতা ছকের চেয়ে অনেক বেশি। পুরো ছকটাকে (সব সারি একসাথে) container-এর নিচের দিকে নামাতে কোনটি লিখবেন?

  • align-content: end
  • align-items: end
  • justify-items: end
  • align-self: end প্রতিটি item-এ

একটি ধাপে ধাপে রান্নার নির্দেশনার তালিকায় grid-auto-flow: dense দেওয়া হলো, ফলে কয়েকটি ধাপ চোখে আগে-পরে চলে গেল। মূল সমস্যা কোনটি?

  • পাতা অনেক ধীরে লোড হবে
  • চোখের ক্রম আর screen reader বা কীবোর্ডের ক্রম আলাদা হয়ে যাবে
  • dense শুধু একটি ব্রাউজারে চলে
  • HTML-এর ক্রম স্থায়ীভাবে বদলে যাবে

একটি পণ্যের কার্ডে ছবির ওপর “নতুন” ব্যাজ বসাতে হবে, ব্যাজ থাকবে ওপর-ডান কোণে, আর লম্বা নাম এলে কার্ড নিজে বড় হবে। কোন পদ্ধতি সবচেয়ে উপযুক্ত?

  • ব্যাজে float: right
  • কার্ডে নির্দিষ্ট height দিয়ে ব্যাজে position: absolute
  • কার্ডকে grid বানিয়ে ছবি আর ব্যাজকে একই ঘরে (grid-row: 1; grid-column: 1) বসানো, ব্যাজে justify-self: end; align-self: start
  • ছবি আর ব্যাজ একটি <table>-এর দুই ঘরে

শব্দকোষ

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

মনে রাখুন

  1. Grid দুই দিকের লেআউট: আগে ছক (display: grid + grid-template-columns/rows), তারপর সরাসরি সন্তানরা ঘরে বসে। Flexbox content-out, Grid layout-in.
  2. fr = নির্দিষ্ট track আর gap বাদ দেওয়ার পরের জায়গার ভাগ; শতাংশের মতো বেরিয়ে যায় না। repeat(4, 1fr) চারটি সমান কলাম; সমান রাখতে কঠোর হলে minmax(0, 1fr).
  3. n track = n + 1 লাইন। grid-column: 1 / 3, 2 / span 2, পুরো চওড়া 1 / -1 — ঋণাত্মক নম্বর গোনে শুধু explicit ছকের শেষ থেকে।
  4. বাড়তি item-এর জন্য implicit সারি/কলাম তৈরি হয় — মাপ দেয় grid-auto-rows/columns, দিক দেয় grid-auto-flow. dense ফাঁক ভরায়, কিন্তু চোখের ক্রম আর কীবোর্ডের ক্রম আলাদা করে দেয়।
  5. items/self ঘরের ভেতরে সরায়, content পুরো ছক সরায়; justify আড়াআড়ি, align খাড়া। একই ঘরে একাধিক item-এ overlap, z-index লাগে position ছাড়াই; ভুল ধরতে DevTools-এর grid overlay.

পরের পর্বে: আজ লাইন নম্বর দিয়ে ছক সাজালেন। এবার ছকের ঘরগুলোকে নাম দেবেন — “head”, “side”, “main” — আর মিডিয়া কোয়েরি ছাড়াই কলাম নিজে থেকে কমবে-বাড়বে auto-fit আর minmax() দিয়ে; সাথে ভেতরের grid-কে বাইরের ছক মানানোর কৌশল subgrid.

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

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