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

প্রথম HTML পেজ — element, tag, attribute আর ডকুমেন্টের গঠন

Your First HTML Page — Elements, Tags, Attributes & Document Structure

Taught in Bangla, this lesson builds a first HTML page. It separates tags, elements and attributes, introduces void elements, nesting and the DOM tree of parents, children and siblings, and explains every line of a valid document skeleton from doctype to title. It also covers quirks mode, how the parser repairs broken markup, whitespace, comments, quoting, global attributes like id, class and lang, and checking pages with the W3C validator.

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

  • tag, element আর attribute-এর সঠিক পার্থক্য — আর void element কোনগুলো
  • nesting-এর নিয়ম, আর ব্রাউজার কীভাবে আপনার লেখা থেকে DOM tree বানায়
  • একটি পূর্ণ, বৈধ HTML ডকুমেন্টের প্রতিটি লাইন কেন আছে — doctype থেকে title পর্যন্ত
  • ভুল HTML-এ ব্রাউজার কী করে, আর validator দিয়ে ভুল ধরার কৌশল
  • whitespace, comment, বড়-ছোট হাতের অক্ষর, quote আর global attribute-এর নিয়ম

১ · HTML আসলে কী — লেখার গায়ে লেবেল

পর্ব ১-এ দেখেছেন, ব্রাউজার সার্ভার থেকে একটি ফাইল আনে, তারপর সেটি পর্দায় সাজিয়ে দেখায়। সেই ফাইলটি আসলে একটি সাধারণ টেক্সট ফাইল — Notepad-এও খোলা যায়। তাহলে ব্রাউজার বোঝে কীভাবে, কোন লাইনটি শিরোনাম, কোনটি অনুচ্ছেদ, আর কোনটি একটি লিংক?

উত্তর হলো markup — লেখার গায়ে ছোট ছোট চিহ্ন বসিয়ে বলে দেওয়া, কোন অংশ কী। HTML-এর পুরো নাম HyperText Markup Language. “HyperText” মানে এমন লেখা, যেখান থেকে লিংক ধরে অন্য লেখায় যাওয়া যায়; আর “Markup Language” মানে চিহ্ন বসানোর ভাষা।

একটি মুদি দোকানের গুদামের কথা ভাবুন। বস্তায় বস্তায় চাল, ডাল, চিনি — দেখতে প্রায় একই। কর্মচারী যাতে না গুলিয়ে ফেলেন, তাই প্রতিটি বস্তার গায়ে লেবেল: “মিনিকেট চাল — ৫০ কেজি”, “মসুর ডাল — দেশি”। বস্তার ভেতরের জিনিস বদলায়নি, শুধু লেবেল বলে দিচ্ছে এটা কী। HTML ঠিক এই লেবেলের কাজ করে — লেখাকে বদলায় না, লেখার পরিচয় জানিয়ে দেয়। আর লেবেল দেখে তাকে কীভাবে সাজানো হবে — কোন তাকে, কোন রঙের কাগজে — সেটা ঠিক করে CSS (পর্ব ১৬ থেকে)।

একটি গুরুত্বপূর্ণ কথা শুরুতেই মনে রাখুন: HTML প্রোগ্রামিং ভাষা নয়। এতে যোগ-বিয়োগ, শর্ত (if) বা লুপ নেই। এটি একটি বর্ণনার ভাষা — “এটি শিরোনাম, এটি তালিকা, এটি ছবি।” এজন্যই HTML শেখা সহজ; কিন্তু ঠিকভাবে লেখা, যাতে ব্রাউজার, সার্চ ইঞ্জিন আর screen reader সবাই সঠিক অর্থ বোঝে — সেটিই আসল দক্ষতা।

১৯৮৯–৯১ সালে সুইজারল্যান্ডের গবেষণাগার CERN-এ Tim Berners-Lee ওয়েব আর HTML তৈরি করেন। তাঁর প্রথম তালিকায় ছিল মাত্র ১৮টির মতো ট্যাগ। এরপর HTML 2.0, 3.2, 4.01, XHTML আর HTML5 পার হয়ে আজ HTML একটি Living Standard — যার কোনো version নম্বর নেই, নিয়মিত হালনাগাদ হয়। এটি দেখভাল করে WHATWG, যেখানে Apple, Google, Mozilla আর Microsoft-এর মতো ব্রাউজার-নির্মাতারা একসাথে কাজ করেন। তাই কেউ “HTML6 কবে আসবে?” জিজ্ঞেস করলে উত্তর — আসবে না; HTML প্রতিদিনই একটু একটু বদলাচ্ছে।

২ · Element, tag আর attribute — একটি element-এর ব্যবচ্ছেদ

দৈনন্দিন কথায় অনেকে “tag” আর “element” মিশিয়ে বলেন। কাজ চলে যায়, কিন্তু পরীক্ষা, ইন্টারভিউ আর পেশাদার আলোচনায় পার্থক্যটি জানা জরুরি। নিচে দোকানের একটি লিংক ধাপে ধাপে ভেঙে দেখুন — “পরে” চাপুন:

<a href="dokan.html" title="রহিমের অনলাইন দোকান" > দোকানে যান </a>
  1. শুরুর tag খুলল: <a — কোণ-বন্ধনী < দিয়ে শুরু, তারপর tag-এর নাম a (anchor, অর্থাৎ লিংক)। নামটিই বলে দেয় এটি কী ধরনের জিনিস। নামের পরে অন্তত একটি space, তারপর attribute আসতে পারে।
  2. প্রথম attribute: href="dokan.html" — attribute সবসময় নাম="মান" রূপে লেখা হয়, আর থাকে শুধু শুরুর tag-এর ভেতরে। href বলছে লিংকটি কোথায় নিয়ে যাবে (পর্ব ৫-এ বিস্তারিত)।
  3. দ্বিতীয় attribute: title="…" — একাধিক attribute space দিয়ে আলাদা করা হয়; তাদের ক্রমে কিছু যায়-আসে না। title-এ মাউস রাখলে ছোট একটি বার্তা ভেসে ওঠে। এটি একটি global attribute — অংশ ৮-এ দেখবেন।
  4. শুরুর tag বন্ধ: > — এখানে শুরুর tag শেষ। <a href="…" title="…"> — পুরোটাকে বলে start tag (শুরুর tag).
  5. Content (বিষয়বস্তু): “দোকানে যান” — পাঠক পর্দায় এটুকুই দেখবেন, নীল রঙে, নিচে দাগসহ। Content হতে পারে লেখা, আবার অন্য element-ও।
  6. শেষের tag: </a> — নামের আগে স্ল্যাশ /. এটি end tag. এখন পুরো ছবিটা: start tag + content + end tag মিলে একটি element. Tag হলো দুই প্রান্তের চিহ্ন; element হলো চিহ্নসহ পুরো জিনিসটি — ব্রাউজারের ভেতরে যা একটি বস্তু হিসেবে বেঁচে থাকে।
মূল ধারণা

Tag = লেবেল (<p>, </p>). Element = লেবেলসহ পুরো জিনিস (<p>চাল ৬০ টাকা</p>). Attribute = start tag-এর ভেতরে বাড়তি তথ্য (class="price"). ব্রাউজার ফাইল পড়ার পর tag-গুলো আর থাকে না — থাকে শুধু element, যাদের প্রতিটির নিজস্ব attribute আর content আছে।

Void element — যাদের ভেতরে কিছু রাখার নেই

কিছু element-এর content থাকতেই পারে না — যেমন লাইন ভাঙা বা একটি ছবি। এদের বলে void element. এদের শুধু start tag থাকে; end tag লেখা নিষেধ। HTML-এ এ রকম element মোট ১৩টি:

১৩টি void element

area, base, br, col, embed, hr, img, input, link, meta, source, track, wbr. সবগুলো এখনই মুখস্থ করার দরকার নেই — br, hr, img, input, meta, link — এই ছয়টি প্রতিদিন দেখবেন।

পরীক্ষায় প্রিয় প্রশ্ন

শেষে স্ল্যাশ: <br />?

পুরোনো XHTML-এর অভ্যাস। HTML-এ void element-এর শেষে / দেওয়া বৈধ, কিন্তু এর কোনো প্রভাব নেই। সাবধান: <div /> লিখলে div বন্ধ হয় না — HTML স্ল্যাশটি উপেক্ষা করে, div খোলাই থাকে।

AI প্রায়ই এভাবে লেখে

</br> বা <img></img> লেখা ভুল। নতুনরা যে আরেকটি নাম শোনেন — “empty tag” বা “single tag” — সেটি void element-এরই পুরোনো ডাকনাম। একটি element-এর অংশগুলোর পরিচয় শেষ; এবার দেখি element-গুলো একে অপরের সাথে কীভাবে জোড়া লাগে।

৩ · Nesting আর tree — parent, child, sibling

এক element-এর ভেতরে আরেকটি রাখাকে বলে nesting. যেমন একটি অনুচ্ছেদের ভেতরে একটি শব্দকে মোটা করা: <p>আজ <strong>হরতাল নেই</strong>, দোকান খোলা।</p>. নিয়ম একটাই, কিন্তু কঠোর — যেটি পরে খুলেছেন, সেটি আগে বন্ধ করবেন।

টিফিন ক্যারিয়ারের বাটির মতো ভাবুন — বড় বাটির ভেতরে ছোট বাটি। ছোট বাটি বাইরে না এনে বড়টি বন্ধ করা যায় না। <p><strong>…</strong></p> ঠিক; <p><strong>…</p></strong> ভুল — যেন ভেতরের বাটি খোলা রেখে বাইরের ঢাকনা লাগানোর চেষ্টা।

এই বাটির ভেতরে বাটি সাজানো থেকেই তৈরি হয় একটি গাছ বা tree. ব্রাউজার HTML পড়ে মেমরিতে যে tree বানায়, তার নাম DOM (Document Object Model). Tree-এর প্রতিটি অংশকে বলে node — element node, লেখার (text) node, comment node. পরিবারের সম্পর্কের নামেই এদের সম্পর্ক বোঝানো হয়। নিচে একটি ছোট পাতার tree ধাপে ধাপে দেখুন:

<html>root — সবার মূল
<head>পাতার তথ্য
<body>যা দেখা যায়
<title>head-এর ভেতরে
<h1>body-র ভেতরে
<ul>body-র ভেতরে
<p>body-র ভেতরে
  1. Root — গাছের গোড়া। সবকিছুর বাইরে থাকে <html>. বাকি সব element এর ভেতরে। Tree-তে এর ওপরে আছে শুধু document নিজে।
  2. Child আর sibling. <html>-এর সরাসরি ভেতরে দুটি element: <head> আর <body>. এরা html-এর child (সন্তান), আর একে অপরের sibling (ভাইবোন) — কারণ এদের parent একই।
  3. Parent. <h1>, <ul> আর <p> — তিনজনেরই parent (মা-বাবা) হলো <body>. প্রতিটি element-এর parent ঠিক একটি (root ছাড়া)। Child থাকতে পারে শূন্য থেকে অনেক।
  4. Sibling-দের ক্রম আছে। h1, ul, p তিন ভাইবোন — আর তাদের ক্রম গুরুত্বপূর্ণ। ব্রাউজার এই ক্রমেই পাতায় সাজায়, screen reader এই ক্রমেই পড়ে। CSS-এ “পরের sibling” বেছে নেওয়ার selector-ও আছে (পর্ব ১৭)।
  5. Ancestor আর descendant. <title>-এর parent head, আর parent-এর parent html — এরা সবাই title-এর ancestor (পূর্বপুরুষ)। উল্টো দিকে, title হলো html-এর descendant (বংশধর)। CSS আর JavaScript দুটোই এই সম্পর্ক ধরে element খোঁজে — তাই সঠিক nesting মানে সঠিক পরিবার।

খেয়াল করুন, আপনি যে ফাইল লেখেন (source) আর ব্রাউজার যে tree বানায় (DOM) — দুটো আলাদা জিনিস। ব্রাউজারে Ctrl+U চাপলে দেখা যায় source — আপনার হুবহু লেখা। আর DevTools-এর Elements প্যানেলে (পর্ব ২) দেখা যায় DOM — ব্রাউজার যা বুঝেছে। লেখা ঠিক থাকলে দুটো প্রায় এক; ভুল থাকলে পার্থক্য চোখে পড়ে — অংশ ৬-এ নিজেই দেখবেন।

JavaScript-এ এই tree নিয়েই কাজ হয় — element খোঁজা, বদলানো, নতুন যোগ করা। সেটি শিখবেন পর্ব ৫২-তে, আর বিস্তারিত আমাদের JavaScript কোর্সের DOM পর্বে। আপাতত মনে রাখুন: পাতা মানে একটি tree, আর আপনার HTML সেই tree-এর নকশা।

৪ · একটি পূর্ণ HTML ডকুমেন্টের কঙ্কাল

এবার একটি সম্পূর্ণ, বৈধ পাতা লিখি। বাড়ি বানানোর আগে যেমন ভিত, পিলার আর ছাদের কাঠামো লাগে, তেমনি প্রতিটি HTML পাতার একই কঙ্কাল থাকে। নিচের এডিটরটি লাইভ — কোড বদলালেই সাথের প্রিভিউ বদলে যাবে।

<!doctype html>
<html lang="bn">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>রহিমের চায়ের দোকান</title>
</head>
<body>
  <h1>রহিমের চায়ের দোকান</h1>
  <p>দুধ চা ১৫ টাকা, লাল চা ১০ টাকা।</p>
  <!-- সময়সূচি পরে বদলাতে পারে -->
  <p>সকাল ৭টা থেকে রাত ১১টা পর্যন্ত খোলা।</p>
</body>
</html>

প্রিভিউতে দেখবেন একটি বড় শিরোনাম আর দুটি অনুচ্ছেদ। Comment লাইনটি (<!-- … -->) কোথাও দেখা যাচ্ছে না, আর <head>-এর কিছুই পাতায় আসেনি — title দেখা যায় ব্রাউজারের ট্যাবে (প্রিভিউটি ট্যাব নয়, তাই এখানে দেখবেন না)। চেষ্টা করুন: শেষ </p>-এর পরে <p>বাকিতে চা দেওয়া হয় না</p> যোগ করুন। তারপর <h1>-কে <h2> করে দেখুন — শিরোনাম ছোট হলো কেন, তা পর্ব ৪-এ জানবেন।

প্রতিটি লাইন কেন আছে, এক এক করে দেখি:

লাইনকাজনা দিলে কী হয়
<!doctype html>ব্রাউজারকে বলে “আধুনিক নিয়মে পাতা আঁকো”পাতা চলে যায় quirks mode-এ — পুরোনো, অদ্ভুত নিয়মে (অংশ ৫)
<html lang="bn">সবকিছুর মূল element; lang জানায় পাতার ভাষা বাংলাscreen reader ভুল উচ্চারণে পড়তে পারে, অনুবাদ-টুল ভাষা গুলিয়ে ফেলে
<meta charset="utf-8">অক্ষরগুলো কোন নিয়মে (UTF-8) জমা আছে, তা জানায়বাংলা লেখা ভেঙে “রহ” জাতীয় হিজিবিজি হতে পারে
<meta name="viewport" …>মোবাইলে পাতার চওড়া = ফোনের পর্দার চওড়াফোনে পাতা ডেস্কটপের মতো চওড়া ধরে ছোট করে দেখায়
<title>ট্যাব, বুকমার্ক আর সার্চ ফলাফলে পাতার নামট্যাবে ফাইলের নাম দেখায়; validator error দেয়
<body>পাঠক যা দেখবেন — লেখা, ছবি, লিংক, ফর্মব্রাউজার নিজেই একটি body বানিয়ে নেয় (অংশ ৬)

head আর body — দোকানের পেছনের খাতা আর সামনের তাক

<head> — পাতার সম্পর্কে তথ্য

দোকানের পেছনের হিসাবের খাতার মতো — ক্রেতা দেখেন না, কিন্তু দোকান চলে এর ওপর। এখানে থাকে <title>, meta তথ্য, CSS ফাইলের সংযোগ (<link>), কখনো <script>. পাতায় সরাসরি কিছুই আঁকা হয় না।

ব্রাউজার, সার্চ ইঞ্জিন আর সোশ্যাল মিডিয়ার জন্য

<body> — যা পাঠক দেখেন

দোকানের সামনের সাজানো তাক। শিরোনাম, অনুচ্ছেদ, ছবি, লিংক, বোতাম, ফর্ম — পাতার দৃশ্যমান সবকিছু এখানে। একটি পাতায় head একটি, body-ও একটি।

মানুষের জন্য

<meta charset="utf-8"> লাইনটি head-এর একদম শুরুতে রাখুন — নিয়ম অনুযায়ী এটি ফাইলের প্রথম ১০২৪ বাইটের মধ্যে থাকতে হয়, কারণ ব্রাউজার এটুকু পড়েই ঠিক করে বাকি অক্ষরগুলো কীভাবে পড়বে। আর বাংলা পাতার জন্য UTF-8 ছাড়া অন্য কিছু ভাবার দরকার নেই; আধুনিক নিয়মে নতুন পাতার encoding হতেই হবে UTF-8. বাংলা অক্ষর কম্পিউটারে কীভাবে জমা থাকে, তা জানতে চাইলে আমাদের বাংলা টাইপিং ও Unicode পর্ব দেখুন; ওয়েবে বাংলার খুঁটিনাটি আসবে পর্ব ১৪-তে।

Viewport meta ছাড়া ফোনের ব্রাউজার ধরে নেয় পাতাটি ডেস্কটপের জন্য বানানো — প্রায় ৯৮০ পিক্সেল চওড়া — তারপর পুরোটা ছোট করে পর্দায় ঢোকায়, লেখা পড়তে হয় চিমটি দিয়ে বড় করে। width=device-width বলে “ফোনের আসল চওড়াই পাতার চওড়া”। এখানে এটুকু জানলেই চলবে; head-এর বাকি meta আর SEO পর্ব ১৩-তে, আর viewport-এর পূর্ণ গল্প পর্ব ৩০-এ (রেসপন্সিভ ডিজাইন)।

৫ · Doctype আর quirks mode — পুরোনো ওয়েবের উত্তরাধিকার

প্রথম লাইনটি দেখতে সবচেয়ে অদ্ভুত — এটি কোনো element নয়, এর end tag নেই, পাতায় কিছু দেখায়ও না। তাহলে এটি আছে কেন? উত্তর লুকিয়ে আছে ১৯৯০-এর দশকের শেষে, “ব্রাউজার যুদ্ধের” সময়ে।

তখন Netscape আর Internet Explorer যে যার মতো নিয়মে পাতা আঁকত, আর লাখো ওয়েবসাইট সেই ভুলভাল নিয়মের ওপর ভর করে বানানো হয়েছিল। পরে CSS-এর সঠিক নিয়ম চালু করতে গিয়ে ব্রাউজার-নির্মাতারা বিপদে পড়লেন — সঠিক নিয়মে আঁকলে পুরোনো সাইটগুলো ভেঙে যায়। সমাধান: doctype দেখে আচরণ বেছে নেওয়া। পাতার শুরুতে আধুনিক doctype থাকলে standards mode (সঠিক নিয়ম); না থাকলে বা পুরোনো ধাঁচের হলে quirks mode — পুরোনো ব্রাউজারের “খামখেয়ালি” (quirk) নকল করা।

নিচের পাতাটি নিজেই বলে দেয় সে কোন mode-এ চলছে। প্রথম লাইনটি (<!doctype html>) মুছে দিয়ে দেখুন কী হয়:

<!doctype html>
<html lang="bn">
<head>
  <meta charset="utf-8">
  <title>Mode পরীক্ষা</title>
</head>
<body>
  <div style="font-size: 28px">
    <p>বড় লেখা — div থেকে পাওয়া</p>
    <table><tr><td>টেবিলের লেখা</td></tr></table>
  </div>
  <p>এই পাতা চলছে: <b id="mode">?</b></p>
  <script>
    const mode = document.compatMode;
    document.getElementById('mode').textContent =
      mode === 'CSS1Compat' ? 'standards mode' : 'quirks mode';
    console.log('document.compatMode = ' + mode);
  </script>
</body>
</html>

doctype থাকা অবস্থায় দুটি লেখাই সমান বড় (২৮ পিক্সেল), নিচে লেখা standards mode, আর আউটপুটে document.compatMode = CSS1Compat. এবার প্রথম লাইনটি মুছুন: টেবিলের লেখা হঠাৎ ছোট হয়ে যায়, আর লেখা আসে quirks mode ও BackCompat. কারণ পুরোনো ব্রাউজারে টেবিল বাইরের লেখার আকার নিত না — quirks mode আজও সেই ভুলটি সযত্নে নকল করে। (style attribute দিয়ে ছোট্ট CSS লিখেছি; CSS শুরু হবে পর্ব ১৬-তে।) চাইলে <!DOCTYPE HTML> বড় হাতে লিখে দেখুন — mode বদলায় না, কারণ doctype বড়-ছোট হাতের অক্ষর মানে না।

HTML5-এর আগে doctype ছিল দীর্ঘ, মুখস্থ করা কঠিন — যেমন <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">. HTML5-এর নকশাকারীরা খুঁজে বের করলেন সবচেয়ে ছোট কোন লেখাটি সব ব্রাউজারকে standards mode-এ নিয়ে যায়: <!doctype html>. ব্যস, এটুকুই। এর কোনো version নেই, আর কখনো বদলাবে না।

আধুনিক নতুন পাতায় quirks mode চাওয়ার কোনো কারণ নেই। কেউ doctype ভুলে গেলে CSS-এর কিছু নিয়ম অদ্ভুত আচরণ করে — শতাংশে উচ্চতা, টেবিলের লেখা, ছবির চারপাশের ফাঁকা জায়গা — আর ঘণ্টার পর ঘণ্টা কেউ ভাবেন “আমার CSS কাজ করছে না কেন?” প্রথম লাইনটি সবসময় <!doctype html>, আর এর আগে কিছু নয় — এমনকি একটি comment-ও না রাখাই নিরাপদ।

৬ · ব্রাউজার ভুল ক্ষমা করে — parser কীভাবে মেরামত করে

C বা Java-তে একটি সেমিকোলন বাদ পড়লে compiler পুরো প্রোগ্রাম বাতিল করে দেয়। HTML-এ ব্যাপারটা একদম উল্টো — আপনি যত ভুলই করুন, ব্রাউজার কিছু একটা দেখাবেই। কারণ ওয়েবের শুরু থেকেই নীতি ছিল: পাঠকের সামনে খালি পর্দা নয়, যতটুকু সম্ভব পাতা দেখাও।

HTML ফাইল পড়ে tree বানানোর কাজটি করে ব্রাউজারের parser. সে লেখা পড়ে টুকরো টুকরো করে (কোনটি start tag, কোনটি লেখা), আর একটি “খোলা element-এর স্তূপ” মনে রাখে — শেষ যেটি খুলেছে, সেটি সবার ওপরে। মজার ব্যাপার, অনেক tag লেখা ঐচ্ছিক — parser নিজেই বুঝে নেয় কোথায় সেগুলো থাকার কথা। এদের বলে optional tag. নিচের চার লাইনের “পাতা”-তে <html>, <head>, <body> কোনোটাই নেই, </p>-ও নেই। Parser কী করে, দেখুন:

1<!doctype html>2<title>রহিমের দোকান</title>3<p>চাল ৬০ টাকা4<p>ডাল ১১০ টাকা5
Parser-এর খাতা
এইমাত্র পড়া
খোলা স্তূপ
নিজে যা করল
  1. Doctype পড়া হলো। Parser দেখল আধুনিক doctype আছে, তাই standards mode. Tree-তে এখনো শুধু document আর doctype; কোনো element নেই।
  2. <title> — কিন্তু html কোথায়? Title থাকার কথা head-এর ভেতরে, আর head থাকার কথা html-এর ভেতরে। লেখা না থাকলেও parser নিজেই html আর head তৈরি করল, তারপর title খুলল। এটি কোনো ভুল নয় — html আর head-এর tag লেখা নিয়ম অনুযায়ীই ঐচ্ছিক।
  3. লেখা ঢুকল, title বন্ধ হলো। “রহিমের দোকান” title-এর ভেতরে একটি text node হয়ে বসল। </title> পেয়ে parser স্তূপ থেকে title সরাল — এখন ওপরে head.
  4. <p> — head-এ তো অনুচ্ছেদ চলে না! Parser বুঝল head-এর কাজ শেষ। নিজেই head বন্ধ করল, নিজেই body বানাল, তারপর তার ভেতরে p খুলল। এজন্যই head-এ ভুল করে কোনো দৃশ্যমান element রাখলে সেখান থেকেই body শুরু হয়ে যায়।
  5. লেখা p-এর ভেতরে। “চাল ৬০ টাকা” আর লাইনের শেষের Enter — দুটোই প্রথম p-এর text node. এখনো </p> আসেনি।
  6. আরেকটি <p> — আগেরটির কী হবে? নিয়ম বলে অনুচ্ছেদের ভেতরে অনুচ্ছেদ থাকতে পারে না। তাই নতুন p খোলার আগে parser নিজেই আগের p বন্ধ করল। ফলে দুটি p হলো sibling, একটি আরেকটির ভেতরে নয়।
  7. ফাইল শেষ। খোলা যা ছিল (p, body, html) — সব বন্ধ। চূড়ান্ত DOM-এ html, head, body তিনটিই আছে, যদিও আপনি একটিও লেখেননি। বৈধ, কিন্তু নতুনদের জন্য পরামর্শ: এই tag-গুলো নিজে লিখুন — পড়তে সহজ, ভুলের সুযোগ কম, আর <html lang="bn"> লেখার জায়গাও এটিই।

উপরের মেরামতগুলো সব নিয়মসিদ্ধ। কিন্তু সত্যিকারের ভুল হলে কী হয়? নিচের কোডে চারটি ভুল ইচ্ছা করে রাখা আছে — বন্ধ না করা p, ভুল ক্রমে বন্ধ করা b-i, অনুচ্ছেদের ভেতরে div, আর বন্ধ না করা li. সাথের ছোট script-টি ব্রাউজারের বানানো DOM tree ছাপিয়ে দেখায়:

<div id="demo">
<p>প্রথম অনুচ্ছেদ
<p>দ্বিতীয় — আগেরটি বন্ধ করিনি
<p><b>মোটা <i>মোটা-বাঁকা</b> শুধু বাঁকা?</i></p>
<p>লেখার মাঝে <div>একটি div</div> বাকি লেখা</p>
<ul><li>চাল<li>ডাল</ul>
</div>
<script>
  // DOM tree ছাপাই: element হলে <নাম>, লেখা হলে "লেখা"
  function show(node, pad) {
    for (const c of node.childNodes) {
      if (c.nodeType === 1) {
        console.log(pad + '<' + c.localName + '>');
        show(c, pad + '  ');
      } else if (c.nodeType === 3 && c.data.trim()) {
        console.log(pad + '"' + c.data.trim() + '"');
      }
    }
  }
  show(document.getElementById('demo'), '');
</script>

আউটপুটে চারটি মেরামত দেখবেন। (১) প্রথম দুটি p পাশাপাশি sibling — parser নিজেই বন্ধ করেছে। (২) <b>-এর পরে একটি নতুন <i> তৈরি হয়েছে: “শুধু বাঁকা?” আর মোটা নয়, শুধু বাঁকা। (৩) <div> আসতেই p বন্ধ হয়ে গেছে, তাই "বাকি লেখা" কোনো p-এর ভেতরে নেই, আর অনাথ </p> থেকে জন্ম নিয়েছে একটি খালি <p>. (৪) li দুটি ঠিকঠাক বন্ধ হয়েছে — এটি নিয়মসিদ্ধ ঐচ্ছিক tag. চেষ্টা করুন: চতুর্থ লাইনের <div>…</div>-কে <span>…</span> করে দিন — খালি p আর অনাথ লেখা দুটোই উধাও হবে।

আরও গভীরে

HTML5-এর আগে প্রতিটি ব্রাউজার ভুল HTML নিজের মতো করে মেরামত করত, তাই একই পাতা চার ব্রাউজারে চার রকম দেখাত। HTML5 প্রথমবার পুরো parse error-মেরামতের নিয়ম লিখে দেয় — একটি tokenizer (কয়েক ডজন অবস্থা বা state-ওয়ালা একটি যন্ত্র) আর tree-নির্মাণের ধাপ (“insertion mode”, যেমন “in head”, “in body”, “in table”). b-i-এর মতো ভুল ক্রমের formatting element মেরামতের অংশটির নাম “adoption agency algorithm”, আর টেবিলের ভেতরে ভুল জায়গার লেখা টেবিলের বাইরে সরিয়ে দেওয়ার নাম “foster parenting”. এখন সব প্রধান ব্রাউজার একই অ্যালগরিদম চালায় — তাই ভুল HTML-ও আজ সব ব্রাউজারে একই DOM দেয়।

“ব্রাউজার তো ঠিক করেই নেয়” — এই ভরসায় ভুল HTML রেখে দেবেন না। মেরামত হয় নিয়ম মেনে, আপনার ইচ্ছা মেনে নয়। ফলে CSS ভুল element-এ লাগে, JavaScript যে element খোঁজে তা পায় না, আর screen reader ভুল কাঠামো পড়ে শোনায়। উপরের খালি <p>-টির মতো অদৃশ্য ভুলগুলোই সবচেয়ে বেশি সময় নষ্ট করে।

৭ · লেখার আদবকায়দা — whitespace, comment, অক্ষরের হাত আর quote

Whitespace গলে যায়

পরীক্ষার খাতায় যেমন যত জোরে কলম চাপুন, শব্দের মাঝের ফাঁক দিয়ে নম্বর বাড়ে না — HTML-এও লেখার মাঝে দশটি space বা পাঁচবার Enter দিলে ব্রাউজার দেখায় মাত্র একটি space. একে বলে whitespace collapsing. Space, Tab আর নতুন লাইন — সবই “whitespace”; পাশাপাশি অনেকগুলো থাকলে মিলে একটি হয়ে যায়, আর লাইনের শুরু-শেষের ফাঁকা অংশ মুছে যায়। নিচে নিজেই দেখুন:

<p>রহিম      চাচার
        চায়ের


   দোকান</p>

<pre>রহিম      চাচার
        চায়ের
   দোকান</pre>

<p>দাম:&nbsp;&nbsp;&nbsp;১০&nbsp;টাকা</p>

<p><b>চা</b><b>কফি</b> বনাম <b>চা</b> <b>কফি</b></p>

প্রথম অনুচ্ছেদে সব ফাঁক আর নতুন লাইন মিলে এক লাইন: “রহিম চাচার চায়ের দোকান”। <pre> (preformatted) ফাঁকগুলো হুবহু রেখেছে, লেখাও এসেছে সমান-চওড়া (monospace) ফন্টে। তৃতীয় লাইনে &nbsp; (non-breaking space) — একটি বিশেষ entity — গলে না, তাই তিনটি ফাঁক আলাদা দেখা যাচ্ছে; আর “১০ টাকা”-র মাঝে লাইন কখনো ভাঙবে না। শেষ লাইনে “চাকফি” জোড়া লেগে গেছে, কারণ মাঝে কোনো whitespace নেই — whitespace “গলে” ঠিকই, কিন্তু একেবারে হারায় না। চেষ্টা করুন: প্রথম অনুচ্ছেদে “চাচার”-এর পরে <br> বসিয়ে দেখুন লাইন ভাঙে কি না।

এর মানে: পাতায় ফাঁকা জায়গা বা লাইন-বিরতি আনতে space বা Enter নয়, সঠিক element ব্যবহার করুন — নতুন অনুচ্ছেদের জন্য <p>, কবিতা বা ঠিকানার লাইনের জন্য <br>, আর দূরত্বের জন্য CSS (পর্ব ১৯-এ margin, padding). পাশাপাশি সাজানো element-এর মাঝের whitespace কখনো কখনো অপ্রত্যাশিত ফাঁক তৈরি করে — সেই রহস্যের সমাধান পর্ব ২৩-এ।

Comment — নিজের জন্য নোট

<!-- এখানে নোট --> হলো comment. ব্রাউজার এটি দেখায় না, কিন্তু DOM-এ একটি comment node হিসেবে থেকে যায়, আর Ctrl+U চাপলে যে কেউ পড়তে পারে। তাই পাসওয়ার্ড, গোপন দাম বা কারও সম্পর্কে মন্তব্য comment-এ কখনো নয়। Comment-এর ভেতরে comment রাখা যায় না — প্রথম --> পেলেই comment শেষ।

বড়-ছোট হাতের অক্ষর আর quote

  • Tag আর attribute-এর নাম case-insensitive: <P CLASS="x"> আর <p class="x"> ব্রাউজারের কাছে একই। পুরোনো বইয়ে বড় হাতের tag দেখবেন; আজকের প্রচলন সবই ছোট হাতে।
  • কিন্তু attribute-এর মান প্রায়ই case-sensitive: id="offer" আর id="Offer" দুটি আলাদা id. Class-এর নামও তাই। ফাইলের নামও — Windows-এ Logo.png আর logo.png একই হলেও Linux সার্ভারে আলাদা, আর বেশিরভাগ হোস্টিং চলে Linux-এ।
  • Quote: মান লেখা যায় ডাবল quote-এ (class="price"), সিঙ্গেল quote-এ (class='price'), এমনকি quote ছাড়াও (class=price) — শেষেরটি শুধু তখন, যখন মানে space, quote, =, <, > বা backtick নেই। প্রচলন: সবসময় ডাবল quote. class=price new লিখলে ব্রাউজার বুঝবে class হলো শুধু price, আর new একটি আলাদা (অর্থহীন) attribute.
  • Boolean attribute: কিছু attribute-এর মান লাগে না — থাকলেই “হ্যাঁ”। যেমন hidden, disabled, required. সাবধান: hidden="false" লিখলেও element লুকানোই থাকে! নিচের অংশে নিজেই দেখবেন।

৮ · Global attribute — id, class, title, lang আর hidden

বেশিরভাগ attribute নির্দিষ্ট element-এর জন্য — href শুধু লিংকের, src ছবির। কিন্তু কিছু attribute যেকোনো HTML element-এ বসানো যায়। এদের বলে global attribute. সবচেয়ে বেশি ব্যবহৃত পাঁচটি:

Attributeকাজনিয়ম ও সাবধানতা
idelement-এর অনন্য নাম — যেমন জাতীয় পরিচয়পত্রের নম্বরপুরো পাতায় একটিই থাকবে; ভেতরে space চলবে না। লিংকে #offer দিয়ে লাফ, JavaScript-এ খোঁজা, label জোড়া — সবখানে লাগে
classদলের নাম — যেমন স্কুলের “দশম শ্রেণি, ক শাখা”অনেক element একই class পেতে পারে; একটি element-এ space দিয়ে একাধিক class: class="card sale". CSS-এর প্রধান হাতিয়ার (পর্ব ১৭)
titleমাউস রাখলে ছোট বার্তা (tooltip)ফোন আর কিবোর্ড-ব্যবহারকারীরা প্রায়ই দেখতে পান না — জরুরি তথ্য কখনো শুধু title-এ নয়
langelement-এর লেখার ভাষাপুরো পাতার জন্য <html lang="bn">; মাঝে ইংরেজি অংশ থাকলে সেই element-এ lang="en"
hiddenelement লুকিয়ে রাখা (boolean)থাকলেই লুকানো — মান যা-ই হোক। CSS-এ display দিলে hidden হার মানতে পারে

এ ছাড়া style (ছোট CSS), dir (লেখার দিক), tabindex, contenteditable আর নিজের ডেটা রাখার data-* — এরাও global attribute; যথাসময়ে দেখা হবে। নিচের কোডে ইচ্ছা করে বড় হাতের tag, quote ছাড়া মান আর hidden="false" রাখা আছে:

<P ID="offer" Class=notice title="অফার চলবে ৩০ অক্টোবর পর্যন্ত">ঈদ অফার — এখানে মাউস রাখুন</P>
<p lang="en">Free delivery inside Dhaka</p>
<p hidden>এই লাইনটি পাতায় দেখা যাবে না</p>
<p hidden="false">এটিও দেখা যাবে না!</p>
<script>
  const offer = document.getElementById('offer');
  console.log(offer.outerHTML);
  console.log('id="Offer" আছে? ' + (document.getElementById('Offer') !== null));
  console.log('লুকানো element: ' + document.querySelectorAll('[hidden]').length);
</script>

প্রিভিউতে দুটি লাইন — চারটির মধ্যে দুটি লুকানো, এমনকি hidden="false"-ওয়ালাটিও। প্রথম লাইনে মাউস রাখলে tooltip আসে। আউটপুটের প্রথম লাইনে দেখুন: আপনি লিখেছিলেন <P ID=… Class=notice>, কিন্তু DOM-এ জমা আছে <p id="offer" class="notice" …> — সব ছোট হাতে, quote সহ। অর্থাৎ নামের হাত গুরুত্বহীন। কিন্তু দ্বিতীয় লাইন বলছে false — id-এর মান “Offer” আর “offer” আলাদা। চেষ্টা করুন: চতুর্থ লাইন থেকে পুরো hidden="false" মুছে দিন, তবেই লেখাটি দেখা যাবে।

lang শুধু একটি ছোট attribute মনে হলেও এর প্রভাব বড়: screen reader সঠিক ভাষার কণ্ঠ বেছে নেয়, ব্রাউজার সঠিক ফন্ট ও শব্দ-ভাঙার নিয়ম প্রয়োগ করে, আর Google Translate-এর মতো টুল বোঝে পাতাটি কোন ভাষার। অ্যাক্সেসিবিলিটির আন্তর্জাতিক নির্দেশিকা WCAG-এর একদম প্রথম স্তরের শর্তই হলো পাতার ভাষা জানানো (পর্ব ১২)। আর hidden-এর একটি নতুন রূপ আছে — hidden="until-found", যেখানে লুকানো লেখা পাতার ভেতরে খুঁজলে (Ctrl+F) নিজে থেকে বেরিয়ে আসে। এটি এখনো Baseline Widely available নয় — ব্যবহারের আগে Can I use-এ দেখে নিন; না-চলা ব্রাউজারে সাধারণ hidden-এর মতোই লুকিয়ে থাকে, খুঁজে পাওয়া যায় না।

পরীক্ষা ও ইন্টারভিউতে

এ ধরনের প্রশ্ন প্রায়ই আসে:

  • Tag আর element-এর পার্থক্য কী? Tag হলো চিহ্ন (<p>); element হলো start tag, content আর end tag মিলে পুরো অংশ।
  • Void element কী? দুটি উদাহরণ দিন। যার content আর end tag নেই — <br>, <img>.
  • <!doctype html> না দিলে কী হয়? পাতা quirks mode-এ আঁকা হয়, CSS-এর কিছু নিয়ম পুরোনো ভুল আচরণ করে।
  • id আর class-এর পার্থক্য? id পাতায় একবারই, একটি element-কে চেনায়; class অনেক element-এ বারবার ব্যবহার করা যায়।
  • HTML কি case-sensitive? Tag আর attribute-এর নাম নয়; তবে id, class-এর মতো মান case-sensitive.

৯ · Validator — আপনার HTML-এর পরীক্ষক

ব্রাউজার ভুল দেখায় না, চুপচাপ মেরামত করে। তাহলে ভুল ধরবে কে? উত্তর validator — একটি টুল, যা আপনার HTML-কে নিয়মের বইয়ের সাথে মিলিয়ে প্রতিটি ভুল লাইন নম্বরসহ জানায়। সবচেয়ে প্রচলিতটি W3C-র বিনামূল্যের validator.w3.org/nu (Nu Html Checker). তিনভাবে ব্যবহার করা যায়: প্রকাশিত পাতার URL দিয়ে, ফাইল আপলোড করে, বা সরাসরি কোড পেস্ট করে (“Text Input”).

অংশ ৬-এর ভুল কোডটি পেস্ট করলে এ রকম বার্তা পাবেন (হুবহু শব্দ সময়ে সময়ে একটু বদলাতে পারে):

Error: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
Error: End tag “b” violates nesting rules.
Error: No “p” element in scope but a “p” end tag seen.
Warning: Consider adding a “lang” attribute to the “html” start tag to declare the language of this document.
বার্তায় যা দেখবেনমানেকী করবেন
without seeing a doctypeপ্রথম লাইনে doctype নেইফাইলের একদম শুরুতে <!doctype html>
violates nesting rulesযেটি পরে খুলেছেন, সেটি আগে বন্ধ করেননিবন্ধের ক্রম উল্টে দিন
No “p” element in scopeঅনাথ </p> — প্রায়ই p-এর ভেতরে div রাখার ফলp-কে div বানান, বা ভেতরের div-কে span
missing a required instance of child element “title”head-এ title নেইঅর্থবহ একটি <title> দিন
Duplicate IDএকই id দুবারএকটির নাম বদলান, বা id-এর বদলে class নিন
Trailing slash on void elements (Info)<br /> ধাঁচের স্ল্যাশ — ভুল নয়, শুধু তথ্যচাইলে স্ল্যাশ মুছে দিন

অভ্যাস গড়ুন: সবার আগে প্রথম error-টি ঠিক করুন, তারপর আবার যাচাই করুন — একটি ভুল প্রায়ই পরের দশটি “ভুল”-এর জন্ম দেয়। আর DevTools-এর Elements প্যানেল দিয়ে মিলিয়ে দেখুন ব্রাউজারের DOM আপনার ইচ্ছার সাথে মিলছে কি না। Validator নিয়ম যাচাই করে, DevTools দেখায় ফল — দুটো মিলিয়েই পূর্ণ ছবি।

১০ · AI-এর যুগে — সেকেন্ডে পাতা, কিন্তু যাচাই আপনার

আজ ChatGPT, Gemini বা Copilot-কে বললেই কয়েক সেকেন্ডে পুরো একটি পাতা লিখে দেয়। দারুণ সুবিধা — কিন্তু AI শিখেছে ইন্টারনেটের কোটি কোটি পাতা থেকে, যার বড় অংশই পুরোনো বা অগোছালো। তাই AI-এর HTML দেখতে ঠিক লাগলেও ভেতরে প্রায়ই পুরোনো অভ্যাস লুকিয়ে থাকে। এই পর্বের জ্ঞান দিয়েই আপনি সেগুলো ধরতে পারবেন।

AI যা প্রায়ই করেসমস্যাসঠিক পথ
বাংলা পাতায় <html lang="en">screen reader বাংলাকে ইংরেজি উচ্চারণে পড়েlang="bn"
সবকিছু <div> দিয়ে (“div-soup”)কাঠামোর অর্থ হারায়, অ্যাক্সেসিবিলিটি দুর্বলঅর্থবহ element (পর্ব ৪ ও ১০)
<center>, <font>, <br><br> দিয়ে ফাঁকাবহু আগে বাতিল বা ভুল উদ্দেশ্যে ব্যবহারনকশার কাজ CSS-এ
<meta http-equiv="X-UA-Compatible" content="IE=edge">বন্ধ হয়ে যাওয়া Internet Explorer-এর জন্য — আজ অর্থহীনমুছে দিন
একই id একাধিক জায়গায়লিংক, label আর JavaScript ভুল element ধরেid অনন্য; পুনরাবৃত্তির জন্য class
<div />, <p>…<div>…</div></p>ব্রাউজার ভিন্ন DOM বানায়validator দিয়ে ধরুন

AI-কে কাজ দেওয়ার সময় মান নির্দিষ্ট করে দিন — কোন ভাষা, কোন নিয়ম, কী চান না। নিচের prompt-টি কপি করে নিজের প্রয়োজনমতো বদলে নিন:

আমার একটি ছোট চায়ের দোকানের জন্য এক পাতার HTML ওয়েবসাইট লিখে দাও। শর্ত: ১. WHATWG HTML Living Standard মেনে বৈধ HTML — validator.w3.org-এ কোনো error থাকবে না। ২. প্রথম লাইনে <!doctype html>, <html lang="bn">, meta charset utf-8, viewport meta আর অর্থবহ title. ৩. div-soup নয় — যেখানে সম্ভব অর্থবহ element; একই id দুবার নয়। ৪. center, font বা IE-যুগের কোনো meta নয়; void element-এর শেষে স্ল্যাশ দিও না। ৫. কোড দেওয়ার পর প্রতিটি element কেন বেছে নিলে, সহজ বাংলায় এক লাইনে বলো।

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

AI লেখে দ্রুত, ব্রাউজার ক্ষমা করে নীরবে —
নিয়ম জানা মানুষই বোঝেন পাতার ভেতরে আসলে কী আছে।

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

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

প্র ০১ব্রাউজার ভুল HTML ক্ষমা করে কেন? কঠোর নিয়মের XHTML কেন জিততে পারল না?

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

২০০০ সালের দিকে W3C উল্টো পথ ধরল: XHTML — HTML-কে XML-এর কঠোর নিয়মে লেখা। XML-এ একটি ট্যাগ বন্ধ না করলেই পুরো পাতা বাতিল; ব্রাউজার শুধু একটি error বার্তা দেখায়। কাগজে এটি সুন্দর — নিখুঁত, যন্ত্রে পড়া সহজ। কিন্তু বাস্তবে প্রায় সবাই XHTML লিখে পাঠাতেন সাধারণ HTML হিসেবে (text/html), তাই ব্রাউজার সেটিকে ক্ষমাশীল HTML parser দিয়েই পড়ত — কঠোরতা কাগজেই থেকে গেল। আর যাঁরা সত্যিই XML হিসেবে পাঠাতেন, তাঁদের সাইটে একটি মন্তব্যে একটি ভাঙা ট্যাগ থাকলেই পুরো পাতা উধাও।

W3C যখন পুরোনো HTML-এর সাথে মেলে না এমন XHTML 2 নিয়ে এগোচ্ছিল, তখন ২০০৪ সালে Apple, Mozilla আর Opera মিলে গড়ে তোলে WHATWG. তাদের দর্শন ছিল বাস্তববাদী: ওয়েব যেমন আছে, তেমনভাবেই মেনে নিয়ে ভুলের মেরামতকেও নিয়মে বেঁধে ফেলো। সেখান থেকেই HTML5 আর তার বিস্তারিত parsing অ্যালগরিদম। ২০০৯ সালে W3C XHTML 2-এর কাজ বন্ধ করে, আর ২০১৯ সালে দুই সংস্থা একমত হয় যে WHATWG-এর Living Standard-ই HTML-এর মূল নিয়ম।

লক্ষ করুন, “ক্ষমা” মানে এখন আর এলোমেলো অনুমান নয় — প্রতিটি ভুলের ফল নির্দিষ্ট, সব ব্রাউজারে এক। কঠোরতা সরে গেছে অন্য জায়গায়: validator, linter আর DevTools-এ, যা ডেভেলপারকে সাবধান করে, পাঠককে শাস্তি দেয় না।

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

প্র ০২Quirks mode তো পুরোনো ভুলের নকল — তাহলে আজও ব্রাউজারগুলো এটি রেখে দিয়েছে কেন?

কারণ ওয়েবের সবচেয়ে বড় অলিখিত আইন: “ওয়েব ভাঙা যাবে না” (don't break the web). আজও লাখো পুরোনো পাতা চালু আছে — সরকারি নোটিশ, পুরোনো বিশ্ববিদ্যালয়ের সাইট, বছরের পর বছর কেউ হাত না দেওয়া ব্যবসার পাতা। এগুলোর অনেকগুলোতে doctype নেই। ব্রাউজার যদি হঠাৎ quirks mode বাদ দেয়, এই পাতাগুলোর লেআউট ভেঙে পড়বে, আর ব্যবহারকারী দোষ দেবেন ব্রাউজারকেই।

ইতিহাসটা মজার। ১৯৯০-এর দশকে Windows-এর Internet Explorer-এ একটি element-এর চওড়া (width) মাপা হতো padding আর border মিলিয়ে, অথচ CSS-এর নিয়ম বলত width মানে শুধু ভেতরের অংশ। পরে ব্রাউজারগুলো সঠিক নিয়মে যেতে চাইল, কিন্তু পুরোনো পাতা রক্ষাও জরুরি। সমাধান হিসেবে “doctype switching” — doctype দেখে ঠিক করা কোন নিয়মে আঁকা হবে — প্রথম চালু হয় Mac-এর জন্য Internet Explorer 5-এ (২০০০ সালের দিকে)। এরপর বাকি ব্রাউজারও এটি গ্রহণ করে। মজার ব্যাপার, সেই পুরোনো IE-র width-হিসাব পরে এতই কাজের প্রমাণিত হয় যে CSS-এ box-sizing: border-box দিয়ে সেটি ইচ্ছামতো চালু করার ব্যবস্থা এসেছে — পর্ব ১৯-এ দেখবেন।

আসলে mode তিনটি: no-quirks (standards), quirks, আর মাঝামাঝি limited-quirks (“almost standards”). শেষেরটি আসে কিছু পুরোনো ধাঁচের doctype থেকে; এতে প্রায় সব নিয়ম আধুনিক, শুধু টেবিলের ঘরে ছবির নিচে ফাঁক নিয়ে একটি পুরোনো আচরণ রাখা হয়েছে। এসব quirk আজ আর গোপন বা ব্রাউজার-ভিত্তিক নয় — WHATWG-এর আলাদা একটি “Quirks Mode Standard”-এ লিখে রাখা আছে, যাতে সব ব্রাউজার একইভাবে ভুল করে!

মূল উপলব্ধি: জনপ্রিয় প্ল্যাটফর্মে “পেছনের দিকে সামঞ্জস্য” (backward compatibility) প্রায় পবিত্র। ভুল একবার ছড়িয়ে পড়লে সেটি মুছে ফেলা যায় না, শুধু আলাদা ঘরে রাখা যায় — আর এজন্যই প্রথম দিন থেকে সঠিক মান মেনে চলা এত দামি।

প্র ০৩HTML 4.01, XHTML, HTML5 — আর এখন “Living Standard”. HTML-এর version নম্বর হারিয়ে গেল কেন, এতে লাভ না ক্ষতি?

এক সময় HTML-এর সংস্করণ বের হতো নির্দিষ্ট বছর ধরে: ১৯৯৫ সালে HTML 2.0, ১৯৯৭-এ 3.2 আর 4.0, ১৯৯৯-এ 4.01, ২০০০-এ XHTML 1.0, আর বহু বছরের কাজের পর ২০১৪ সালে W3C-র HTML5. সমস্যা হলো, একটি সংস্করণ চূড়ান্ত হতে বছরের পর বছর লাগত, অথচ ব্রাউজারগুলো ততদিনে নতুন ফিচার চালু করে ফেলত। কাগজের মান আর বাস্তবের ব্রাউজার — দুটো আলাদা পথে হাঁটত।

WHATWG ২০১১ সালের দিকে সিদ্ধান্ত নেয় নম্বর বাদ দেওয়ার: HTML হবে একটি Living Standard — একটি জীবন্ত দলিল, যেখানে কোনো ফিচার যোগ হয় তখনই, যখন অন্তত দুটি ব্রাউজার-নির্মাতা সেটি বাস্তবায়নে আগ্রহী। ভুল পেলে সংশোধন হয় সঙ্গে সঙ্গে। আজ <dialog> বা popover-এর মতো ফিচার (পর্ব ১১) এভাবেই ধাপে ধাপে মানে ঢুকেছে।

কিন্তু তাহলে ডেভেলপার কীভাবে জানবেন কোন ফিচার ব্যবহার করা নিরাপদ? “HTML5 সাপোর্ট করে কি না” — এই প্রশ্ন এখন অর্থহীন। এর জায়গা নিয়েছে প্রতিটি ফিচারের আলাদা হিসাব: Baseline. কোনো ফিচার সব প্রধান ব্রাউজারে (Chrome, Edge, Firefox, Safari) চলে এলে তা “Baseline Newly available”, আর তার প্রায় আড়াই বছর পর “Widely available” — তখন নিশ্চিন্তে ব্যবহার করা যায়। MDN আর Can I use-এ প্রতিটি ফিচারের পাশে এই চিহ্ন দেখবেন।

লাভ: মান আর বাস্তব একসাথে চলে, নতুন ফিচার দ্রুত আসে। ক্ষতি: “একটা বই পড়ে সব শিখে ফেলব” — এমন স্থির রেখা আর নেই; পুরোনো বই বা টিউটোরিয়ালে (আর তাদের থেকে শেখা AI-তে) বাতিল ফিচার থেকে যায়। তাই উৎস দেখার অভ্যাস — MDN, স্পেসিফিকেশন, Can I use — আজকের ওয়েব ডেভেলপারের মৌলিক দক্ষতা।

মূল উপলব্ধি: প্রশ্নটা “কোন version?” থেকে বদলে হয়েছে “এই ফিচারটি আমার ব্যবহারকারীদের ব্রাউজারে চলে কি?” — ফিচার ধরে ভাবা, সংখ্যা ধরে নয়।

প্র ০৪একই id দুটি element-এ দিলে পাতা তো দিব্যি চলে — তাহলে “id অনন্য হতে হবে” নিয়মটি এত কড়া কেন?

দেখতে চলে, কারণ ব্রাউজার id-র নকল নিয়ে চেঁচামেচি করে না — আবারও সেই ক্ষমাশীলতা। কিন্তু id-র ওপর নির্ভর করে অনেকগুলো ব্যবস্থা, আর প্রত্যেকে ধরে নেয় একটি id মানে ঠিক একটি element:

  • JavaScript: document.getElementById('price') সবসময় প্রথম মিলটি দেয়। দ্বিতীয় element-টি কোডের কাছে অদৃশ্য — বাগটি ধরা পড়ে অনেক পরে।
  • পাতার ভেতরে লিংক: #price লিংকে চাপলে ব্রাউজার প্রথমটিতে লাফায় (পর্ব ৫)।
  • ফর্ম আর অ্যাক্সেসিবিলিটি: <label for="phone"> id দিয়ে ইনপুটের সাথে জোড়া লাগে (পর্ব ৮)। ARIA-র অনেক attribute-ও id দিয়ে অন্য element দেখায়। নকল id থাকলে screen reader ভুল ঘরের নাম পড়ে — দৃষ্টিপ্রতিবন্ধী ব্যবহারকারী ফোন নম্বরের ঘরে লিখে ফেলেন জন্মতারিখ।
  • CSS: #price selector দুটোকেই ধরে — ফলে “CSS-এ তো চলছে” ভেবে ভুল আরও লুকিয়ে যায়। আর id selector-এর জোর (specificity) অনেক বেশি, যা পরে মাথাব্যথার কারণ হয় (পর্ব ১৮)।

আরেকটি পুরোনো ঐতিহ্য আছে: id-ওয়ালা element ব্রাউজারে window-এর একটি property-ও হয়ে যায় — id="demo" থাকলে JavaScript-এ সরাসরি demo লিখলেই element পাওয়া যায়। এটি পুরোনো IE-যুগের অভ্যাস, মানে টিকে আছে শুধু পুরোনো পাতার জন্য; এর ওপর ভরসা করা বিপজ্জনক, কারণ নামের সংঘাতে অদ্ভুত বাগ হয়।

বাস্তব নিয়ম: id ব্যবহার করুন কম — শুধু যেখানে সত্যিই একটি নির্দিষ্ট element-কে চেনাতে হবে (label, লিংকের গন্তব্য, JavaScript-এর একক লক্ষ্য)। নকশার জন্য class. এই পর্বের validator-ও “Duplicate ID” ধরতে পারে।

মূল উপলব্ধি: “চলছে” আর “ঠিক আছে” এক জিনিস নয়। কোনো নিয়ম ভাঙলে তাৎক্ষণিক শাস্তি না এলেও, যে ব্যবস্থাগুলো সেই নিয়মের ওপর দাঁড়িয়ে আছে, তারা নীরবে ভুল করতে শুরু করে।

প্র ০৫বাংলা পাতায় lang="bn" না দিলে লেখা তো ঠিকই দেখা যায় — এই ছোট attribute আসলে কার কাজে লাগে?

চোখে দেখে পড়া মানুষের কাছে পার্থক্যটা প্রায় অদৃশ্য — আর ঠিক এ কারণেই নিয়মটি সবচেয়ে বেশি উপেক্ষিত হয়। কিন্তু পাতার “পাঠক” শুধু চোখ নয়:

  • Screen reader: দৃষ্টিপ্রতিবন্ধী মানুষ NVDA, JAWS, TalkBack বা VoiceOver দিয়ে পাতা শোনেন। lang দেখে এরা ঠিক করে কোন ভাষার কণ্ঠ (speech synthesizer) ব্যবহার করবে। ভুল বা অনুপস্থিত হলে বাংলা লেখা ইংরেজি উচ্চারণের নিয়মে পড়া হতে পারে — শোনায় অর্থহীন।
  • অনুবাদ আর সার্চ: ব্রাউজারের অনুবাদ-ফিচার আর সার্চ ইঞ্জিন lang থেকে পাতার ভাষা সম্পর্কে ইঙ্গিত পায়।
  • টাইপোগ্রাফি: শব্দ-ভাঙা (hyphenation), উদ্ধৃতি-চিহ্ন, কখনো ফন্ট বাছাই ভাষার ওপর নির্ভর করে। CSS-এ :lang(bn) দিয়ে শুধু বাংলা অংশে আলাদা ফন্ট বা লাইনের উচ্চতা দেওয়া যায় — বাংলার যুক্তাক্ষর আর কার-চিহ্নের জন্য প্রায়ই একটু বেশি লাইন-উচ্চতা লাগে (পর্ব ১৪ ও ২১)।

অ্যাক্সেসিবিলিটির আন্তর্জাতিক নির্দেশিকা WCAG-এ এটি স্পষ্ট শর্ত: পুরো পাতার ভাষা জানানো (Success Criterion 3.1.1, Level A — সবচেয়ে মৌলিক স্তর), আর পাতার ভেতরে অন্য ভাষার অংশ থাকলে সেটিও জানানো (3.1.2, Level AA). বাংলাদেশসহ অনেক দেশে সরকারি ও ব্যাংকিং সেবা অনলাইনে আসছে; ভালো অ্যাক্সেসিবিলিটি এখন আর ভালো-লাগার বিষয় নয়, অনেক প্রতিষ্ঠানের ক্ষেত্রে নীতিগত বা আইনি প্রত্যাশা।

মান কেমন হবে? bn (বাংলা) যথেষ্ট; দেশ বোঝাতে bn-BD বা bn-IN লেখা যায় — এগুলো BCP 47 নামের আন্তর্জাতিক ভাষা-কোড নিয়ম মেনে চলে। ইংরেজি বাক্য থাকলে সেই element-এ lang="en".

মূল উপলব্ধি: HTML শুধু চোখের জন্য লেখা হয় না — যন্ত্র, সহায়ক প্রযুক্তি আর ভবিষ্যতের অজানা টুলও আপনার পাতার পাঠক। ছোট্ট একটি attribute অনেক মানুষের অভিজ্ঞতা বদলে দিতে পারে।

অনুশীলন

বেশিরভাগই দেখা আর ভাবার কাজ — একটিতে শুধু ভুল কোড ঠিক করতে হবে।

  1. Source বনাম DOM: নিজের কম্পিউটারে একটি ফাইলে শুধু এটুকু লিখে সেভ করুন: <table><tr><td>চাল</td></tr></table>. ব্রাউজারে খুলে প্রথমে Ctrl+U, তারপর DevTools-এর Elements প্যানেল দেখুন। দুটোর মধ্যে কোন কোন element-এর পার্থক্য পেলেন?

    Source-এ হুবহু আপনার এক লাইন। কিন্তু DOM-এ দেখবেন html, head, body — তিনটিই parser নিজে বানিয়েছে — আর table ও tr-এর মাঝে একটি tbody, যা আপনি লেখেননি। টেবিলের সারি সবসময় একটি table section-এর (tbody, thead বা tfoot) ভেতরে থাকে, তাই না লিখলে parser নিজে tbody যোগ করে। এই কারণে CSS-এ table > tr লিখলে কাজ করে না — DOM-এ tr আসলে tbody-র child. (টেবিল নিয়ে বিস্তারিত পর্ব ৭-এ।)

  2. ভুল কোড মেরামত: নিচের পাতায় অন্তত ছয়টি সমস্যা আছে। খুঁজে বের করে সঠিক পাতা লিখুন: <HTML><head><title>আমার প্রোফাইল<body><h1>তানিয়া আক্তার</h2><p>আমি <b><i>ওয়েব ডেভেলপার</b></i> হতে চাই<p><div>দক্ষতা: HTML</div></p>

    সমস্যাগুলো: (১) doctype নেই; (২) lang নেই, আর বড় হাতের HTML বৈধ হলেও প্রচলনবিরোধী; (৩) charset meta নেই; (৪) <title> বন্ধ হয়নি — ফলে পুরো বাকি লেখাই title-এর ভেতরে টেক্সট হয়ে যাবে, পাতা থাকবে খালি! (৫) <h1> খুলে </h2> দিয়ে বন্ধ; (৬) b-i-এর ভুল ক্রম; (৭) p-এর ভেতরে div. সঠিক রূপ (এডিটরে বদলে দেখুন):

    <!doctype html>
    <html lang="bn">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>আমার প্রোফাইল</title>
    </head>
    <body>
      <h1>তানিয়া আক্তার</h1>
      <p>আমি <b><i>ওয়েব ডেভেলপার</i></b> হতে চাই।</p>
      <div>দক্ষতা: HTML</div>
    </body>
    </html>

    প্রিভিউতে শিরোনাম, এক লাইনের অনুচ্ছেদ (“ওয়েব ডেভেলপার” মোটা ও বাঁকা) আর দক্ষতার লাইন। মজার পরীক্ষা: </title> মুছে দিন — পাতা পুরো সাদা হয়ে যাবে, কারণ parser বাকি সব লেখাকে title-এর টেক্সট ভেবে নেয়। তারপর validator-এ এই সঠিক কোডটি পেস্ট করে নিশ্চিত হোন শূন্য error.

  3. Validator-এর ভবিষ্যদ্বাণী: কোডটি validator.w3.org-এ পেস্ট করার আগে খাতায় লিখুন কোন বার্তাগুলো আসবে: <!doctype html><html lang="bn"><head><meta charset="utf-8"></head><body><p id="a">এক</p><p id="a">দুই</p><br/></body></html>. তারপর মিলিয়ে দেখুন।

    তিন ধরনের বার্তা আশা করুন: (১) Error — head-এ title নেই (“missing a required instance of child element title” ধাঁচের); (২) Error — Duplicate ID “a”; (৩) Info — <br/>-এর শেষের স্ল্যাশের কোনো প্রভাব নেই। লক্ষ করুন, ব্রাউজারে পাতাটি দিব্যি দেখায় — এজন্যই চোখের দেখা নয়, validator দিয়ে যাচাই। Viewport meta না থাকায় validator কিছু বলবে না — কারণ এটি নিয়মের বাধ্যবাধকতা নয়, ভালো অভ্যাস। সব ভালো অভ্যাস validator ধরে না; Lighthouse-এর মতো টুল সেই ঘাটতি পূরণ করে।

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

    শর্তহীন অনুরোধে প্রায়ই যা আসে: lang="en" (পাতা বাংলা হলেও), <meta http-equiv="X-UA-Compatible">-এর মতো IE-যুগের লাইন, শিরোনাম আর অনুচ্ছেদের বদলে div, কখনো inline style-এর ছড়াছড়ি। সাধারণত validator error কমই থাকে — AI ব্যাকরণে ভালো — কিন্তু ভাষা, অর্থবহ কাঠামো আর আধুনিকতায় দুর্বলতা থাকে। নির্দিষ্ট শর্তওয়ালা prompt-এ ফল চোখে পড়ার মতো ভালো হয়। শিক্ষা: AI-এর মান অনেকটাই আপনার প্রশ্নের মানের ওপর নির্ভর করে, আর প্রশ্নের মান নির্ভর করে আপনি নিয়ম কতটা জানেন তার ওপর।

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

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

ক্রমএকটি HTML ফাইলে লাইনগুলো ওপর থেকে নিচে যে ক্রমে আসে, সেভাবে সাজান (▲▼ চেপে সরান)

  1. <!doctype html>
  2. <html lang="bn">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>…</title>
  6. <body>

নিচের কোনটি void element (যার content ও end tag থাকে না)?

  • <p>
  • <title>
  • <img>
  • <div>

HTML ফাইলের প্রথম লাইনে <!doctype html> লেখার মূল কাজ কী?

  • ব্রাউজারকে পাতার ভাষা জানানো
  • ব্রাউজারকে standards mode-এ পাতা আঁকতে বলা
  • অক্ষরের encoding UTF-8 জানানো
  • HTML-এর version নম্বর 5 জানানো

ব্রাউজার <p>এক<div>দুই</div>তিন</p> পড়লে DOM-এ কী দাঁড়ায়?

  • একটি p, যার ভেতরে div আর তিনটি লেখাই আছে
  • কিছুই দেখায় না, পুরো অংশ বাতিল
  • একটি p, একটি div, আর “তিন” div-এর ভেতরে
  • p (“এক”), div (“দুই”), p-ছাড়া লেখা “তিন”, আর একটি খালি p

<p>ঢাকা&nbsp;&nbsp;মেট্রো রেল</p> (“মেট্রো” আর “রেল”-এর মাঝে ছয়টি সাধারণ space) — পাতায় “মেট্রো” আর “রেল”-এর মাঝে কতগুলো ফাঁক দেখা যাবে?

  • একটি
  • দুটি
  • ছয়টি, যতগুলো লেখা হয়েছে
  • একটিও না — শব্দ দুটি জোড়া লেগে যাবে

<p hidden="false">অফার</p> — পাতায় কী দেখা যাবে?

  • “অফার” লেখাটি, কারণ মান false
  • একটি error বার্তা
  • কিছুই না — element লুকানোই থাকবে
  • ধূসর রঙে “অফার”

id আর class সম্পর্কে কোন কথাটি সঠিক?

  • একটি class পুরো পাতায় একবারই ব্যবহার করা যায়
  • id পাতায় অনন্য হবে; একই class অনেক element-এ দেওয়া যায়
  • id শুধু div-এ, class শুধু p-এ দেওয়া যায়
  • id-এর মান বড়-ছোট হাতের অক্ষর মানে না

শব্দকোষ

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

মনে রাখুন

  1. Tag চিহ্ন, element পুরো জিনিস, attribute start tag-এর ভেতরে বাড়তি তথ্য; void element-এর (br, img, meta…) end tag নেই।
  2. যেটি পরে খুলেছেন, সেটি আগে বন্ধ করুন — HTML থেকে ব্রাউজার বানায় DOM tree (parent, child, sibling).
  3. কঙ্কাল: <!doctype html> → <html lang="bn"> → head (charset, viewport, title) → body. Doctype না দিলে quirks mode.
  4. ব্রাউজার ভুল HTML নির্দিষ্ট নিয়মে মেরামত করে — আপনার ইচ্ছামতো নয়। যাচাই করুন validator.w3.org আর DevTools দিয়ে।
  5. Whitespace গলে একটি হয়; নাম ছোট হাতে, মান ডাবল quote-এ; id অনন্য, class দলের নাম, hidden থাকলেই লুকানো।

পরের পর্বে: কঙ্কাল তৈরি — এবার তাতে মাংস লাগানোর পালা। heading-এর ছয় স্তর, অনুচ্ছেদ, আর strong বনাম b-এর মতো element কেন “দেখতে কেমন” নয়, “অর্থ কী” দিয়ে বাছতে হয় — পর্ব ৪-এ।

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

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