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

তালিকা আর টেবিল — ঠিক জায়গায় ঠিক কাঠামো

Lists & Tables — ul, ol, dl, Navigation Menus, Accessible Data Tables, colspan & rowspan

Taught in Bangla, this lesson explains when to use ul, ol and dl, ordered list attributes, and building navigation menus from nested lists. It then covers data tables only for tabular data, with caption, thead, tbody, tfoot, th and scope for accessibility, colspan and rowspan slot counting, colgroup, headers and id for complex tables, and making wide tables scroll on phones.

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

  • কোন তথ্যের জন্য কোন তালিকা — ul, ol, dl — আর ol-এর type, start, reversed, value
  • নেস্টেড তালিকা দিয়ে সঠিক নেভিগেশন মেনুর কাঠামো, আর screen reader সেটি কীভাবে শোনায়
  • টেবিল কখন ব্যবহার করবেন, কখন নয় — আর টেবিল-লেআউটের ইতিহাস থেকে শিক্ষা
  • caption, thead, tbody, tfoot, th, scope, colspan, rowspan, colgroup দিয়ে পরিষ্কার ও অ্যাক্সেসিবল টেবিল
  • জটিল টেবিলে headers/id, ফোনে চওড়া টেবিল সামলানো, আর AI-এর বানানো টেবিল যাচাই

১ · দেখতে এক, অর্থে আলাদা — কাঠামো কেন জরুরি

তিনটি কাগজের কথা ভাবুন। প্রথমটি মায়ের লেখা বাজারের ফর্দ — চাল, ডাল, পেঁয়াজ, ডিম। কোনটি আগে কিনবেন তাতে কিছু যায় আসে না। দ্বিতীয়টি খিচুড়ির রেসিপি — আগে চাল-ডাল ধোয়া, তারপর পেঁয়াজ ভাজা, তারপর পানি। এখানে ক্রম উল্টে দিলে খাবারটাই নষ্ট। তৃতীয়টি স্কুলের নোটিশ বোর্ডে টাঙানো ফলাফল — সারিতে শিক্ষার্থীর নাম, কলামে বিষয়, আর প্রতিটি ঘরে নম্বর। এখানে একটি সংখ্যার মানে বুঝতে হলে তার সারি আর কলাম দুটোই জানতে হয়।

তিনটিই “লেখা”, কিন্তু তিনটির কাঠামো আলাদা। HTML-এ এই তিন কাঠামোর জন্য আলাদা element আছে — unordered list (<ul>), ordered list (<ol>) আর table (<table>). পর্ব ০৪-এ দেখেছেন, HTML চেহারা নয়, অর্থ বলে। তালিকা আর টেবিল সেই নীতির সবচেয়ে স্পষ্ট উদাহরণ।

বাড়ি বানানোর কথা ভাবুন। দেয়াল, বিম, কলাম — এগুলো কাঠামো। রং, টাইলস, পর্দা — এগুলো সাজ। রং বদলালে বাড়ি দাঁড়িয়ে থাকে, কিন্তু বিম সরালে ছাদ ভেঙে পড়ে। HTML হলো কাঠামো, CSS হলো রং। বুলেট চিহ্ন বা টেবিলের দাগ দেখতে কেমন হবে, সেটা পরে CSS ঠিক করবে (পর্ব ১৬ থেকে)। কিন্তু “এটা একটা তালিকা”, “এই সংখ্যাটা গণিতের কলামের” — এই সত্যগুলো HTML-কেই বলতে হবে।

কে এই কাঠামো পড়ে? অনেকেই। চোখে দেখতে পান না এমন মানুষ screen reader ব্যবহার করেন — সফটওয়্যারটি পাতার লেখা জোরে পড়ে শোনায়। আপনি <ul> লিখলে screen reader বলে “তালিকা, ৪টি আইটেম” — শ্রোতা আগেই জানেন কত বড় তালিকা আসছে। কিন্তু একই চেহারা যদি <br> আর হাতে টাইপ করা “•” দিয়ে বানান, তাহলে শুধু এলোমেলো কয়েকটি লাইন শোনা যায়। সার্চ ইঞ্জিন, ব্রাউজারের “Reader mode”, অনুবাদ টুল, এমনকি AI-এর ওয়েব-পড়া টুলও এই কাঠামো থেকেই বোঝে কোন তথ্য কোথায়।

মূল ধারণা

ব্রাউজার আপনার HTML থেকে দুটি জিনিস বানায়: পর্দার ছবি, আর একটি accessibility tree — প্রতিটি অংশের “ভূমিকা” (role) আর নামের একটি গাছ। <ul> সেখানে হয় list, <li> হয় listitem, <th> হয় columnheader বা rowheader. CSS দিয়ে একটি div-কে হুবহু তালিকার মতো দেখানো যায়, কিন্তু accessibility tree-তে সেটি তালিকা হয় না। তাই ঠিক element বেছে নেওয়াটাই আসল কাজ।

২ · ul, ol আর li — ক্রম কি অর্থের অংশ?

প্রশ্ন একটাই: আইটেমগুলোর ক্রম বদলে দিলে কি অর্থ বদলায়? বদলালে <ol> (ordered — ক্রমযুক্ত), না বদলালে <ul> (unordered — ক্রমহীন)। দুই ক্ষেত্রেই ভেতরের প্রতিটি আইটেম একটি list item, অর্থাৎ <li>.

তথ্যক্রম বদলালে?ঠিক element
বাজারের ফর্দ, একজনের দক্ষতার তালিকাকিছু বদলায় না<ul>
bKash-এ টাকা পাঠানোর ধাপ, রেসিপিকাজটাই ভুল হয়<ol>
মেধাতালিকা, শীর্ষ ১০টি বইর‍্যাংক বদলে যায়<ol>
সাইটের মেনুর লিংকগুলোসাধারণত না<ul> (<nav>-এর ভেতরে)

একটি কঠিন নিয়ম মনে রাখুন: <ul> আর <ol>-এর সরাসরি সন্তান শুধু <li> হতে পারে (ব্যতিক্রম শুধু <script> আর <template>-এর মতো স্ক্রিপ্ট-সহায়ক element). তালিকার ভেতরে সরাসরি <p>, <div> বা শিরোনাম রাখা ভুল। তবে <li>-এর ভেতরে প্রায় সবকিছুই রাখা যায় — অনুচ্ছেদ, ছবি, লিংক, এমনকি আরেকটি তালিকা।

ol-এর চারটি কাজের attribute

নম্বর ব্রাউজার নিজেই বসায় — আপনি হাতে “১.” লিখবেন না। মাঝখানে একটি আইটেম যোগ করলে নম্বরগুলো নিজে থেকে ঠিক হয়ে যায়। নম্বরের ধরন আর শুরুর জায়গা বদলাতে আছে:

  • type — চিহ্নের ধরন: 1 (ডিফল্ট), a, A, i, I.
  • start — কোন সংখ্যা থেকে গোনা শুরু। অক্ষর বা রোমান চিহ্নেও মানটি সংখ্যায় লিখতে হয়: type="a" start="4" মানে শুরু “d” থেকে।
  • reversed — উল্টো গোনা (৩, ২, ১)। এটি একটি boolean attribute — শুধু নামটা লিখলেই চালু, কোনো মান লাগে না।
  • value — এটি <li>-এর attribute: ওই আইটেম থেকে নতুন নম্বর, এবং তার পরেরগুলো সেখান থেকে গোনা চলে।
<h3>পরীক্ষার আগের রাতের প্রস্তুতি</h3>
<ol>
  <li>প্রবেশপত্র ব্যাগে রাখুন</li>
  <li>কলম, পেনসিল, স্কেল গুছিয়ে নিন</li>
  <li>সময়মতো ঘুমিয়ে পড়ুন</li>
</ol>

<h3>শীর্ষ তিন — শেষ থেকে ঘোষণা</h3>
<ol reversed>
  <li>তানিয়া</li>
  <li>রাকিব</li>
  <li>সুমাইয়া</li>
</ol>

<h3>নীতিমালার উপধারা</h3>
<ol type="a" start="4">
  <li>চার নম্বর থেকে শুরু</li>
  <li value="10">এখান থেকে নতুন নম্বর</li>
  <li>এরপর গোনা চলতে থাকে</li>
</ol>

প্রথম তালিকায় 1, 2, 3. দ্বিতীয়টিতে reversed থাকায় 3, 2, 1 — শেষ থেকে ঘোষণার মতো। তৃতীয়টিতে চিহ্ন d, তারপর value="10"-এর কারণে লাফ দিয়ে j, আর শেষটি k. চেষ্টা করুন: দ্বিতীয় তালিকার মাঝে একটি নতুন <li> যোগ করুন — নম্বরগুলো নিজে নিজে ঠিক হয় কি না দেখুন। তারপর প্রথম <ol>-কে লিখুন <ol style="list-style-type: bengali"> — নম্বরগুলো বাংলা অঙ্কে আসবে (এটি CSS-এর আগে থেকে তৈরি একটি গণনার ধরন; CSS শিখবেন পর্ব ১৬ থেকে)।

একটু ইতিহাস: HTML 4-এর সময় type attribute-কে “পুরোনো, CSS ব্যবহার করুন” বলে বাদ দেওয়ার পথে রাখা হয়েছিল। HTML5 সেটিকে আবার পুরো বৈধ করে দেয়। কারণটা চমৎকার: কিছু লেখায় নম্বরের ধরনটাই অর্থের অংশ। আইনের বইয়ে “ধারা ৩-এর (খ)” বললে মানুষ ওই অক্ষর ধরেই খোঁজে — CSS বন্ধ থাকলেও সেটা বজায় থাকা দরকার। তবে <ul type="circle">-এর মতো বুলেটের ধরন এখন অচল; বুলেটের চেহারা CSS-এর কাজ।

৩ · তালিকার ভেতরে তালিকা — নেভিগেশন মেনুর কঙ্কাল

বইয়ের সূচিপত্রে অধ্যায়ের নিচে উপ-অধ্যায় থাকে। ওয়েবে একে বলে nested list — একটি তালিকার আইটেমের ভেতরে আরেকটি তালিকা। নিয়মটি এক লাইনের: ভেতরের তালিকাটি থাকবে মূল আইটেমের <li>-এর ভেতরে, তার </li> বন্ধ হওয়ার আগে।

প্রায় প্রতিটি ওয়েবসাইটের ওপরের মেনু আসলে এই জিনিস — লিংকের একটি তালিকা। দোকানের সাইনবোর্ডের পাশে যেমন “কোন তলায় কী” লেখা একটি বোর্ড থাকে, ওয়েবসাইটের মেনুও তাই। এটি HTML-এ লেখা হয় <nav> element দিয়ে মোড়ানো একটি <ul> হিসেবে। <nav> জানায় “এটা সাইটের প্রধান চলাচলের পথ” — screen reader একে একটি landmark হিসেবে চেনে, আর শ্রোতা একটি শর্টকাট চেপে সরাসরি মেনুতে লাফ দিতে পারেন। (<nav> আর অন্য semantic অংশের পুরো গল্প পর্ব ১০-এ।)

<nav aria-label="প্রধান মেনু">
  <ul>
    <li><a href="#home">হোম</a></li>
    <li><a href="#courses">কোর্স</a>
      <ul>
        <li><a href="#html">HTML ও CSS</a></li>
        <li><a href="#js">JavaScript</a></li>
      </ul>
    </li>
    <li><a href="#blog">ব্লগ</a></li>
    <li><a href="#contact" aria-current="page">যোগাযোগ</a></li>
  </ul>
</nav>

প্রিভিউতে চারটি বুলেট দেখবেন; “কোর্স”-এর নিচে একটু ভেতরে সরে আরও দুটি, আর সেগুলোর বুলেট আলাদা (সাধারণত ফাঁপা বৃত্ত) — ব্রাউজার নিজেই স্তর বুঝে চিহ্ন বদলায়। এখনো এটি দেখতে “মেনু”-র মতো নয়, পাশাপাশি নেই — সেটা CSS-এর কাজ (পর্ব ২৬-এ Flexbox দিয়ে navbar বানাব)। চেষ্টা করুন: ভেতরের <ul>…</ul> অংশটি কেটে “কোর্স”-এর </li>-এর পরে বসান। দেখতে প্রায় একই থাকবে, কিন্তু এখন সেটি ভুল HTML — উপ-মেনুটি আর “কোর্স”-এর অংশ নয়। চোখে না পড়া এই ভুলটিই সবচেয়ে বেশি হয়।

এবার শুনে দেখা যাক, কাঠামো বদলালে একজন screen reader ব্যবহারকারী কী শোনেন। “পরে” চাপুন:

ধাপ ১শুধু div আর লিংক
<div class="menu">
  <a href="#home">হোম</a>
  <a href="#courses">কোর্স</a>
  <a href="#blog">ব্লগ</a>
  <a href="#contact">যোগাযোগ</a>
</div>
ধাপ ২ul আর li যোগ হলো
<ul>
  <li><a href="#home">হোম</a></li>
  <li><a href="#courses">কোর্স</a></li>
  <li><a href="#blog">ব্লগ</a></li>
  <li><a href="#contact">যোগাযোগ</a></li>
</ul>
ধাপ ৩“কোর্স”-এর ভেতরে উপ-তালিকা
<ul>
  <li><a href="#home">হোম</a></li>
  <li><a href="#courses">কোর্স</a>
    <ul>
      <li><a href="#html">HTML ও CSS</a></li>
      <li><a href="#js">JavaScript</a></li>
    </ul>
  </li>
  … ব্লগ, যোগাযোগ …
</ul>
ধাপ ৪nav দিয়ে মোড়ানো হলো
<nav aria-label="প্রধান মেনু">
  <ul>
    … আগের মতোই …
  </ul>
</nav>
ধাপ ৫এখন কোন পাতায় আছি
<li><a href="#contact" aria-current="page">যোগাযোগ</a></li>
  1. শুধু div. দেখতে মেনুর মতো করা যায়, কিন্তু screen reader শুধু একটির পর একটি লিংক পড়ে যায়। কতগুলো লিংক, কোথায় মেনু শেষ — শ্রোতার জানার উপায় নেই। এটাকেই বলে “div-soup” — অর্থহীন div-এর স্যুপ।
  2. ul আর li. এখন accessibility tree-তে একটি list আছে। ঢোকার সময়ই শ্রোতা শোনেন “তালিকা, ৪টি আইটেম” — ঠিক যেন লিফটে ঢুকে দেখলেন বিল্ডিং চার তলার। শেষে “তালিকা শেষ” শুনে বোঝেন মেনু পেরিয়ে এসেছেন।
  3. Nested তালিকা. “কোর্স”-এর ভেতরে আরেকটি তালিকা — screen reader জানায় এটি “স্তর ২”। কোন লিংক কোন বিভাগের অধীনে, এই সম্পর্ক কেবল তখনই বোঝা যায় যখন উপ-তালিকা ঠিক ওই li-এর ভেতরে থাকে।
  4. nav দিয়ে মোড়ানো. এখন এটি একটি landmark. aria-label নাম দিয়েছে “প্রধান মেনু” — পাতায় দুটি nav থাকলে (ওপরে আর পাদদেশে) নাম দিয়ে আলাদা করা যায়। শ্রোতা landmark-এর তালিকা খুলে সরাসরি এখানে আসতে পারেন।
  5. বর্তমান পাতা. aria-current="page" বলে “আপনি এখন এই পাতায়”। চোখে দেখা মানুষ রং বা দাগ দেখে বোঝেন; শ্রোতা শোনেন “বর্তমান পৃষ্ঠা”। একই attribute CSS-এও ধরা যায়, তাই আলাদা class লাগে না। (শব্দগুলো screen reader ভেদে একটু আলাদা হয় — NVDA, JAWS, VoiceOver বা Android-এর TalkBack নিজের ভাষায় বলে — কিন্তু তথ্যটা একই।)

বুলেট সরালে কী হয়? মেনুতে বুলেট চাই না, তাই CSS-এ list-style: none লেখা হয়। কিছু ব্রাউজার-screen reader জুটি (বিশেষ করে Safari আর VoiceOver) ইচ্ছাকৃতভাবে এমন “বুলেটহীন” তালিকাকে সব সময় তালিকা হিসেবে ঘোষণা করে না — কারণ ওয়েবে বহু জায়গায় তালিকা শুধু লেআউটের জন্য ব্যবহার হয়। সংখ্যা জানানো যদি সত্যিই জরুরি হয়, <ul role="list"> লিখে তালিকার ভূমিকা স্পষ্ট করে দেওয়া একটি প্রচলিত সমাধান। এটি ARIA-র প্রথম নিয়মের (“আগে নিজস্ব HTML, ARIA শেষ উপায়”) ব্যতিক্রম নয় — এখানে নিজস্ব HTML-ই আছে, শুধু হারানো ভূমিকাটি ফিরিয়ে দেওয়া হচ্ছে। ARIA-র নিয়মগুলো বিস্তারিত পাবেন পর্ব ১২-এ।

একটি প্রশ্ন প্রায়ই আসে: HTML-এ তো <menu> নামেও একটি element আছে! আজকের WHATWG নিয়মে <menu> হলো কাজের বোতামের (যেমন একটি টুলবারের “কপি”, “মুছুন”) তালিকার জন্য <ul>-এর একটি অর্থবহ বিকল্প, এবং ব্রাউজার একে <ul>-এর মতোই দেখায়। সাইটের পাতাগুলোর মধ্যে চলাচলের মেনুর জন্য সঠিক জুটি এখনো <nav> + <ul>.

৪ · Description list — নাম আর তার বিবরণ জোড়া

অনলাইন দোকানে একটি মোবাইল ফোনের পাতায় নিচে থাকে “বিবরণ”: র‍্যাম — ৬ GB, ব্যাটারি — ৫০০০ mAh, রং — কালো, নীল। প্রতিটি লাইনে একটি নাম আর তার মান। এটা ক্রমহীন তালিকাও নয়, টেবিলও নয় — এটা জোড়ার তালিকা। HTML-এ এর জন্য আছে description list:

  • <dl> — পুরো তালিকা (description list)
  • <dt> — নাম বা শব্দ (description term)
  • <dd> — তার বিবরণ বা মান (description details)

এক নামের একাধিক মান হতে পারে (রং: কালো, নীল), আবার একাধিক নামের একটি মানও (“মোবাইল”, “সেলফোন” — দুটোরই এক ব্যাখ্যা)। আধুনিক নিয়মে প্রতিটি নাম-মান দলকে একটি <div>-এ মুড়েও রাখা যায় — CSS দিয়ে সাজাতে এটা কাজে লাগে। শব্দকোষ, প্রশ্ন-উত্তর (FAQ), পণ্যের বিবরণ, প্রোফাইলের তথ্য (নাম, জেলা, পেশা) — সবই dl-এর কাজ।

<h3>ফোনের বিবরণ (উদাহরণ)</h3>
<dl>
  <dt>র‍্যাম</dt>
  <dd>৬ GB</dd>
  <dt>ব্যাটারি</dt>
  <dd>৫০০০ mAh</dd>
  <dt>রং</dt>
  <dd>কালো</dd>
  <dd>নীল</dd>
</dl>

<h3>সাধারণ প্রশ্ন</h3>
<dl>
  <div>
    <dt>ডেলিভারি কত দিনে হয়?</dt>
    <dd>ঢাকার ভেতরে সাধারণত দুই-তিন দিনে।</dd>
  </div>
</dl>

ব্রাউজারের ডিফল্ট চেহারায় <dt> বাঁ দিকে, আর প্রতিটি <dd> একটু ভেতরে সরে নিচের লাইনে বসে — বুলেট বা নম্বর নেই। “রং”-এর নিচে দুটি মান। চেষ্টা করুন: “ডেলিভারি”-র দলের ঠিক নিচে আরেকটি <div> দল যোগ করুন (“পেমেন্ট কীভাবে?” — “ক্যাশ অন ডেলিভারি বা মোবাইল ব্যাংকিং”)। খেয়াল করুন, <dl>-এর ভেতরে div রাখা যায় শুধু dt-dd দলকে মোড়ানোর জন্য — অন্য কিছু রাখার জন্য নয়।

HTML 4-এ এর নাম ছিল “definition list” — শুধু সংজ্ঞার তালিকা। HTML5 নাম বদলে করে “description list”, যাতে যেকোনো নাম-মান জোড়া (name-value group) এতে লেখা যায়। পুরোনো টিউটোরিয়ালে “definition list” দেখলে বুঝবেন একই জিনিস।

৫ · টেবিল শুধু টেবিলের ডেটার জন্য — লেআউটের পুরোনো গল্প

টেবিল তখনই ঠিক, যখন তথ্যের মধ্যে দুই দিকের সম্পর্ক আছে — প্রতিটি মানের মানে বুঝতে তার সারি আর কলাম দুটোই জানতে হয়। পরীক্ষার ফল (শিক্ষার্থী × বিষয়), ট্রেনের সময়সূচি (ট্রেন × স্টেশন), মোবাইল প্যাকেজের তুলনা (প্যাকেজ × অপারেটর), ক্লাস রুটিন (দিন × পিরিয়ড) — এগুলো আসল টেবিলের ডেটা, একে বলে data table.

কিন্তু একসময় ওয়েবের প্রায় প্রতিটি পাতা টেবিল দিয়ে বানানো হতো — তথ্য দেখাতে নয়, পাতা সাজাতে। বাঁ দিকে মেনু, মাঝে লেখা, ডানে বিজ্ঞাপন — পুরো পাতাটাই একটি বিশাল টেবিল, তার ঘরের ভেতরে আরও টেবিল। একে বলে layout table.

১৯৯০-এর দশকের মাঝামাঝি Netscape ব্রাউজার টেবিল দেখানো শুরু করে, আর ১৯৯৭ সালে HTML 3.2 টেবিলকে আনুষ্ঠানিক মান দেয়। তখন CSS প্রায় ছিলই না — CSS1 (১৯৯৬) লেখার রং-ফন্ট বদলাতে পারত, কিন্তু পাশাপাশি কলাম বানানোর নির্ভরযোগ্য উপায় দিত না, আর ব্রাউজারগুলো CSS-কে ঠিকভাবে মানতও না। ডিজাইনাররা তাই টেবিলকেই গ্রিড বানালেন। ফাঁকা জায়গা তৈরি করতে ঘরে বসানো হতো এক পিক্সেলের অদৃশ্য ছবি — “spacer GIF”. David Siegel-এর ১৯৯৬ সালের বিখ্যাত বই Creating Killer Web Sites এই কৌশলগুলো জনপ্রিয় করে। ২০০০-এর দশকের শুরুতে “টেবিল-মুক্ত” CSS নকশার আন্দোলন শুরু হয় — ২০০২ সালে Wired News-এর CSS-নির্ভর নতুন নকশা আর ২০০৩ সালে Dave Shea-র CSS Zen Garden দেখাল, একই HTML-এ শুধু CSS বদলে সম্পূর্ণ ভিন্ন নকশা সম্ভব। আর ২০১৭ সালে প্রধান সব ব্রাউজারে CSS Grid আসার পর টেবিল-লেআউটের শেষ যুক্তিটাও হারিয়ে যায়।

লেআউটে টেবিল কেন ভুল

শ্রোতা বিভ্রান্ত হন

Screen reader প্রতিটি টেবিলকে ডেটা ধরে নিয়ে “টেবিল, ৩ সারি, ৩ কলাম” বলতে পারে, আর ঘরে ঘরে লেখা পড়ে — লেখার স্বাভাবিক ক্রম ভেঙে যায়।

অ্যাক্সেসিবিলিটি

ফোনে ভাঙে

টেবিলের কলাম পাশাপাশি থাকতেই চায়। ৩৬০ পিক্সেলের ফোনে তিন কলামের পাতা মানে চাপাচাপি বা পাশে স্ক্রল — রেসপন্সিভ করা কঠিন।

রেসপন্সিভ

কোড জট পাকায়

টেবিলের ভেতরে টেবিল, তার ভেতরে আরও — একটি ঘর সরাতে গেলে পুরো পাতা নতুন করে লিখতে হয়। কাঠামো আর নকশা আলাদা থাকে না।

রক্ষণাবেক্ষণ

আজকের উপায়

পাতার কাঠামো semantic element-এ (পর্ব ১০), আর পাশাপাশি সাজানো CSS-এর Flexbox ও Grid দিয়ে (পর্ব ২৫–২৯)।

আধুনিক

একমাত্র বড় ব্যতিক্রম — HTML ইমেইল। অনেক ইমেইল অ্যাপ এখনো আধুনিক CSS পুরোপুরি মানে না (যেমন Windows-এর ডেস্কটপ Outlook বহু বছর ধরে Microsoft Word-এর রেন্ডারিং ইঞ্জিনে ইমেইল দেখায়)। তাই নিউজলেটারের মতো ইমেইলে আজও টেবিল-লেআউট চলে। সেখানেও নিয়ম হলো লেআউট-টেবিলে role="presentation" দেওয়া, যাতে screen reader একে ডেটা-টেবিল না ভাবে। ওয়েবপেজে এই অজুহাত খাটে না।

৬ · টেবিলের অঙ্গপ্রত্যঙ্গ — caption, thead, tbody, tfoot, th আর scope

একটি HTML টেবিল আসলে কয়েকটি স্তরে সাজানো। পরীক্ষার ফলাফলের কাগজটাই ধরুন: ওপরে শিরোনাম (“মডেল টেস্টের ফল”), প্রথম সারিতে কলামের নাম, মাঝখানে শিক্ষার্থীদের সারি, আর নিচে গড় বা মোট। HTML-এ ঠিক এই ভাগগুলোর জন্য আলাদা element:

Elementকাজকাগজের ফলাফলে যা
<table>পুরো টেবিলপুরো কাগজটা
<caption>টেবিলের শিরোনাম; থাকলে <table>-এর একদম প্রথম সন্তান“মডেল টেস্টের ফল — ব্যাচ ক”
<thead>মাথার সারি(গুলো)র দলনাম, রোল, বাংলা, গণিত…
<tbody>মূল ডেটার সারির দল (একাধিকও হতে পারে)প্রত্যেক শিক্ষার্থীর সারি
<tfoot>পায়ের সারি(গুলো)র দল — যোগফল, গড়“গড়” সারি
<tr>একটি সারি (table row)একটি লাইন
<th>শিরোনাম-ঘর (header cell)“গণিত”, “নুসরাত”
<td>ডেটা-ঘর (table data)“৯২”

তিনটি সারির দল — thead, tbody, tfoot — কে বলে row group. এগুলো শুধু অর্থ বাড়ায় না, কাজেও লাগে: লম্বা টেবিল ছাপলে অনেক ব্রাউজার প্রতিটি পাতার মাথায় thead আবার ছাপে, আর স্ক্রলের সময় CSS দিয়ে thead-এর ঘরগুলো ওপরে আটকে রাখা যায়। এখনকার নিয়মে <tfoot> লেখা হয় tbody-র পরে (HTML 4-এ উল্টো, tbody-র আগে লেখার নিয়ম ছিল — পুরোনো কোডে দেখলে অবাক হবেন না)।

<caption> টেবিলের নাম। Screen reader টেবিলে ঢোকার সময় এটাই আগে পড়ে, আর পাতায় অনেক টেবিল থাকলে শ্রোতা নাম দেখে বেছে নিতে পারেন। পুরোনো summary attribute এখন অচল — বাড়তি ব্যাখ্যা দরকার হলে caption-এর ভেতরে বা টেবিলের আগে সাধারণ লেখায় দিন।

th আর scope — প্রতিটি সংখ্যার পরিচয়পত্র

<th> লিখলেই ব্রাউজার লেখাটি মোটা আর মাঝখানে দেখায় — কিন্তু আসল লাভ চোখে পড়ে না। <th> বলে “আমি একটি শিরোনাম, এই কলাম (বা সারি)-এর সব ঘর আমার অধীনে”। scope attribute সেই দিকটা স্পষ্ট করে: scope="col" — নিচের দিকের পুরো কলাম; scope="row" — ডান দিকের পুরো সারি। (দলবদ্ধ শিরোনামের জন্য colgroup আর rowgroup মানও আছে।) সাধারণ টেবিলে ব্রাউজার নিজেও অনুমান করতে পারে, তবে scope লিখে দিলে অনুমানের দরকার পড়ে না।

<style>
  table { border-collapse: collapse; }
  th, td { border: 1px solid #999; padding: 4px 10px; }
</style>
<table>
  <caption>মডেল টেস্টের ফল — ব্যাচ ক (উদাহরণ)</caption>
  <thead>
    <tr>
      <th scope="col">নাম</th>   <th scope="col">রোল</th>
      <th scope="col">বাংলা</th> <th scope="col">গণিত</th>
      <th scope="col">মোট</th>
    </tr>
  </thead>
  <tbody>
    <tr><th scope="row">নুসরাত</th><td>১০১</td><td>৭৮</td><td>৯২</td><td>১৭০</td></tr>
    <tr><th scope="row">আরিফ</th><td>১০২</td><td>৮৫</td><td>৭৪</td><td>১৫৯</td></tr>
  </tbody>
  <tfoot>
    <tr><th scope="row" colspan="2">গড়</th><td>৮১.৫</td><td>৮৩</td><td>১৬৪.৫</td></tr>
  </tfoot>
</table>

ওপরে মাঝখানে caption, তার নিচে মোটা অক্ষরে কলামের নাম, প্রতিটি সারির শুরুতে মোটা অক্ষরে শিক্ষার্থীর নাম, আর শেষে “গড়” সারি — যেটি colspan="2" দিয়ে নাম আর রোল দুই কলাম জুড়ে আছে। ওপরের <style> অংশটি শুধু দাগ দেখানোর জন্য — CSS ছাড়া ব্রাউজার টেবিলে কোনো দাগই দেয় না। চেষ্টা করুন: tbody-তে তৃতীয় একজন শিক্ষার্থীর সারি যোগ করুন — তারপর tfoot-এর গড়গুলোও কি বদলাতে হবে? (হ্যাঁ — HTML হিসাব করে না, ওটা আপনার বা JavaScript-এর কাজ।) আর <style> অংশটা মুছে দেখুন CSS ছাড়া টেবিলটি কেমন দেখায়।

এবার ভাবুন, এই টেবিলটি একজন দৃষ্টিপ্রতিবন্ধী শিক্ষার্থী শুনছেন। Screen reader-এ টেবিলের ভেতরে তীর-চিহ্নের মতো কী দিয়ে ঘর থেকে ঘরে যাওয়া যায়। প্রতিবার কী শোনা যায়, দেখুন:

নামরোলবাংলাগণিতমোট
নুসরাত১০১১৭০
আরিফ১০২৮৫১৫৯
গড়৮১.৫১৬৪.৫
  1. টেবিলে ঢোকা। প্রথমেই caption — শ্রোতা জানলেন এটা কিসের টেবিল, আর কত বড় (৪টি সারি: thead-এর ১টি, tbody-র ২টি, tfoot-এর ১টি)। caption না থাকলে শুধু শোনা যেত “টেবিল” — কোনটা কিসের, পাতায় তিনটি টেবিল থাকলে বোঝা কঠিন।
  2. নুসরাতের বাংলার ঘরে। শুধু “৭৮” নয় — সারির শিরোনাম “নুসরাত” আর কলামের শিরোনাম “বাংলা” দুটোই শোনা গেল। চোখে দেখা মানুষ এক পলকে ওপরে আর বাঁয়ে তাকিয়ে যা বোঝেন, th আর scope শ্রোতাকে ঠিক সেটাই দেয়।
  3. ডানে সরলেন — গণিত। সারি বদলায়নি, তাই screen reader আর “নুসরাত” বলে না; শুধু নতুন কলামের নাম “গণিত” আর মান। অপ্রয়োজনীয় কথা বাদ — শুনতে আরামদায়ক।
  4. নিচে নামলেন — আরিফ। কলাম একই (গণিত), তাই এবার শুধু নতুন সারির শিরোনাম “আরিফ”। শ্রোতা বুঝলেন আরিফ গণিতে ৭৪ পেয়েছে।
  5. আরও নিচে — tfoot. “গড়, ৮৩” — গণিতের গড়। tfoot-এর সারির শুরুতেও th scope="row" আছে বলে “গড়” শব্দটি শিরোনাম হিসেবে কাজ করছে।
  6. যদি সব ঘর td হতো। একই ঘরে শোনা যেত শুধু “সারি ৩, কলাম ৪, ৭৪”। কার নম্বর, কোন বিষয়ের — শ্রোতাকে বারবার ওপরে আর বাঁয়ে গিয়ে মিলিয়ে আসতে হতো। দেখতে টেবিল একদম একই — পার্থক্য পুরোটাই কাঠামোয়। (শব্দ আর ক্রম screen reader ভেদে একটু আলাদা হয়, কিন্তু নীতিটা এক।)

আরও গভীরে: HTML parser টেবিলের ব্যাপারে খুব কড়া। আপনি <table>-এর ভেতরে সরাসরি <tr> লিখলে parser নিজেই একটি <tbody> বসিয়ে দেয় — আপনার ফাইলে না থাকলেও DOM-এ থাকে। তাই CSS-এ table > tr selector কিছুই ধরে না। আর টেবিলের ভেতরে ভুল জায়গায় লেখা বা element রাখলে parser সেটিকে টেবিলের আগে সরিয়ে দেয় (spec-এ একে “foster parenting” বলে)। এরপর ব্রাউজার WHATWG-এর “forming a table” নিয়ম মেনে একটি স্লট-গ্রিড বানায়, আর প্রতিটি ঘরের শিরোনাম খোঁজার আলাদা একটি নিয়ম চালায় — screen reader যা বলে তার ভিত্তি এটাই। নিচের ছোট স্ক্রিপ্টে নিজেই দেখুন:

// ফাইলে tbody লেখা নেই — DOM-এ কী আছে?
const routine = document.querySelector('table');
console.log('first child of table:', routine.firstElementChild.tagName);
console.log('tr directly inside table:', routine.querySelectorAll(':scope > tr').length);
console.log('total rows:', routine.rows.length);

// তৃতীয় সারির প্রথম ঘর "ইংরেজি" — চোখে সে কলাম ২-এ আছে
const english = routine.rows[2].cells[0];
console.log(english.textContent, '-> cellIndex:', english.cellIndex);
console.log('cells in row 3:', routine.rows[2].cells.length);

প্রথম লাইনে আসবে first child of table: TBODY — আপনি না লিখলেও parser বসিয়েছে, তাই সরাসরি table-এর ভেতরে tr সংখ্যা 0. মোট সারি 3. তারপর ইংরেজি -> cellIndex: 0 — DOM-এ সে তার সারির প্রথম ঘর, যদিও পর্দায় সে দ্বিতীয় কলামে, কারণ প্রথম কলামের জায়গাটা ওপরের “রবি”-র rowspan দখল করে আছে। তৃতীয় সারিতে ঘর মাত্র 2টি। চেষ্টা করুন: rows[2]-কে rows[1] করে দেখুন — এবার প্রথম ঘর “রবি”। DOM নিয়ে আরও জানতে JavaScript কোর্সের DOM পর্বটি দেখুন।

৭ · colspan আর rowspan — ঘর জোড়া লাগানোর হিসাব

স্কুলের ক্লাস রুটিনে প্রায়ই দেখবেন, বিজ্ঞানের ব্যবহারিক ক্লাস টানা দুই পিরিয়ড — রুটিনে ঘরটা দুই কলাম চওড়া। আবার কোনো বিষয় পরপর দুই দিন একই পিরিয়ডে — ঘরটা দুই সারি লম্বা। HTML-এ এর জন্য দুটি attribute:

  • colspan="2" — ঘরটি ডান দিকে ২টি কলাম জুড়ে থাকবে।
  • rowspan="2" — ঘরটি নিচের দিকে ২টি সারি জুড়ে থাকবে।

নতুনরা এখানেই সবচেয়ে বেশি ভুল করেন, কারণ কোড পড়ে বোঝা যায় না কোন ঘর কোথায় বসবে। রহস্যটা হলো, ব্রাউজার মনে মনে একটি স্লট-গ্রিড আঁকে — দাবার বোর্ডের মতো খোপ — আর প্রতিটি ঘরকে বাঁ থেকে ডানে প্রথম খালি খোপে বসায়। rowspan দেওয়া ঘর নিচের সারির খোপও আগেই দখল করে রাখে। নিচের স্টেপারে ব্রাউজারের এই হিসাবের খাতা দেখুন:

1<table>2  <tr><th>দিন</th><th>১ম</th><th>২য়</th><th>৩য়</th></tr>3  <tr><th>রবি</th>4    <td colspan="2">বিজ্ঞান</td><td>বাংলা</td></tr>5  <tr><th>সোম</th><td rowspan="2">গণিত</td>6    <td>ইংরেজি</td><td>ICT</td></tr>7  <tr><th>মঙ্গল</th><td>ধর্ম</td><td>খেলা</td></tr>8</table>
স্লট-গ্রিড (কলাম ১ → ৪)
সারি ১
সারি ২
সারি ৩
সারি ৪
  1. মাথার সারি. চারটি th চারটি খোপে বসল — দিন, ১ম, ২য়, ৩য় পিরিয়ড। এখান থেকেই ব্রাউজার ধরে নিল টেবিলে কলাম ৪টি (আসলে সব সারির মধ্যে সবচেয়ে চওড়াটি কলাম সংখ্যা ঠিক করে)।
  2. colspan="2". “রবি” কলাম ১-এ। “বিজ্ঞান” প্রথম খালি খোপ কলাম ২-এ বসে, আর colspan="2"-এর কারণে কলাম ৩-ও দখল করে (“← বিজ্ঞান” মানে বাঁয়ের ঘরটিই এখানে ছড়িয়ে আছে)। তাই “বাংলা” চলে গেল কলাম ৪-এ। কোডে এই সারিতে ঘর মাত্র ৩টি, কিন্তু খোপ ৪টিই ভরা।
  3. rowspan="2". “গণিত” কলাম ২-এ বসে, আর নিচের সারি ৪-এর কলাম ২-ও এখনই দখল করে রাখে (“↑ গণিত”) — সারি ৪-এর কোড পড়ার আগেই! ইংরেজি আর ICT বসল কলাম ৩ ও ৪-এ।
  4. দখল করা খোপ এড়িয়ে যাওয়া. “মঙ্গল” কলাম ১-এ। এরপর “ধর্ম” — ব্রাউজার কলাম ২ দেখে, সেটি গণিতের দখলে, তাই এড়িয়ে কলাম ৩-এ বসায়। “খেলা” কলাম ৪-এ। এই সারিতে মাত্র ৩টি ঘর লিখলেই চলে — চতুর্থটি লিখলে টেবিলের ডানে একটি বাড়তি পঞ্চম কলাম বেরিয়ে আসত।
  5. যাচাইয়ের নিয়ম. প্রতিটি সারিতে: নিজের ঘরগুলোর colspan যোগ করুন (না লিখলে ১), তার সাথে যোগ করুন ওপরের সারি থেকে নেমে আসা rowspan-এর খোপ। যোগফল প্রতিটি সারিতে সমান হতে হবে। না মিললে টেবিল হয় “দাঁত বের করা” — একপাশে বাড়তি ঘর বা ফাঁকা গর্ত। জটিল টেবিল লেখার আগে কাগজে খোপ এঁকে নিন — পেশাদাররাও তাই করেন।

ধাঁধা — ট্রেনের সময়সূচি ঠিক করুন

নিচের টেবিলে একটি ভুল আছে — একটি সারি ডান দিকে “দাঁত বের করে” আছে। প্রিভিউ দেখে খুঁজুন, স্লট-গ্রিডের নিয়মে কারণ বের করুন, তারপর এডিটরেই ঠিক করুন। (সময় আর ট্রেনের নাম কাল্পনিক।)

<style>
  table { border-collapse: collapse; }
  th, td { border: 1px solid #999; padding: 4px 10px; }
</style>
<table>
  <caption>কমলাপুর থেকে ছাড়ার সময় (কাল্পনিক উদাহরণ)</caption>
  <tr>
    <th scope="col">গন্তব্য</th><th scope="col">ট্রেন</th><th scope="col">ছাড়ে</th>
  </tr>
  <tr>
    <th scope="row" rowspan="2">চট্টগ্রাম</th><td>ট্রেন-ক</td><td>সকাল ৭টা</td>
  </tr>
  <tr>
    <th scope="row">চট্টগ্রাম</th><td>ট্রেন-খ</td><td>বিকেল ৩টা</td>
  </tr>
  <tr>
    <th scope="row">সিলেট</th><td colspan="2">আজ কোনো ট্রেন নেই</td>
  </tr>
</table>

প্রিভিউতে তৃতীয় সারিটি (ট্রেন-খ) ডানে একটি বাড়তি ঘর নিয়ে বেরিয়ে আছে, আর “চট্টগ্রাম” দুবার দেখা যাচ্ছে। কারণ: ওপরের “চট্টগ্রাম”-এর rowspan="2" আগেই এই সারির কলাম ১ দখল করেছে, তাই এখানে আবার <th>চট্টগ্রাম</th> লেখায় সারিটি ১ + ১ + ১ + ১ = ৪ খোপ চাইছে, অথচ কলাম ৩টি। সমাধান: ওই সারির <th scope="row">চট্টগ্রাম</th> অংশটি মুছে দিন। সিলেটের সারিতে colspan="2" ঠিকই আছে — সেটিকে 1 করে দেখুন, ডান দিকে একটি গর্ত তৈরি হয়।

৮ · colgroup, col আর জটিল টেবিলে headers

পুরো কলামকে একসাথে ধরা

HTML-এ টেবিল লেখা হয় সারি ধরে ধরে — কলাম বলে আলাদা কোনো ঘর নেই। তাহলে “মোট” কলামটা পুরো সবুজ করতে চাইলে? প্রতিটি ঘরে আলাদা class না বসিয়ে ব্যবহার করুন <colgroup> আর তার ভেতরে <col> — প্রতিটি col একটি কলামের প্রতিনিধি, আর span দিয়ে একসাথে কয়েকটি কলাম ধরা যায়। colgroup বসে caption-এর পরে, thead-এর আগে।

<style>
  table { border-collapse: collapse; }
  th, td { border: 1px solid #999; padding: 4px 10px; }
</style>
<table>
  <caption>সাপ্তাহিক বাজার খরচ, টাকায় (উদাহরণ)</caption>
  <colgroup>
    <col>
    <col span="2" style="background: #fef3c7">
    <col style="background: #dcfce7; width: 7em">
  </colgroup>
  <tr><th scope="col">পণ্য</th><th scope="col">শুক্রবার</th><th scope="col">সোমবার</th><th scope="col">মোট</th></tr>
  <tr><th scope="row">চাল</th><td>৩২০</td><td>০</td><td>৩২০</td></tr>
  <tr><th scope="row">সবজি</th><td>১৫০</td><td>১২০</td><td>২৭০</td></tr>
</table>

শুক্র আর সোমবারের দুই কলাম (একটি col-এ span="2") হালকা হলুদ, “মোট” কলাম হালকা সবুজ আর একটু চওড়া — অথচ কোনো ঘরে হাত দিতে হয়নি। এখন একটি মজার পরীক্ষা: শেষ col-এর style-এ color: red যোগ করুন। লেখার রং বদলাবে না! কারণ ঘরগুলো আসলে col-এর “সন্তান” নয়, তাই উত্তরাধিকারসূত্রে কিছু পায় না; col-এ কেবল চারটি জিনিস কাজ করে — background, border, width আর visibility. (CSS পর্ব ১৬ থেকে; এখানে style attribute শুধু দেখানোর জন্য।)

জটিল টেবিল — যখন scope যথেষ্ট নয়

কিছু টেবিলে শিরোনাম দুই স্তরে থাকে। যেমন একটি পরীক্ষার রুটিন: ওপরে “তত্ত্বীয়” আর “ব্যবহারিক”, প্রতিটির নিচে আবার “তারিখ” আর “সময়”। এখানে একটি ঘরের (“১২ মে”) মানে বুঝতে তিনটি শিরোনাম লাগে — পদার্থবিজ্ঞান, তত্ত্বীয়, তারিখ। এমন ক্ষেত্রে প্রতিটি শিরোনামে একটি id দিন, আর ডেটা-ঘরে headers attribute-এ সেই id-গুলো ফাঁকা দিয়ে লিখুন:

<table>
  <caption>ব্যবহারিকসহ পরীক্ষার রুটিন (উদাহরণ)</caption>
  <thead>
    <tr>
      <th id="sub" rowspan="2">বিষয়</th>
      <th id="theory" colspan="2">তত্ত্বীয়</th>
      <th id="prac" colspan="2">ব্যবহারিক</th>
    </tr>
    <tr>
      <th id="t-date">তারিখ</th><th id="t-time">সময়</th>
      <th id="p-date">তারিখ</th><th id="p-time">সময়</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th id="phy" headers="sub">পদার্থবিজ্ঞান</th>
      <td headers="phy theory t-date">১২ মে</td>
      <td headers="phy theory t-time">সকাল ১০টা</td>
      <td headers="phy prac p-date">২০ মে</td>
      <td headers="phy prac p-time">দুপুর ২টা</td>
    </tr>
  </tbody>
</table>

headers/id হলো হাতে তার জোড়া — প্রতিটি ঘর নিজেই বলে দেয় তার শিরোনাম কে কে। কাজ করে নিশ্চিতভাবে, কিন্তু লেখা আর রক্ষণাবেক্ষণ করা ঝামেলার; একটি কলাম যোগ করলেই অনেক id বদলাতে হয়। তাই পেশাদার পরামর্শ: আগে টেবিলটা সরল করা যায় কি না ভাবুন — একটি জটিল টেবিলের বদলে “তত্ত্বীয় রুটিন” আর “ব্যবহারিক রুটিন” নামে দুটি সরল টেবিল প্রায়ই সবার জন্য, চোখে দেখা পাঠকের জন্যও, বেশি পরিষ্কার। (দুই স্তরের শিরোনামে scope="colgroup" দিয়েও কাজ হয়, তবে তখন টেবিলে মিলিয়ে <colgroup> লিখতে হয়।)

৯ · ফোনের ছোট পর্দায় চওড়া টেবিল

বাংলাদেশে বেশিরভাগ মানুষ ওয়েব দেখেন ফোনে। পরীক্ষার ফল, ভর্তির বিজ্ঞপ্তি, ট্রেনের সময়সূচি — সবই খোলা হয় ছোট পর্দায়। কিন্তু টেবিলের স্বভাবই হলো কলামগুলো পাশাপাশি রাখা; ছয় কলামের একটি তুলনার টেবিল ৩৬০ পিক্সেল চওড়া পর্দায় আঁটে না। তখন ব্রাউজার পুরো পাতাটাই পাশে টেনে চওড়া করে ফেলে — লেখা, মেনু, সব কিছু পাশে স্ক্রল করতে হয়।

সবচেয়ে সহজ ও নির্ভরযোগ্য সমাধান: টেবিলটিকে একটি স্ক্রল কন্টেইনারে মুড়ে দিন — একটি div, যার নিজের ভেতরে পাশে স্ক্রল হয়, কিন্তু বাকি পাতা ঠিক থাকে। এই পাতার টেবিলগুলোও ঠিক এভাবেই বানানো। পুরো CSS কৌশল (overflow) পর্ব ২৩-এ আর রেসপন্সিভ ভাবনা পর্ব ৩০-এ শিখবেন; এখানে শুধু HTML কাঠামোটা দেখুন:

<style>
  table { border-collapse: collapse; }
  th, td { border: 1px solid #999; padding: 4px 10px; white-space: nowrap; }
</style>
<p>ফোনের মাপের একটি বাক্স (৩০০ পিক্সেল):</p>
<div role="region" aria-label="প্যাকেজের তুলনা" tabindex="0"
     style="overflow-x: auto; max-width: 300px; border: 2px dashed #888;">
  <table>
    <caption>ইন্টারনেট প্যাকেজের তুলনা (কাল্পনিক উদাহরণ — আসল দাম নয়)</caption>
    <thead><tr><th scope="col">প্যাকেজ</th><th scope="col">অপারেটর ক</th>
      <th scope="col">অপারেটর খ</th><th scope="col">অপারেটর গ</th></tr></thead>
    <tbody>
      <tr><th scope="row">১০ GB, ৩০ দিন</th><td>৳ ক১</td><td>৳ খ১</td><td>৳ গ১</td></tr>
      <tr><th scope="row">২৫ GB, ৩০ দিন</th><td>৳ ক২</td><td>৳ খ২</td><td>৳ গ২</td></tr>
    </tbody>
  </table>
</div>
<p>এই লেখাটি আর পাশে সরে না।</p>

ড্যাশ দাগের বাক্সটি ফোনের মতো সরু; টেবিলটি তার চেয়ে চওড়া, তাই ডানের কলামগুলো কাটা পড়েছে আর বাক্সের ভেতরেই পাশে স্ক্রল করা যায় (কিছু ডিভাইসে স্ক্রলবার কেবল ছুঁলে বা মাউস রাখলে দেখা যায়), অথচ নিচের লেখা জায়গামতো। দাম লেখা “৳ ক১”-এর মতো চিহ্নে — আসল দাম অপারেটরের সাইট থেকে মিলিয়ে নেবেন, বানানো সংখ্যা নয়। চেষ্টা করুন: style থেকে overflow-x: auto; মুছে দিন — টেবিল বাক্স ভেদ করে বেরিয়ে যাবে। আর কি-বোর্ডের Tab চেপে বাক্সে আসুন, তারপর ডান তীর চাপুন — tabindex="0" থাকায় মাউস ছাড়াও স্ক্রল করা যায়।

wrapper-এর তিনটি attribute-এর প্রতিটির কারণ আছে। tabindex="0" — শুধু কি-বোর্ড ব্যবহারকারী (মাউস নেই) যেন বাক্সে focus এনে তীর চিহ্নে স্ক্রল করতে পারেন। role="region" আর aria-label — focus এলে screen reader যেন বলে “প্যাকেজের তুলনা, region”, শুধু “গ্রুপ” বা কিছুই না। WCAG 2.2-এর Reflow নিয়মে (১.৪.১০) সাধারণ লেখাকে ছোট পর্দায় পাশে স্ক্রল ছাড়াই আঁটাতে হয়, কিন্তু ডেটা-টেবিলের মতো দুই দিকের কাঠামোর জন্য ব্যতিক্রম রাখা আছে — তাই টেবিলের নিজের ভেতরে স্ক্রল গ্রহণযোগ্য, পুরো পাতার স্ক্রল নয়।

অনেকে ফোনে টেবিলকে “কার্ড” বানাতে CSS-এ tr, td-কে display: block করে দেন। দেখতে সুন্দর হয়, কিন্তু কিছু ব্রাউজারে এতে টেবিলের অর্থ (role) হারিয়ে যেতে পারে, আর তখন screen reader-এর কাছে এটা আর টেবিল থাকে না। এ কৌশল ব্যবহার করলে আসল ডিভাইস আর screen reader দিয়ে পরীক্ষা করুন। শুরুর জন্য স্ক্রল কন্টেইনারই নিরাপদ পথ। পর্ব ২৪-এ position: sticky দিয়ে টেবিলের শিরোনাম আটকে রাখার কৌশল দেখবেন — একই কৌশলে প্রথম কলামও আটকে রাখা যায়, তখন পাশে স্ক্রল করলেও নামগুলো চোখের সামনে থাকে।

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

“একটা ফলাফলের টেবিল বানিয়ে দাও” — AI কয়েক সেকেন্ডে কোড দেবে, আর প্রিভিউতে সুন্দরও দেখাবে। সমস্যা হলো, AI শিখেছে ইন্টারনেটের কোটি কোটি পাতা থেকে, যার বড় অংশ পুরোনো বা ভুল অভ্যাসে লেখা। তাই চেহারা ঠিক থাকলেও কাঠামোয় প্রায়ই গলদ থাকে — যা চোখে পড়ে না, কিন্তু screen reader, validator আর ফোনে ধরা পড়ে।

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

AI-এর ভুলকেন সমস্যাঠিক উপায়
div আর CSS grid দিয়ে “টেবিল”accessibility tree-তে কোনো টেবিল নেই, শিরোনাম-সম্পর্ক নেইআসল <table>, <th>
সব ঘর <td>, ওপরের সারি শুধু মোটা করাশিরোনাম চেনা যায় না<thead> + <th scope="col">
caption নেইটেবিলের নাম নেই<caption>
border="1", cellpadding, align, bgcolorHTML-এ অচল, পুরোনো অভ্যাসএগুলোর কাজ CSS-এ
মেনু = <div>/<span>-এ onclickকি-বোর্ডে চলে না, লিংক হিসেবে চেনা যায় না<nav> > <ul> > <li> > <a href>
“•” বা “১.” হাতে লিখে <br>তালিকা নয়, শুধু লেখা<ul> বা <ol>
বানানো দাম বা তথ্য সত্যের মতো দেখানোপাঠক ভুল সিদ্ধান্ত নেনউৎস মিলিয়ে নিন, উদাহরণ হলে স্পষ্ট লিখুন

AI-কে কাজ দেওয়ার সময় শর্তগুলো আগেই লিখে দিন — তাহলে প্রথম উত্তরেই ভালো কাঠামো পাবেন। শেষের লাইনটি খেয়াল করুন: AI-কে নিজের কাজ ব্যাখ্যা করতে বললে তার ভুলও প্রায়ই বেরিয়ে আসে।

তুমি একজন অ্যাক্সেসিবিলিটি-সচেতন ফ্রন্ট-এন্ড ডেভেলপার। আমার কোচিং ব্যাচের ৫ জনের মডেল টেস্টের ফল নিয়ে একটি HTML টেবিল বানাও (নাম, রোল, বাংলা, ইংরেজি, গণিত, মোট)। শর্ত: ১. caption, thead, tbody আর শেষে গড়ের জন্য tfoot থাকবে। ২. কলামের শিরোনামে th scope="col", প্রতিটি সারির নামে th scope="row". ৩. border, cellpadding, align, bgcolor-এর মতো পুরোনো attribute দেবে না; দরকারি স্টাইল আলাদা CSS-এ। ৪. div দিয়ে টেবিল বানাবে না; টেবিলটি role="region", aria-label আর tabindex="0" দেওয়া একটি স্ক্রল কন্টেইনারে রাখবে। ৫. সব নাম ও নম্বর কাল্পনিক, caption-এ "উদাহরণ" লিখবে। শেষে সহজ বাংলায় বলো, screen reader গণিতের একটি ঘরে গেলে কী কী শোনাবে।

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

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

  • <ul> আর <ol>-এর পার্থক্য? — ক্রম অর্থের অংশ হলে ol (ব্রাউজার নম্বর দেয়), না হলে ul (বুলেট)।
  • description list-এ কোন কোন ট্যাগ থাকে? — <dl>-এর ভেতরে নাম <dt> আর বিবরণ <dd>; দলগুলো চাইলে div-এ মোড়ানো যায়।
  • <th> আর <td>-এর পার্থক্য, scope কেন? — th শিরোনাম-ঘর, td ডেটা-ঘর; scope বলে শিরোনামটি কলামের না সারির।
  • colspan আর rowspan কী করে? — একটি ঘরকে পাশাপাশি কয়েকটি কলাম বা ওপর-নিচে কয়েকটি সারি জুড়ে বসায়।
  • লেআউটে টেবিল কেন নয়? আর tbody না লিখলে কী হয়? — অর্থ ভুল হয়, অ্যাক্সেসিবিলিটি আর রেসপন্সিভনেস ভাঙে; tbody না লিখলে HTML parser নিজেই DOM-এ বসিয়ে দেয়।

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

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

প্র ০১টেবিল দিয়ে পাতার লেআউট বানানো এত জনপ্রিয় হয়েছিল কেন — আর সেটা ছাড়তে এত বছর লাগল কেন?

কারণ সেই সময়ে এটাই ছিল একমাত্র কাজ করা উপায়। ১৯৯০-এর দশকের মাঝামাঝি ডিজাইনাররা ছাপা পত্রিকার মতো পাতা চাইতেন — পাশাপাশি কলাম, নির্দিষ্ট জায়গায় ছবি। HTML তখন ছিল মূলত বৈজ্ঞানিক লেখার জন্য: শিরোনাম, অনুচ্ছেদ, তালিকা। টেবিল এল ডেটার জন্য, কিন্তু ডিজাইনাররা আবিষ্কার করলেন, ঘরের প্রস্থ ঠিক করে দিলে এটা দিয়েই গ্রিড বানানো যায়। ফাঁকা জায়গার জন্য স্বচ্ছ এক পিক্সেলের spacer GIF, গোল কোণার জন্য ঘরে ঘরে কাটা ছবি — টেবিলের ভেতরে টেবিল, তার ভেতরে আরও।

CSS ১৯৯৬ সালে এলেও শুরুতে পাশাপাশি কলাম বানানোর কোনো সোজা উপায় দেয়নি। পরে float আর position দিয়ে লেআউট সম্ভব হলো, কিন্তু Internet Explorer আর Netscape-এর মতো ব্রাউজারগুলো CSS আলাদা আলাদাভাবে, অনেক বাগসহ মানত — একই CSS দুই ব্রাউজারে দুই রকম দেখাত। টেবিল অন্তত সব জায়গায় একরকম দেখাত। ব্যবসার কাছে “সব ব্রাউজারে একরকম” ছিল সবচেয়ে বড় কথা।

পরিবর্তন এলো ধীরে। ২০০০-এর দশকের শুরুতে Web Standards আন্দোলন, ২০০২ সালে Wired News-এর CSS-নির্ভর নতুন নকশা, আর ২০০৩ সালে CSS Zen Garden দেখাল কাঠামো আর নকশা আলাদা রাখার শক্তি। স্মার্টফোন আসার পর টেবিল-লেআউট সত্যিকারের বোঝা হয়ে দাঁড়াল — স্থির প্রস্থের কলাম ছোট পর্দায় ভাঙে। শেষ পর্যন্ত Flexbox আর ২০১৭ সালে প্রধান ব্রাউজারগুলোতে আসা CSS Grid এমন লেআউট দিল, যা টেবিলের চেয়েও সহজ এবং রেসপন্সিভ।

ছাড়তে দেরি হওয়ার আরেকটা কারণ মানুষ আর পুরোনো কোড — হাজার হাজার সাইট, টেমপ্লেট আর CMS টেবিলে লেখা ছিল, নতুন করে লেখার খরচ বিশাল। আজও HTML ইমেইলে টেবিল-লেআউট টিকে আছে, কারণ কিছু ইমেইল অ্যাপ আধুনিক CSS মানে না।

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

প্র ০২CSS দিয়ে ul আর ol-কে হুবহু একরকম দেখানো যায় — তাহলে কোনটা লিখলাম তাতে আসলে কী যায় আসে?

চেহারা আর অর্থ দুটি আলাদা স্তর — আর চেহারা যিনি দেখতে পান না, বা যে যন্ত্র “দেখে” না, তাঁর কাছে শুধু অর্থটাই পৌঁছায়।

  • Screen reader: ol-এ শ্রোতা শোনেন “তালিকা, ৫টি আইটেম … ১, …”। ক্রম যে গুরুত্বপূর্ণ, এই তথ্য তিনি পান। রান্নার ধাপ বা ফর্ম পূরণের নির্দেশনায় এটা জরুরি।
  • CSS বন্ধ থাকলে বা কপি করলে: ধীর ইন্টারনেটে CSS লোড না হলে, Reader mode-এ, বা লেখা কপি করে Word-এ বসালে ol-এর নম্বর থেকে যায়। হাতে লেখা বা শুধু CSS দিয়ে বসানো নম্বর অনেক সময় হারিয়ে যায়।
  • যন্ত্রের বোঝা: সার্চ ইঞ্জিন রেসিপি বা “কীভাবে করবেন” ধরনের পাতার ধাপ চিনতে কাঠামো ব্যবহার করে। ওয়েব পড়ে উত্তর দেওয়া AI টুলও ol দেখে বোঝে এখানে ধাপে ধাপে নির্দেশ।
  • অর্থবহ নম্বর: HTML5 ol-এর type attribute ফিরিয়ে এনেছিল এই যুক্তিতেই — আইনের নথিতে “ধারা ৩(খ)” বললে ওই “খ” নিজেই তথ্য, সাজসজ্জা নয়।

উল্টো দিকটাও ভাবুন: যেখানে ক্রমের কোনো মানে নেই, সেখানে ol লেখা মানে শ্রোতাকে ভুল সংকেত দেওয়া — তিনি ভাববেন ১ নম্বরটাই সবচেয়ে গুরুত্বপূর্ণ। মেনুর লিংক ol-এ লিখলে “১, হোম; ২, কোর্স” শোনায়, যা অর্থহীন। তাই প্রশ্নটা কখনো “কোনটা দেখতে ভালো” নয়, সব সময় “ক্রম বদলালে কি অর্থ বদলায়”।

মূল উপলব্ধি: HTML একটি চুক্তি — আপনি ব্রাউজার আর সহায়ক প্রযুক্তিকে প্রতিশ্রুতি দিচ্ছেন যে এই অংশটা আসলে কী। CSS সেই প্রতিশ্রুতি বদলাতে পারে না, শুধু তার পোশাক বদলায়।

প্র ০৩div আর CSS Grid দিয়ে তো সুন্দর “টেবিল” বানানো যায় — তাহলে আসল <table> কেন? আর ARIA-র role="table" দিলে কি সমস্যা মেটে?

CSS Grid চমৎকার লেআউট টুল, কিন্তু এটা কেবল চেহারা ঠিক করে। div-এর গ্রিডে accessibility tree-তে কোনো টেবিল থাকে না — screen reader টেবিলের ভেতরে সারি-কলাম ধরে চলাচলের সুবিধা দিতে পারে না, কোন ঘরের শিরোনাম কোনটা তাও জানে না। আসল <table> এগুলো বিনামূল্যে দেয়: সারি ও কলামের সংখ্যা, শিরোনাম ঘোষণা, ছাপার সময় thead পুনরাবৃত্তি, এমনকি কপি করে Excel-এ বসালে ঘরগুলো ঠিক ঘরেই পড়া।

ARIA দিয়ে div-কে role="table", role="row", role="columnheader", role="cell" বানানো সম্ভব। কিন্তু ARIA-র প্রথম নিয়ম বলে: যে কাজের জন্য নিজস্ব HTML element আছে, সেটাই ব্যবহার করুন। কারণ ARIA শুধু ভূমিকা ঘোষণা করে, আচরণ দেয় না — প্রতিটি div-এ সঠিক role না দিলে, বা একটি সারি বাদ পড়লে পুরো কাঠামো ভেঙে যায়, আর সেই ভুল চোখে ধরা পড়ে না। যেখানে <table> নিজেই সব জানে, সেখানে হাতে নকল বানানো মানে বাড়তি ঝুঁকি।

আরেকটি সূক্ষ্ম বিষয়: role="grid" আর role="table" এক নয়। grid হলো স্প্রেডশিটের মতো ইন্টারঅ্যাকটিভ উইজেট, যেখানে তীর চিহ্নে ঘর থেকে ঘরে যাওয়া আর সম্পাদনার আচরণ JavaScript দিয়ে নিজেকে বানাতে হয়। শুধু ডেটা দেখাতে grid ব্যবহার করলে screen reader অন্যরকম আচরণ আশা করে, আর ব্যবহারকারী বিপদে পড়েন।

উল্টো দিক থেকেও একটি শিক্ষা আছে: আসল টেবিলে CSS-এ display বদলে দিলে (যেমন ফোনে কার্ড বানাতে) কিছু ব্রাউজারে টেবিলের অর্থ হারিয়ে যেতে পারে। তখন অনেক ডেভেলপার ভূমিকাগুলো ARIA দিয়ে ফিরিয়ে দেন — এটা ARIA-র বৈধ ব্যবহার, কারণ নিজস্ব element-ই আছে, শুধু হারানো অর্থ পূরণ করা হচ্ছে।

মূল উপলব্ধি: চেহারা যেকোনো element দিয়ে বানানো যায়; অর্থ আর আচরণ বিনামূল্যে পেতে হলে ঠিক element বেছে নিন। ARIA মেরামতের যন্ত্র, কাঠামোর বিকল্প নয়।

প্র ০৪ফোনের ছোট পর্দায় বড় টেবিল — পাশে স্ক্রল, কার্ডে ভাঙা, নাকি কলাম লুকানো? কোনটা কখন?

এখানে কোনো একটা “সেরা” উত্তর নেই — প্রতিটি পথের দাম আছে, আর সিদ্ধান্ত নির্ভর করে পাঠক টেবিল দিয়ে কী করবেন তার ওপর।

  • স্ক্রল কন্টেইনার: টেবিলের কাঠামো আর তুলনার সুবিধা অক্ষত থাকে, কোড সবচেয়ে সরল, ঝুঁকি সবচেয়ে কম। দুর্বলতা — ডানের কলাম চোখের আড়ালে থাকে, পাঠক হয়তো জানেনই না আরও আছে। প্রথম কলাম position: sticky দিয়ে আটকে রাখলে (sticky-র কৌশল পর্ব ২৪-এ) আর কিনারায় ছায়া দিয়ে ইঙ্গিত দিলে অনেকটা সমাধান হয়। WCAG-এর Reflow নিয়মও ডেটা-টেবিলের জন্য এই দুই দিকের স্ক্রলকে ব্যতিক্রম হিসেবে মেনে নেয়।
  • কার্ডে ভাঙা (stack): প্রতিটি সারি একটি কার্ড, ভেতরে “লেবেল: মান”। একজনের তথ্য পড়তে আরামদায়ক — যেমন রেজাল্ট সাইটে শুধু নিজের ফল দেখা। কিন্তু দুই সারির তুলনা কঠিন হয়ে যায়, আর CSS-এ display বদলালে কিছু ব্রাউজারে টেবিলের অর্থ হারানোর ঝুঁকি থাকে।
  • কম জরুরি কলাম লুকানো: পর্দা ছোট হলে শুধু মূল কলাম দেখানো, বাকিগুলো একটি বোতাম বা লিংকে। তথ্য হারিয়ে যাওয়ার ঝুঁকি আছে — যে কলামকে আপনি “কম জরুরি” ভাবছেন, কারও কাছে হয়তো সেটাই আসল।
  • টেবিলটাই নতুন করে ভাবা: অনেক সময় বড় টেবিলের বদলে একটি ফিল্টার বা ছোট কয়েকটি টেবিল ভালো।

বাংলাদেশের বাস্তবতায় ভাবুন: পরীক্ষার ফল প্রকাশের দিন লাখো মানুষ কম দামি Android ফোন আর ধীর মোবাইল ডেটায় একই সাইট খোলেন। সেখানে ভারী JavaScript দিয়ে চমক দেখানোর চেয়ে হালকা, সঠিক HTML টেবিল আর একটি স্ক্রল কন্টেইনার অনেক বেশি মানুষের কাজে লাগে।

মূল উপলব্ধি: রেসপন্সিভ ডিজাইন মানে শুধু “ছোট পর্দায় আঁটানো” নয়; ছোট পর্দায় পাঠক যে কাজটা করতে চান, সেটা সহজ করা। আগে কাজটা বুঝুন, তারপর কৌশল বাছুন।

প্র ০৫Screen reader একটি টেবিল আসলে “বোঝে” কীভাবে — scope, headers/id আর ব্রাউজারের হিসাবের মধ্যে সম্পর্ক কী?

Screen reader নিজে HTML পড়ে না; সে পড়ে ব্রাউজারের বানানো accessibility tree, যা অপারেটিং সিস্টেমের অ্যাক্সেসিবিলিটি API দিয়ে তার কাছে পৌঁছায়। তাই আসল কাজটা ব্রাউজারের — আর ব্রাউজার HTML স্পেসিফিকেশনের দুটি নিয়ম মেনে চলে।

  • টেবিল গঠন (forming a table): প্রতিটি ঘরকে স্লট-গ্রিডে বসানো, colspan-rowspan হিসাব করে কোন খোপ কার দখলে তা ঠিক করা — এই পর্বের স্টেপারে যা দেখেছেন।
  • শিরোনাম নির্ধারণ: প্রতিটি ডেটা-ঘরের জন্য ব্রাউজার খোঁজে কোন th তার শিরোনাম। ঘরে headers attribute থাকলে সরাসরি সেই id-গুলো নেয়। না থাকলে ঘর থেকে ওপরে আর বাঁয়ে খোপ ধরে ধরে স্ক্যান করে th খোঁজে, আর scope দেখে ঠিক করে কোন th কোন দিকে প্রযোজ্য। scope না থাকলে কিছু অনুমান করে — যেমন প্রথম সারির th-কে কলামের শিরোনাম ধরা।

এ কারণেই সরল টেবিলে scope যথেষ্ট — স্ক্যানটাই সঠিক উত্তর দেয়। কিন্তু দুই স্তরের শিরোনাম, মাঝখানে শিরোনাম-সারি, বা অনিয়মিত rowspan থাকলে স্ক্যান ভুল th ধরতে পারে; তখন headers/id দিয়ে সম্পর্কটা নিজে বলে দিতে হয়। বাস্তবে ব্রাউজার আর screen reader-ভেদে জটিল টেবিলের সমর্থন সমান নয়, তাই বিশেষজ্ঞরা বারবার বলেন — জটিল টেবিল এড়াতে পারলে এড়ান।

WCAG-এর নিয়ম ১.৩.১ (Info and Relationships) বলে, চোখে দেখা কাঠামো — কোন সংখ্যা কোন শিরোনামের অধীনে — কোডেও প্রকাশ পেতে হবে। caption হয়ে যায় টেবিলের “নাম”, যা দিয়ে শ্রোতা পাতার অনেক টেবিলের মধ্যে খুঁজে নেন। একসময় টেবিলের সারাংশ দিতে summary attribute ছিল, কিন্তু সেটা শুধু screen reader শুনত, চোখে দেখা কেউ না — আজ সেটি অচল, তার বদলে সবার জন্য দৃশ্যমান caption বা লেখা।

মূল উপলব্ধি: আপনার HTML থেকে ব্রাউজার একটি গাণিতিক কাঠামো বানায়, আর screen reader সেই কাঠামোই শোনায়। কাঠামো পরিষ্কার হলে চোখে দেখা আর না-দেখা — দুই পাঠকই একই তথ্য পান।

অনুশীলন

প্রথম তিনটিতে কোড লিখতে হবে না — ভাবা আর দেখাই আসল কাজ। চতুর্থটিতে একটি ছোট টেবিল লিখবেন।

  1. কোনটির জন্য কোন কাঠামো? (ক) জাতীয় পরিচয়পত্রের তথ্য — নাম, পিতার নাম, জন্মতারিখ (খ) বিকাশে “Send Money”-র ধাপ (গ) একটি ঈদ উপহারের তালিকা (ঘ) পাঁচটি জেলার মাসিক বৃষ্টিপাত, বারো মাসের।

    (ক) <dl> — প্রতিটি লাইন একটি নাম-মান জোড়া। (খ) <ol> — ধাপের ক্রম বদলালে কাজটাই হবে না। (গ) <ul> — কোনটা আগে লিখলাম তাতে কিছু যায় আসে না। (ঘ) <table> — জেলা × মাস, দুই দিকের সম্পর্ক; প্রতিটি সংখ্যা বুঝতে জেলা আর মাস দুটোই লাগে। caption, মাসের নামে th scope="col", জেলার নামে th scope="row", আর বারো কলাম বলে ফোনের জন্য স্ক্রল কন্টেইনার।

  2. অদৃশ্য tbody খুঁজুন: নিজের কম্পিউটারে একটি ফাইলে শুধু <table><tr><td>১</td></tr></table> লিখে ব্রাউজারে খুলুন। DevTools-এর Elements প্যানেলে কী দেখছেন? এবার Ctrl+U চেপে “View source”-এ কী দেখছেন? পার্থক্য কেন?

    View source দেখায় আপনার ফাইল, হুবহু — সেখানে tbody নেই। কিন্তু Elements প্যানেল দেখায় DOM, অর্থাৎ ব্রাউজার যা বানিয়েছে — সেখানে <tbody> আছে, কারণ HTML parser নিজেই বসিয়েছে। আরও দেখবেন <head> আর <body>-ও তৈরি হয়ে গেছে। শিক্ষা: DevTools যা দেখায় তা “ব্রাউজারের বোঝা” — CSS selector আর JavaScript এই DOM-এর ওপরই কাজ করে, আপনার লেখা ফাইলের ওপর নয়।

  3. কাগজে স্লট-গ্রিড: একটি টেবিলের প্রথম সারিতে আছে <th rowspan="2">, <th colspan="3">; দ্বিতীয় সারিতে তিনটি <th>; তৃতীয় সারিতে চারটি ঘর। টেবিলে কলাম কয়টি? দ্বিতীয় সারির তিনটি th কোন কোন কলামে বসবে? তৃতীয় সারি কি ঠিক আছে?

    প্রথম সারি: ১ + ৩ = ৪টি কলাম। প্রথম th-এর rowspan দ্বিতীয় সারির কলাম ১ দখল করে রাখে, তাই দ্বিতীয় সারির তিনটি th বসবে কলাম ২, ৩, ৪-এ — ঠিক colspan="3" ঘরটির নিচে। এটাই দুই স্তরের শিরোনামের সাধারণ নকশা (যেমন “বিষয়” | “নম্বর: লিখিত, MCQ, ব্যবহারিক”)। তৃতীয় সারিতে কোনো rowspan নেমে আসেনি, তাই চারটি ঘর = ৪ খোপ — ঠিক আছে।

  4. নিজে লিখুন — বাসার মাসিক খরচ: ঢাকার একটি পরিবারের তিন মাসের খরচের টেবিল বানান (খাত: বাসা ভাড়া, বিদ্যুৎ, গ্যাস; কলাম: জানুয়ারি, ফেব্রুয়ারি, মার্চ)। caption, thead, scope, আর tfoot-এ প্রতি মাসের মোট থাকবে; সংখ্যা কাল্পনিক রাখুন। ওপরের যেকোনো লাইভ এডিটরে লিখে পরীক্ষা করুন।

    একটি সম্ভাব্য উত্তর (মোট হাতে হিসাব করে মিলিয়ে নিন):

    <table>
      <caption>বাসার মাসিক খরচ, টাকায় (কাল্পনিক উদাহরণ)</caption>
      <thead>
        <tr><th scope="col">খাত</th><th scope="col">জানুয়ারি</th>
            <th scope="col">ফেব্রুয়ারি</th><th scope="col">মার্চ</th></tr>
      </thead>
      <tbody>
        <tr><th scope="row">বাসা ভাড়া</th><td>১৫০০০</td><td>১৫০০০</td><td>১৫০০০</td></tr>
        <tr><th scope="row">বিদ্যুৎ</th><td>১২০০</td><td>১১০০</td><td>১৬০০</td></tr>
        <tr><th scope="row">গ্যাস</th><td>১০৮০</td><td>১০৮০</td><td>১০৮০</td></tr>
      </tbody>
      <tfoot>
        <tr><th scope="row">মোট</th><td>১৭২৮০</td><td>১৭১৮০</td><td>১৭৬৮০</td></tr>
      </tfoot>
    </table>

    যাচাই: জানুয়ারি ১৫০০০ + ১২০০ + ১০৮০ = ১৭২৮০; ফেব্রুয়ারি ১৭১৮০; মার্চ ১৭৬৮০. খাতের নাম th scope="row" — তাই “বিদ্যুৎ, মার্চ, ১৬০০” শোনা যাবে। ফোনের জন্য এটি একটি role="region", aria-label আর tabindex="0" দেওয়া স্ক্রল কন্টেইনারে রাখলে আরও ভালো।

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

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

ক্রমএকটি HTML <table>-এর ভেতরের অংশগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. <caption> — টেবিলের শিরোনাম
  2. <colgroup> — কলামের দল
  3. <thead> — মাথার সারি
  4. <tbody> — মূল ডেটার সারি
  5. <tfoot> — যোগফল বা গড়ের সারি

একটি ওয়েবপেজে মোবাইল ব্যাংকিং অ্যাপে টাকা পাঠানোর পাঁচটি ধাপ দেখাতে হবে। কোন element সবচেয়ে উপযুক্ত?

  • <ul>
  • <ol>
  • <dl>
  • প্রতিটি ধাপ হাতে নম্বর লিখে <br> দিয়ে আলাদা করা

<ol type="A" start="3"> লেখা একটি তালিকার প্রথম আইটেমের পাশে কোন চিহ্ন বসবে?

  • A
  • 3
  • C
  • c

একটি ডেটা-টেবিলের কলামের শিরোনাম-ঘরে scope="col" লেখার মূল উদ্দেশ্য কী?

  • জানানো যে এই শিরোনাম নিচের পুরো কলামের ঘরগুলোর জন্য প্রযোজ্য
  • কলামের লেখা মোটা ও মাঝখানে দেখানো
  • ঘরটিকে কয়েকটি কলাম জুড়ে বসানো
  • কলামের প্রস্থ নির্দিষ্ট করা

একটি টেবিলে ৪টি কলাম। কোনো সারিতে ওপর থেকে কোনো rowspan নেমে আসেনি, আর সেই সারিতে প্রথমে আছে <td colspan="2">. সারিটি ঠিক রাখতে আর কয়টি সাধারণ <td> লাগবে?

  • ১টি
  • ২টি
  • ৩টি
  • ৪টি

আধুনিক ওয়েবপেজে বাঁ দিকে মেনু আর ডানে মূল লেখা পাশাপাশি সাজানোর সঠিক উপায় কোনটি?

  • দুই কলামের একটি <table> বানিয়ে প্রতিটি ঘরে একটি অংশ রাখা
  • <frameset> দিয়ে পাতা দুই ভাগ করা
  • অনেকগুলো &nbsp; দিয়ে জায়গা তৈরি করা
  • semantic element দিয়ে কাঠামো, আর CSS Flexbox বা Grid দিয়ে সাজানো

ফোনের ছোট পর্দায় একটি চওড়া ডেটা-টেবিল যেন পুরো পাতাকে পাশে টেনে না নেয়, সেজন্য প্রথম ও নিরাপদ পদক্ষেপ কোনটি?

  • টেবিলের লেখা খুব ছোট করে দেওয়া
  • টেবিলটিকে একটি ছবি বানিয়ে বসানো
  • টেবিলটিকে role="region", aria-label আর tabindex="0" দেওয়া একটি স্ক্রল কন্টেইনারে মুড়ে দেওয়া
  • টেবিল বাদ দিয়ে সব তথ্য এক অনুচ্ছেদে লিখে দেওয়া

শব্দকোষ

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

মনে রাখুন

  1. ক্রম বদলালে অর্থ বদলায় — <ol>; না বদলালে <ul>; নাম-মান জোড়া — <dl>. ol-এ type, start, reversed, আর li-তে value.
  2. উপ-তালিকা থাকে মূল <li>-এর ভেতরে; সাইটের মেনু = <nav> > <ul> > <li> > <a>.
  3. টেবিল শুধু সারি-কলামের ডেটার জন্য; পাতার লেআউট CSS-এর কাজ।
  4. অ্যাক্সেসিবল টেবিল: caption, thead/tbody/tfoot, th + scope; জটিল হলে headers/id — তবে আগে সরল করার চেষ্টা।
  5. colspan/rowspan = স্লট-গ্রিডের হিসাব, প্রতিটি সারিতে খোপ সমান; চওড়া টেবিল স্ক্রল কন্টেইনারে।

পরের পর্বে: এতক্ষণ তথ্য দেখালেন; এবার পাঠকের কাছ থেকে তথ্য নেবেন। ফর্মের ভিত্তি — form, input, label আর button — আর কেন প্রতিটি ইনপুটের সাথে একটি label থাকা চাই।

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

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