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

মাইলস্টোন — কয়েক পাতার একটি পূর্ণ HTML ওয়েবসাইট

Milestone Project — Planning, Building & Validating a Multi-Page HTML Website

Taught in Bangla, this lesson is a milestone project combining lessons one to fourteen into a multi-page HTML website for a neighbourhood library. It plans goals, audience, sitemap, folders and file names, then builds home, about, services and schedule, and contact pages with shared header, nav and footer, data tables, a validated form, per-page title, description, canonical and Open Graph, and finishes with an accessibility checklist, validator and rubric.

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

  • একটি বাস্তব প্রতিষ্ঠানের জন্য সাইট পরিকল্পনা — লক্ষ্য, পাঠক, সাইটম্যাপ, ফোল্ডার আর ফাইলের নাম
  • পর্ব ১–১৪-এর সব কিছু জুড়ে চারটি পূর্ণ পাতা: হোম, আমাদের কথা, সেবা ও সময়সূচি, যোগাযোগ-ফর্ম
  • ওয়েবের জন্য লেখা, অর্থবহ alt, ডেটা টেবিল আর built-in validation-সহ ফর্ম
  • প্রতিটি পাতার আলাদা title, description, canonical আর Open Graph
  • অ্যাক্সেসিবিলিটি চেকলিস্ট, validator, একটি রুব্রিক আর নতুনদের সাধারণ ভুল — আর AI-এর বানানো সাইট যাচাই

১ · প্রজেক্ট: পাড়ার পাঠাগারের জন্য একটি ওয়েবসাইট

পর্ব ১ থেকে ১৪ পর্যন্ত আপনি টুকরো টুকরো শিখেছেন — heading, লিংক, ছবি, তালিকা, টেবিল, ফর্ম, semantic অংশ, অ্যাক্সেসিবিলিটি, meta আর বাংলা লেখা। এই মাঝপথের প্রজেক্টে সব টুকরো জুড়ে একটি পূর্ণ ওয়েবসাইট বানাবেন।

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

এই কয়েকটি বাক্যেই প্রজেক্টের পুরো brief আছে। কোড লেখার আগে সেটি তিন ভাগে লিখে নিন:

লক্ষ্য

সময়, ফি, ঠিকানা — এক জায়গায়। আর অনলাইনে সদস্য হওয়ার আবেদন।

সফলতার মাপ: ফোনে প্রশ্ন কমা

পাঠক কারা

শিক্ষার্থী, অভিভাবক, বয়স্ক পাঠক — বেশিরভাগ কম দামি ফোনে, ধীর মোবাইল ডেটায়; কেউ কেউ screen reader-এ।

হালকা, পরিষ্কার, অ্যাক্সেসিবল

সীমাবদ্ধতা

বাজেট প্রায় শূন্য, ডেটাবেস নেই, আপডেট করবেন স্বেচ্ছাসেবীরা — তাই সরল HTML ফাইলের static site.

যত কম জটিলতা, তত ভালো
এই পর্বের নিয়ম

শুধু HTML — কোনো CSS নয়। সাইটটি দেখতে হবে ব্রাউজারের ডিফল্ট চেহারায় — ইচ্ছাকৃতভাবে। বাড়ি বানাতে আগে কলাম, বিম আর দেয়াল, রং পরে। কাঠামো ঠিক থাকলে CSS (পর্ব ১৬ থেকে) শুধু সাজায়। যে সাইট CSS ছাড়াই পুরোপুরি কাজ করে, সেটি ধীর নেটে আর screen reader-এ সবচেয়ে নির্ভরযোগ্য।

পুরো কাজটি ছয়টি ধাপে ভাগ করা যায়। “পরে” চাপুন — প্রতিটি ধাপের সিদ্ধান্ত আর সেটি এড়ালে কী ঝামেলা হয়, দেখুন:

  1. Briefকার জন্য?লক্ষ্য ও পাঠক
  2. সাইটম্যাপ৪টি পাতাকোন পাতায় কী
  3. ফোল্ডারabout.htmlনাম আর path
  4. কঙ্কালheader·main·footerসব পাতায় এক
  5. বিষয়বস্তুলেখা·ছবি·ফর্মপাতা ভরাট
  6. যাচাইvalidatorরুব্রিক ধরে
  1. Brief — কার জন্য, কেন। লক্ষ্য আর পাঠক না জানলে সব সিদ্ধান্ত আন্দাজে হয়। “বয়স্ক পাঠকও আছেন” — এই তথ্য থেকেই আসে সরল ভাষা আর পরিষ্কার লিংকের দাবি।
  2. সাইটম্যাপ — কয়টি পাতা, কোনটিতে কী। প্রতিটি পাতার একটি মূল কাজ। এই ধাপ বাদ দিলে একই তথ্য তিন পাতায় তিন রকম লেখা হয়।
  3. ফোল্ডার আর ফাইলের নাম। সব লিংক এই নামেই লেখা হবে। পরে নাম বদলালে প্রতিটি লিংক বদলাতে হয়, আর শেয়ার করা পুরোনো লিংক ভেঙে যায়।
  4. কঙ্কাল — সব পাতার একই ছাঁচ। doctype, head, skip link, header-nav, main, footer — একবার নিখুঁত করে তারপর বাকি পাতায় কপি।
  5. বিষয়বস্তু — লেখা, ছবি, টেবিল, ফর্ম। এখানে পর্ব ৪–১৪-এর সব কাজে লাগে।
  6. যাচাই — “চলছে” মানেই “ঠিক” নয়। validator, কি-বোর্ড, ফোন, বানান আর লিংক পরীক্ষা; শেষে রুব্রিক ধরে নিজের নম্বর (অংশ ১০)।

২ · সাইটম্যাপ, ফোল্ডার আর ফাইলের নাম

শপিং মলের লিফটের পাশের বোর্ডে লেখা থাকে কোন তলায় কী। সাইটম্যাপ ওয়েবসাইটের সেই বোর্ড — কয়টি পাতা, কোনটি কার নিচে, কোনটি কোন প্রশ্নের উত্তর দেয়। এই চিন্তার পোশাকি নাম information architecture. পাঠাগারের জন্য চারটি পাতাই যথেষ্ট:

শাপলা গণপাঠাগার — সাইটম্যাপ
পাতা (মেনুর নাম)ফাইলপাঠকের যে প্রশ্নের উত্তরমূল HTML
হোমindex.htmlএটা কী, আমার কাজে লাগবে কি?h1, ছোট পরিচিতি, খবরের তালিকা
আমাদের কথাabout.htmlকারা চালায়, বিশ্বাস করা যায় কি?লেখা, figure + alt, তালিকা
সেবা ও সময়services.htmlকখন খোলা, কত টাকা?ul, table, dl
যোগাযোগcontact.htmlকোথায়, কীভাবে সদস্য হব?address, form, label

মেনুর নাম “Services” নয়, “সেবা ও সময়” — লেবেল লিখুন পাঠকের ভাষায়, প্রতিষ্ঠানের ভেতরের ভাষায় নয়।

ফোল্ডারের গঠন

ছোট সাইটে সব HTML পাতা একই ফোল্ডারে রাখাই সহজ — তাহলে লিংক হয় শুধু ফাইলের নাম দিয়ে (পর্ব ৫-এর relative URL). ছবি আলাদা images ফোল্ডারে:

shapla-library/
├── index.html        ← হোম (ফোল্ডারের ঠিকানায় এটাই খোলে)
├── about.html        ← আমাদের কথা
├── services.html     ← সেবা ও সময়সূচি
├── contact.html      ← যোগাযোগ ও ফর্ম
├── images/
│   ├── logo.svg
│   ├── favicon.svg
│   ├── reading-room.jpg
│   └── og-cover.jpg  ← শেয়ার করার ছবি, 1200×630
└── css/              ← আপাতত খালি; পর্ব ১৬ থেকে style.css

ফাইলের নামের পাঁচ নিয়ম

  • ছোট হাতের অক্ষর। বেশিরভাগ সার্ভার Linux-এ চলে, যেখানে নাম case-sensitive — About.html আর about.html আলাদা ফাইল।
  • ফাঁকা জায়গা নয়, হাইফেন। about us.html URL-এ হয় about%20us.html. হাইফেন দিন — kebab-case: membership-form.html.
  • ইংরেজি অক্ষর। বাংলা নাম শেয়ারের সময় percent-encoding-এ লম্বা অক্ষরের সারি হয়ে যায়। লেখা বাংলায়, নাম ইংরেজিতে।
  • হোম পাতা মানেই index.html. শুধু ডোমেইন বা ফোল্ডারের ঠিকানায় সার্ভার এটিই খোঁজে।
  • নাম বলবে বিষয়, ক্রম নয়। page2.html নয়, services.html.

ব্রাউজার লিংক থেকে আসল ঠিকানা কীভাবে বানায়, আর নতুনরা কোথায় আটকান — “পরে” চাপুন:

ধাপ ১পাতা থেকে পাতায়
এখন খোলা: https://shapla-library.example/index.html
<a href="about.html">আমাদের কথা</a>
ধাপ ২ছবি আলাদা ফোল্ডারে
এখন খোলা: https://shapla-library.example/about.html
<img src="images/reading-room.jpg" alt="…">
ধাপ ৩বড় হাতের অক্ষরের ফাঁদ
সার্ভারে আছে: About.html
<a href="about.html">আমাদের কথা</a>
ধাপ ৪নামে ফাঁকা জায়গা
ফাইলের নাম: about us.html
<a href="about us.html">আমাদের কথা</a>
ধাপ ৫ডাবল-ক্লিক করে খোলা ফাইলে “/”
এখন খোলা: file:///C:/Users/Rumana/shapla-library/index.html
<a href="/about.html">আমাদের কথা</a>
  1. পাতা থেকে পাতায়। about.html-এর শুরুতে কোনো / বা https:// নেই, তাই ব্রাউজার ধরে নেয় “এখন যে ফোল্ডারে আছি, সেখানেই খোঁজো”। বর্তমান ঠিকানার শেষ অংশ (index.html) সরিয়ে নতুন নাম বসায়।
  2. ভেতরের ফোল্ডার। images/reading-room.jpg মানে “বর্তমান ফোল্ডারের ভেতরে images, তার ভেতরে ফাইলটি”। চার পাতাই এক জায়গায় বলে সবখানে একই path চলে।
  3. অক্ষরের ছোট-বড়। ফাইলের নাম About.html, লিংকে about.html. আপনার Windows ল্যাপটপে পাতা খুলবে, কারণ Windows-এর ফাইল সিস্টেম ছোট-বড় অক্ষর আলাদা ধরে না। কিন্তু Linux সার্ভারে তুললেই 404. তাই নিয়ম — সব নাম ছোট হাতের।
  4. ফাঁকা জায়গা। URL-এ ফাঁকা জায়গা রাখা যায় না, ব্রাউজার সেটিকে %20 বানিয়ে নেয়। লিংক চলে, কিন্তু কোনো অ্যাপ ফাঁকা জায়গায় লিংক কেটে দিলে ভাঙে।
  5. “/” দিয়ে শুরু। Root-relative লিংক /about.html মানে “সাইটের একদম গোড়া থেকে”। সার্ভারে গোড়া হলো ডোমেইন, তাই সেখানে ঠিক চলে। কিন্তু ফাইল ডাবল-ক্লিক করে খুললে ঠিকানা হয় file://, আর তখন “গোড়া” মানে পুরো C ড্রাইভ! এই প্রজেক্টে তাই শুধু ফাইলের নাম দিয়ে relative লিংক — অথবা VS Code-এর একটি local server দিয়ে পাতা খুলুন (পর্ব ২)।

আরও গভীরে: relative লিংক থেকে পূর্ণ ঠিকানা বানানোর নিয়ম লেখা আছে WHATWG-এর URL Standard-এ: ব্রাউজার পাতার “base URL” নিয়ে তার শেষ অংশ ফেলে দেয়, তারপর .. আর . অংশগুলো হিসাব করে। আর “ফোল্ডারের ঠিকানা লিখলে index.html খোলে” — এটা ব্রাউজারের নয়, সার্ভারের নিয়ম (Apache-এ DirectoryIndex, Nginx-এ index নির্দেশ)। এজন্যই অনেক সাইট /about/ ধরনের “সুন্দর” ঠিকানা দেয় — ভেতরে আসলে about/index.html নামের একটি ফাইল।

৩ · সব পাতার একই কঙ্কাল — আর বারবার ফেরা header, nav, footer

চারটি পাতার বিষয় আলাদা, কাঠামো এক। পর্ব ১০-এর semantic অংশ দিয়ে: প্রথমে একটি skip link, তারপর <header> (নাম আর মেনু), একটিমাত্র <main>, শেষে <footer>. screen reader এগুলোকে landmark হিসেবে চেনে।

নিচে পুরো হোম পাতা, doctype থেকে </html>. মনে রাখুন: প্রিভিউ একটিমাত্র ডকুমেন্ট, তাই এই পর্বের কোনো এডিটরে মেনুর লিংকে (about.html ইত্যাদি) ক্লিক করলে অন্য পাতা খুলবে না — প্রিভিউর নিচে শুধু লেখা আসবে কোন লিংকে ক্লিক হলো। skip link (#main) পাতার ভেতরেই লাফ দেয়, তাই সেটি কাজ করবে।

<!doctype html>
<html lang="bn">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>শাপলা গণপাঠাগার — উত্তরপাড়া, বগুড়া</title>
  <meta name="description" content="উত্তরপাড়ার শাপলা গণপাঠাগার: ৮ হাজারের বেশি বই, বিনা মূল্যে পড়ার ঘর আর শিশু কর্নার।">
</head>
<body>
  <a href="#main">সরাসরি মূল লেখায় যান</a>
  <header>
    <p><a href="index.html">শাপলা গণপাঠাগার</a></p>
    <nav aria-label="প্রধান মেনু">
      <ul>
        <li><a href="index.html" aria-current="page">হোম</a></li>
        <li><a href="about.html">আমাদের কথা</a></li>
        <li><a href="services.html">সেবা ও সময়</a></li>
        <li><a href="contact.html">যোগাযোগ</a></li>
      </ul>
    </nav>
  </header>
  <main id="main">
    <h1>পাড়ার বই, সবার জন্য</h1>
    <p>৮ হাজারের বেশি বই, নিরিবিলি পড়ার ঘর আর শিশুদের আলাদা কর্নার — শুক্রবার ছাড়া প্রতিদিন খোলা।</p>
    <h2>এই মাসের খবর</h2>
    <ul><li>প্রতি শনিবার বিকেল ৪টায় শিশুদের গল্পের আসর</li><li>নতুন এসেছে ১২০টি বই</li></ul>
  </main>
  <footer><p>শাপলা গণপাঠাগার, স্কুল রোড, উত্তরপাড়া · ফোন: <a href="tel:+8801700000000">০১৭০০-০০০০০০</a></p></footer>
</body>
</html>

ওপরে লিংক “সরাসরি মূল লেখায় যান”, তারপর সাইটের নাম, বুলেটসহ চারটি মেনু লিংক, বড় h1, খবরের তালিকা আর নিচে ঠিকানা — CSS নেই বলে সব ওপর-নিচে। “আমাদের কথা”-য় ক্লিক করুন: নিচে লেখা আসবে লিংকে ক্লিক হয়েছে, কিন্তু পাতা বদলাবে না। চেষ্টা করুন: aria-current="page"-কে “হোম” থেকে সরিয়ে “যোগাযোগ”-এ বসান — চোখে কিছুই বদলাবে না, কিন্তু screen reader এখন যোগাযোগকে “বর্তমান পৃষ্ঠা” বলবে। এটা কি সত্যি? না — তাই প্রতিটি পাতায় এটি নিজের লিংকেই থাকা চাই।

সাইটের নামটি হোমে ফেরার লিংক — মানুষ এটা আশা করেন। <nav>-এর aria-label পরে ফুটারে আরেকটি মেনু এলে দুটিকে আলাদা করবে।

চারটি পাতা, চারটি কপি — সমস্যাটা কোথায়

header, nav আর footer চার পাতায় হুবহু এক (শুধু aria-current আলাদা)। HTML-এ “header ফাইলটি এখানে বসাও” বলার কোনো ট্যাগ নেই, তাই প্রতিটি ফাইলে কপি করতে হয়। চল্লিশ পাতায় কী হবে? “পরে” চাপুন:

নতুন মেনু আইটেম“অনুষ্ঠান” → events.html
partials/header.htmlheader একটিমাত্র জায়গায়
index.htmlনিজের header-এর কপি
about.htmlনিজের header-এর কপি
services.htmlনিজের header-এর কপি
contact.htmlনিজের header-এর কপি
৪টি পাতা, একই মেনুসব ঠিক আছে… আপাতত
contact.html-এ পুরোনো মেনুঅসংগতি — পাঠক বিভ্রান্ত
build → ৫টি পাতাএকবার বদলালেই সবখানে
  1. শুরুর অবস্থা। প্রতিটি ফাইলে header-এর নিজস্ব কপি — প্রোগ্রামারদের DRY নীতির উল্টো।
  2. নতুন পাতা “অনুষ্ঠান” যোগ হলো। চারটি ফাইল খুলে চারবার একই কাজ। index, about আর services ঠিক করলেন… তারপর চা খেতে উঠলেন।
  3. একটি ফাইল বাদ পড়ল। contact.html-এ পুরোনো মেনু রয়ে গেল — পাঠক ভাবেন “অনুষ্ঠান” পাতাটি নেই। WCAG-এর নিয়ম ৩.২.৩ (Consistent Navigation) চায় বারবার আসা মেনু সব পাতায় একই ক্রমে থাকুক।
  4. পেশাদার সমাধান — একটিমাত্র উৎস। header থাকে একটি ফাইলে (template). সার্ভার বা একটি static site generator প্রতিটি পাতায় সেটি বসিয়ে পূর্ণ HTML বানায়। ব্রাউজার শেষে সেই সরল HTML-ই পায়।

নিচের তিন লাইন শুধু চিনে রাখার জন্য — এগুলো সরল HTML নয়, কোনো টুল বা সার্ভার পড়ে আসল HTML বানায়:

<!-- Apache-এর Server Side Includes: সার্ভার পাতা পাঠানোর আগে ফাইলটি বসিয়ে দেয় -->
<!--#include virtual="/partials/header.html" -->

<?php include 'partials/header.php'; ?>   <!-- PHP সার্ভারে একই কাজ -->

{% include "header.njk" %}                <!-- Eleventy-র মতো SSG-তে, build-এর সময় -->

প্রথমটি Server Side Include, ওয়েবের শুরুর দিকের কৌশল। দ্বিতীয়টি PHP-র মতো সার্ভার-ভাষায় — WordPress-এর মতো CMS এভাবেই পাতা বানায়। তৃতীয়টি SSG-র: Jekyll, Hugo, Eleventy বা Astro আগেই সব পাতা বানিয়ে দেয়। HTML-এর নিজস্ব <template> আর Web Components পর্ব ৫২-এ, প্রকাশের কথা পর্ব ৫৩-এ। এই প্রজেক্টে আপাতত হাতে কপিই করুন, আর মেনু বদলালে VS Code-এর “Find in Files” (Ctrl+Shift+F) দিয়ে মিলিয়ে নিন সব ফাইলে বদল হলো কি না।

৪ · ওয়েবের জন্য লেখা আর ছবি — “আমাদের কথা” পাতা

ওয়েবে মানুষ পড়েন না, চোখ বুলিয়ে যান। ২০০৬ সালে Nielsen Norman Group চোখের চলাচল মেপে দেখিয়েছিল, অনেক পাঠক মোটামুটি ইংরেজি “F” অক্ষরের মতো করে চোখ বোলান — ওপরের দুই-এক লাইন, তারপর বাঁ দিক ধরে নিচে। তাই পত্রিকার খবরের মতো লিখুন: জরুরি কথা আগে, বিস্তারিত পরে — inverted pyramid.

  • প্রথম বাক্যেই মূল কথা। “আমাদের পাঠাগার একটি ঐতিহ্যবাহী প্রতিষ্ঠান যা…” নয় — “১৯৯৮ সালে ৩০০টি বই নিয়ে শুরু, আজ বিনা মূল্যে পড়ার ঘর।”
  • এক অনুচ্ছেদে এক কথা, ছোট বাক্য, সংখ্যা অঙ্কে (৩০০টি, ১৪ দিন)।
  • heading দিয়ে ভাগ, স্তর লাফ না দিয়ে: h1, তারপর h2, দরকারে h3.
  • লিংকের লেখাই বলবে কোথায় যাচ্ছি। “এখানে ক্লিক করুন” নয় — “যোগাযোগ পাতায় লিখুন”। screen reader ব্যবহারকারীরা প্রায়ই শুধু লিংকের তালিকা শোনেন; সেখানে দশটি “এখানে ক্লিক করুন” অর্থহীন (WCAG ২.৪.৪)।
  • বাংলা ইউনিকোডে, বানান এক রকম (পর্ব ১৪); ইংরেজি বাক্যে lang="en".

ছবি আর alt — ছবিটি না দেখলে কী হারাতেন?

ছবিটি না দেখলে পাঠক কোন তথ্য হারাতেন? সেটুকুই alt text (পর্ব ৬, ১২)। “ছবি” শব্দ লিখবেন না — screen reader নিজেই বলে। লোগো-লিংকের alt হবে গন্তব্য: “শাপলা গণপাঠাগার — হোম”। সাজের ছবিতে alt="". আর <figcaption> সবার জন্য বাড়তি তথ্য, alt-এর পুনরাবৃত্তি নয়।

<header><p><a href="index.html">শাপলা গণপাঠাগার</a></p>
  <nav aria-label="প্রধান মেনু"><ul>
    <li><a href="index.html">হোম</a></li> <li><a href="about.html" aria-current="page">আমাদের কথা</a></li>
    <li><a href="services.html">সেবা ও সময়</a></li> <li><a href="contact.html">যোগাযোগ</a></li>
  </ul></nav></header>
<main id="main">
  <h1>আমাদের কথা</h1>
  <p><strong>১৯৯৮ সালে পাড়ার কয়েকজন শিক্ষক আর শিক্ষার্থী মিলে ৩০০টি বই নিয়ে শাপলা গণপাঠাগার শুরু করেন।</strong> আজ এটি একটি স্বেচ্ছাসেবী কমিটির হাতে চলে।</p>
  <figure>
    <img src="images/reading-room.jpg" width="600" height="400"
         alt="জানালার পাশে লম্বা টেবিলে বসে কয়েকজন শিক্ষার্থী বই পড়ছে">
    <figcaption>বিকেলের পড়ার ঘর — পরীক্ষার মৌসুমে এখানে বসার জায়গা পাওয়াই কঠিন।</figcaption>
  </figure>
  <h2>আমরা যা বিশ্বাস করি</h2>
  <ul>
    <li>বই পড়া সবার অধিকার — সদস্য না হলেও পড়ার ঘরে বসা যায়।</li>
    <li>শিশুর প্রথম বইটি হোক আনন্দের, পরীক্ষার চাপের নয়।</li>
  </ul>
  <h2>পরিচালনা</h2>
  <p>প্রতি দুই বছরে সদস্যদের ভোটে ৭ জনের কমিটি নির্বাচিত হয়। স্বেচ্ছাসেবী হতে চাইলে <a href="contact.html">যোগাযোগ পাতায়</a> লিখুন।</p>
</main>
<footer><p>শাপলা গণপাঠাগার, স্কুল রোড, উত্তরপাড়া · ফোন: <a href="tel:+8801700000000">০১৭০০-০০০০০০</a></p></footer>

ছবির ফাইলটি এখানে নেই, তাই ছবির জায়গায় দেখবেন ভাঙা-ছবির চিহ্ন আর alt-এর লেখা — ভুল path-এ পাঠক এটাই দেখেন, আর screen reader সব সময় এটাই পড়ে। তার নিচে figcaption আর দুটি h2 অংশ। চেষ্টা করুন: alt-কে alt="ছবি" করে দেখুন — চোখে-না-দেখা পাঠক এখন কী জানলেন? কিছুই না। তারপর প্রথম অনুচ্ছেদটি পড়ুন শুধু মোটা অংশটুকু — শুধু ওটুকু পড়েই কি পাঠাগারের মূল পরিচয় পাওয়া যায়? এটাই inverted pyramid.

ফোনের ক্যামেরার ছবি সরাসরি নয়। ফোনে তোলা ছবি প্রায়ই কয়েক মেগাবাইট; ওয়েবে বড়জোর ১২০০–১৬০০ পিক্সেল চওড়া লাগে। ছোট করে WebP বা AVIF-এ রূপান্তর করুন (পর্ব ৬), আর width-height দিন, যাতে লেখা লাফিয়ে না সরে (layout shift). রেসপন্সিভ ছবি পর্ব ৩২-এ।

৫ · সেবা ও সময়সূচি — তালিকা, টেবিল আর dl ঠিক জায়গায়

সেবার পাতায় তিন রকম তথ্য, আর প্রতিটির জন্য পর্ব ৭-এর আলাদা কাঠামো। সেবাগুলো — কোনটি আগে লিখলাম তাতে কিছু যায় আসে না, তাই <ul>. খোলার সময় — প্রতিটি সময় বুঝতে দিন আর সেবা দুটোই জানতে হয়, অর্থাৎ সারি-কলামের সম্পর্ক, তাই একটি আসল data table. সদস্য ফি — নাম আর মানের জোড়া, তাই <dl>.

<header><p><a href="index.html">শাপলা গণপাঠাগার</a></p>
  <nav aria-label="প্রধান মেনু"><ul>
    <li><a href="index.html">হোম</a></li> <li><a href="about.html">আমাদের কথা</a></li>
    <li><a href="services.html" aria-current="page">সেবা ও সময়</a></li> <li><a href="contact.html">যোগাযোগ</a></li>
  </ul></nav></header>
<main id="main">
  <h1>সেবা ও সময়সূচি</h1>
  <ul>
    <li>পড়ার ঘর — সবার জন্য, বিনা মূল্যে</li>
    <li>বাড়িতে বই নেওয়া — একসাথে ২টি, ১৪ দিনের জন্য (শুধু সদস্য)</li>
  </ul>
  <table>
    <caption>খোলার সময় (শুক্রবার ও সরকারি ছুটির দিনে বন্ধ)</caption>
    <thead>
      <tr><th scope="col">দিন</th><th scope="col">পড়ার ঘর</th><th scope="col">বই নেওয়া-ফেরত</th></tr>
    </thead>
    <tbody>
      <tr><th scope="row">শনি – বুধ</th><td>সকাল ১০টা – রাত ৮টা</td><td>বিকেল ৩টা – ৭টা</td></tr>
      <tr><th scope="row">বৃহস্পতি</th><td>সকাল ১০টা – বিকেল ৫টা</td><td>বিকেল ৩টা – ৫টা</td></tr>
    </tbody>
  </table>
  <h2>সদস্য ফি</h2>
  <dl>
    <dt>সাধারণ সদস্য</dt><dd>বছরে ১২০ টাকা</dd>
    <dt>শিক্ষার্থী (পরিচয়পত্রসহ)</dt><dd>বছরে ৬০ টাকা</dd>
  </dl>
  <p><a href="contact.html">সদস্য হওয়ার ফর্ম পূরণ করুন</a></p>
</main>
<footer><p>শাপলা গণপাঠাগার, স্কুল রোড, উত্তরপাড়া · ফোন: <a href="tel:+8801700000000">০১৭০০-০০০০০০</a></p></footer>

টেবিলের ওপরে মাঝখানে caption, মোটা অক্ষরে কলামের নাম, আর প্রতিটি সারির শুরুতে মোটা অক্ষরে দিনের নাম — এগুলো th. খেয়াল করুন, কোনো দাগ বা ঘর নেই; CSS ছাড়া ব্রাউজার টেবিলের বর্ডার আঁকে না, কিন্তু কাঠামো পুরোপুরি আছে। ফির অংশে মানগুলো একটু ভেতরে সরানো — dl-এর ডিফল্ট চেহারা। চেষ্টা করুন: শনিবারের গল্পের আসরের সময় টেবিলে বসাতে চাইলে কোন কলামে বসবে? না মিললে ওটা তালিকায় থাকার কথা। আর scope="row" মুছে দিয়ে ভাবুন, screen reader এখন “বিকেল ৩টা – ৫টা” শোনালে সাথে “বৃহস্পতি” বলবে কি?

সময়সূচি ছবিতে নয়। Facebook-এ অনেকে খোলার সময় পোস্টারের ছবিতে জানান। ওয়েবসাইটে নয়: ছবির লেখা screen reader আর সার্চ ইঞ্জিন পড়তে পারে না, ফোনে জুম লাগে, আর সময় বদলালে নতুন ছবি বানাতে হয়। HTML টেবিল বদলাতে দশ সেকেন্ড।

৬ · যোগাযোগ পাতা — ফর্ম আর built-in validation

যোগাযোগ পাতার কেন্দ্রে একটি ফর্ম, পর্ব ৮ আর ৯-এর নিয়মে। আগে প্রশ্ন করুন: প্রতিটি ঘরের তথ্য দিয়ে আমরা কী করব? যে তথ্য কাজে লাগবে না, চাইবেন না — বাড়তি ঘর মানে ফর্ম ছেড়ে যাওয়ার কারণ, আর অপ্রয়োজনীয় ব্যক্তিগত তথ্য মানে বাড়তি দায়িত্ব।

  • প্রতিটি ঘরে একটি <label>, for আর id দিয়ে জোড়া। placeholder লেবেলের বিকল্প নয় — লিখতে শুরু করলেই মুছে যায়।
  • ঠিক type: tel-এ ফোনে সংখ্যার কি-বোর্ড, email-এ “@” যাচাই।
  • autocomplete: ব্রাউজার সেভ করা নাম, ফোন, ইমেইল নিজেই বসায় — বারবার টাইপ করাবেন না।
  • built-in validation: required, pattern, maxlength — ভুল থাকলে ব্রাউজার জমার আগেই জানায়। নিয়ম (যেমন ১১ অঙ্ক) আগেই লিখুন, আর aria-describedby দিয়ে ঘরের সাথে জুড়ুন।
<!-- header, nav আর footer অন্য পাতাগুলোর মতোই — জায়গা বাঁচাতে এখানে বাদ -->
<main id="main">
  <h1>যোগাযোগ ও সদস্য হওয়া</h1>
  <address>স্কুল রোড, উত্তরপাড়া, বগুড়া<br>ফোন: <a href="tel:+8801700000000">০১৭০০-০০০০০০</a></address>
  <h2>আমাদের লিখুন</h2>
  <form action="/api/contact" method="post">
    <p><label for="name">পুরো নাম</label>
      <input id="name" name="name" autocomplete="name" required></p>
    <p><label for="phone">মোবাইল নম্বর</label>
      <input id="phone" name="phone" type="tel" required
             pattern="01[3-9][0-9]{8}" autocomplete="tel" aria-describedby="phone-hint">
      <small id="phone-hint">১১ অঙ্ক, ইংরেজি অঙ্কে — যেমন 01712345678</small></p>
    <p><label for="email">ইমেইল (ঐচ্ছিক)</label>
      <input id="email" name="email" type="email" autocomplete="email"></p>
    <p><label for="topic">বিষয়</label>
      <select id="topic" name="topic" required>
        <option value="">— একটি বেছে নিন —</option>
        <option>সদস্য হতে চাই</option><option>বই দান করতে চাই</option><option>অন্য প্রশ্ন</option>
      </select></p>
    <p><label for="msg">বার্তা</label>
      <textarea id="msg" name="msg" rows="4" maxlength="500" required></textarea></p>
    <p><label><input type="checkbox" name="rules" required> পাঠাগারের নিয়ম পড়েছি ও মেনে চলব</label></p>
    <button type="submit">পাঠান</button>
  </form>
</main>

প্রথমে কিছু না লিখে “পাঠান” চাপুন — ব্রাউজার প্রথম খালি বাধ্যতামূলক ঘরে থেমে নিজের বার্তা দেখাবে, ফর্ম জমা হবে না। এবার সব ঘর পূরণ করুন, মোবাইলে লিখুন 01712345678 — জমা দিলে প্রিভিউর নিচে দেখবেন “ফর্ম জমা হতো → name=…, phone=…, topic=…, rules=on”. সত্যিকারের সাইটে এই তথ্য যেত action-এর ঠিকানায়। চেষ্টা করুন: মোবাইলে বাংলা অঙ্কে ০১৭১২৩৪৫৬৭৮ লিখুন — নম্বর ঠিক, তবু ব্রাউজার আটকাবে! কারণ [0-9] শুধু ইংরেজি অঙ্ক চেনে। বাংলা কি-বোর্ডের ব্যবহারকারীর জন্য এটা বাস্তব সমস্যা; অনুশীলন ৩-এ এর সমাধান দেখবেন।

দুটি কঠিন সত্য। এক, HTML-এর validation ব্যবহারকারীর সুবিধার জন্য, নিরাপত্তার জন্য নয় — DevTools-এ যে কেউ required মুছতে পারেন, প্রোগ্রাম দিয়ে ব্রাউজার ছাড়াই তথ্য পাঠানো যায়। তাই সার্ভারে আবার যাচাই (server-side validation) বাধ্যতামূলক। দুই, static site নিজে ফর্মের তথ্য রাখতে পারে না — action-এর ঠিকানায় একটি সার্ভার-প্রোগ্রাম বা ফর্ম গ্রহণের সেবা লাগে। action="mailto:…" অনেক ডিভাইসে চলে না — এড়িয়ে চলুন। সার্ভারের দিক এই কোর্সের বাইরে; প্রকাশের কথা পর্ব ৫৩-এ।

৭ · প্রতিটি পাতার head — শিরোনাম, বর্ণনা আর শেয়ারের কার্ড

<head>-এর তথ্য (পর্ব ১৩) দেখা যায় ব্রাউজারের ট্যাবে, সার্চের ফলাফলে আর শেয়ারের কার্ডে। বহু-পাতার সাইটে সবচেয়ে সাধারণ ভুল: চার পাতায় একই title আর description — সার্চে চারটি লিংক হুবহু এক দেখায়।

প্রতিটি পাতার নিজস্ব title আর description
ফাইল<title>meta description-এর মূল কথা
index.htmlশাপলা গণপাঠাগার — উত্তরপাড়া, বগুড়া৮ হাজারের বেশি বই, বিনা মূল্যে পড়ার ঘর, শিশু কর্নার
about.htmlআমাদের কথা | শাপলা গণপাঠাগার১৯৯৮ সালে শুরু, বিশ্বাস, স্বেচ্ছাসেবী কমিটি
services.htmlসেবা ও সময়সূচি | শাপলা গণপাঠাগারখোলার সময়, সদস্য ফি, প্রায়ই আসা প্রশ্ন
contact.htmlযোগাযোগ ও সদস্য হওয়া | শাপলা গণপাঠাগারঠিকানা, ফোন, অনলাইন আবেদন

title-এ আগে পাতার নাম, পরে সাইটের নাম — অনেক ট্যাব খোলা থাকলে শুরুটুকুই দেখা যায়। meta description পাতার নিজের সারাংশ — মোটামুটি ১৬০ অক্ষরের মধ্যে মূল কথা বলুন, বেশি লম্বা হলে ফলাফলে কেটে যায়। canonical বলে আসল ঠিকানা কোনটি। Open Graph ট্যাগ (Facebook ২০১০ সালে চালু করে) শেয়ারের কার্ডের শিরোনাম, বর্ণনা আর ছবি ঠিক করে; og:image-এ পূর্ণ ঠিকানা (absolute URL) লাগে, প্রচলিত মাপ ১২০০×৬৩০. ট্যাবের ছোট আইকন favicon. সেবার পাতার পূর্ণ head:

<!doctype html>
<html lang="bn">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>সেবা ও সময়সূচি | শাপলা গণপাঠাগার</title>
  <meta name="description" content="শাপলা গণপাঠাগারের খোলার সময়, সদস্য ফি আর প্রায়ই আসা প্রশ্ন।">
  <link rel="canonical" href="https://shapla-library.example/services.html">
  <link rel="icon" href="images/favicon.svg" type="image/svg+xml">
  <meta property="og:type" content="website">
  <meta property="og:site_name" content="শাপলা গণপাঠাগার">
  <meta property="og:title" content="সেবা ও সময়সূচি — শাপলা গণপাঠাগার">
  <meta property="og:description" content="শাপলা গণপাঠাগারের খোলার সময়, সদস্য ফি আর প্রায়ই আসা প্রশ্ন।">
  <meta property="og:url" content="https://shapla-library.example/services.html">
  <meta property="og:image" content="https://shapla-library.example/images/og-cover.jpg">
  <meta property="og:image:alt" content="পাঠাগারের পড়ার ঘর">
  <meta property="og:locale" content="bn_BD">
  <meta name="twitter:card" content="summary_large_image">
</head>

.example ডোমেইন উদাহরণের জন্য সংরক্ষিত — আসল সাইটে নিজের ডোমেইন বসাবেন (দেখুন ICT কোর্সের ডোমেইন-হোস্টিং পর্ব)।

দুটি “সাইটম্যাপ” গুলিয়ে ফেলবেন না। অংশ ২-এর সাইটম্যাপ মানুষের জন্য পরিকল্পনা। sitemap.xml হলো সার্চ ইঞ্জিনের জন্য সব পাতার ঠিকানার একটি যন্ত্র-পাঠ্য ফাইল — ২০০৫ সালে Google চালু করে, পরের বছর বড় সার্চ ইঞ্জিনগুলো একই নিয়ম মেনে নেয়। চার পাতার সাইটে জরুরি নয়, বড় সাইটে কাজের।

৮ · অ্যাক্সেসিবিলিটি চেকলিস্ট আর validator দিয়ে যাচাই

যিনি চোখে দেখেন না বা মাউস ধরতে পারেন না, তাঁর জন্যও কি সাইট চলছে? পর্ব ১২-এর অ্যাক্সেসিবিলিটি নীতিগুলো চেকলিস্টে, পাশে WCAG ২.২-এর নিয়মের নম্বর:

প্রজেক্টের অ্যাক্সেসিবিলিটি চেকলিস্ট
যা দেখবেনকীভাবে পরীক্ষা করবেনWCAG
প্রতিটি পাতায় lang="bn", ইংরেজি অংশে lang="en"কোড দেখে; screen reader-এ শুনে৩.১.১, ৩.১.২
প্রতিটি পাতার title আলাদা ও অর্থবহচারটি ট্যাব পাশাপাশি খুলে২.৪.২
একটি h1, heading-এর স্তর লাফ নেইDevTools বা heading-তালিকা দেখায় এমন এক্সটেনশনে১.৩.১, ২.৪.৬
skip link আছে, header/nav/main/footer landmark আছেTab চেপে প্রথমেই skip link আসে কি না২.৪.১
সব ছবিতে অর্থবহ alt, সাজের ছবিতে alt=""ছবি বন্ধ করে, বা validator-এ১.১.১
লিংকের লেখা নিজেই গন্তব্য বলেশুধু লিংকগুলো আলাদা পড়ে দেখুন২.৪.৪
ফর্মের প্রতিটি ঘরে label, নিয়ম আগেই লেখাlabel-এ ক্লিক করলে ঘরে কার্সর যায় কি না৩.৩.২, ১.৩.১
মাউস ছাড়া পুরো সাইট চালানো যায়শুধু Tab, Shift+Tab, Enter, Space২.১.১, ২.৪.৭
মেনু আর সাহায্যের তথ্য সব পাতায় একই ক্রমেচার পাতা পাশাপাশি তুলনা করে৩.২.৩, ৩.২.৬

নিয়ম ৩.২.৬ (Consistent Help) WCAG ২.২-এ নতুন: ফোন বা যোগাযোগের লিংকের মতো সাহায্যের পথ সব পাতায় একই জায়গায় থাকবে — আমাদের ফুটার ঠিক এটাই করে। সাথে চালান DevTools-এর Lighthouse রিপোর্ট আর Accessibility অংশ, আর একবার হলেও আসল screen reader — Windows-এ বিনা মূল্যের NVDA, Android-এ TalkBack.

validator.w3.org — HTML-এর ব্যাকরণ পরীক্ষক

W3C-র validator (Nu Html Checker) HTML-কে WHATWG-এর নিয়মে মিলিয়ে দেখে — ঠিকানা দিয়ে, ফাইল আপলোড করে বা কোড পেস্ট করে (“Validate by Direct Input”). চার পাতাই আলাদা করে পরীক্ষা করুন। মেসেজ পড়া শিখুন:

Errorছবিতে alt নেই
Error: An img element must have an alt attribute, except under certain conditions.
From line 14, column 5; to line 14, column 62
    <img src="images/kids-corner.jpg" width="300" height="200">
Errorবাড়তি বন্ধ-ট্যাগ
Error: Stray end tag div.
From line 22, column 3; to line 22, column 8
  </p>
  </div>
Errorলিংকের ভেতরে বোতাম
Error: The element button must not appear as a descendant of the a element.
    <a href="contact.html"><button>যোগাযোগ</button></a>
Warning · Infoerror নয়, তবু পড়ুন
Warning: Consider adding a lang attribute to the html start tag to declare the language of this document.

Info: Trailing slash on void elements has no effect and interacts badly with unquoted attribute values.
    <br />
সবুজ বার্তাচারটি পাতাতেই এটা চাই
Document checking completed. No errors or warnings to show.
  1. Error পড়ার ধরন। প্রথমে কী ভুল, তারপর লাইন-কলাম, নিচে কোডের সেই অংশ। alt না থাকা শুধু ব্যাকরণের ভুল নয় — screen reader-এ ছবির পুরো তথ্য হারানো।
  2. “Stray end tag”. শুরু নেই এমন একটি </div> — কপি-পেস্টে অংশ বাদ পড়লে হয়। ব্রাউজার চুপচাপ মানিয়ে নেয়, তাই চোখে পড়ে না। সবচেয়ে ওপরের error আগে ঠিক করুন — একটি ভুল থেকেই প্রায়ই নিচের দশটি আসে।
  3. নিয়মে নিষেধ, ব্রাউজারে “চলে”। <a>-এর ভেতরে <button> নিষেধ — কি-বোর্ডে দুবার থামতে হয়, screen reader বিভ্রান্ত হয়। লিংক হলে <a>, কাজের বোতাম হলে <button>.
  4. Warning আর Info. Warning মানে “নিয়ম ভাঙেনি, কিন্তু সম্ভবত ভুলে গেছেন” — যেমন lang. Info আরও হালকা: <br />-এর / HTML-এ কিছুই করে না (XHTML যুগের অভ্যাস, AI প্রায়ই দেয়)। Warning-ও শূন্যে নামান।
  5. সবুজ বার্তা। এর মানে শুধু ব্যাকরণ ঠিক। alt-এ “ছবি” লিখলেও validator খুশি। তাই validator প্রথম ধাপ, শেষ নয় — তারপর চেকলিস্ট আর কি-বোর্ড।

নিচে নতুনদের একটি সাধারণ ভুলে-ভরা অংশ, সাথে একটি ছোট্ট <script> পরীক্ষক, যা কয়েকটি সমস্যা খুঁজে প্রিভিউর নিচে লেখে। আপনার কাজ: HTML ঠিক করে সংখ্যা শূন্যে নামানো। script-এ হাত দেবেন না (JavaScript আর HTML-এর মিলন পর্ব ৫২-এ)।

<div class="header"><b>শাপলা গণপাঠাগার</b>
  <div class="menu">হোম | আমাদের কথা | যোগাযোগ</div></div>
<h3>শিশু কর্নার</h3>
<img src="images/kids-corner.jpg" width="300" height="200">
<p>নতুন বইয়ের তালিকা পেতে <a href="services.html">এখানে ক্লিক করুন</a></p>
<p>নাম: <input name="name" placeholder="আপনার নাম"></p>
<a href="contact.html"><button>যোগাযোগ</button></a>

<script>
{ // ছোট্ট পরীক্ষক — কোড বদলালেই আবার চলে
  const issues = [];
  const heads = [...document.querySelectorAll('h1, h2, h3, h4, h5, h6')];
  if (document.querySelectorAll('h1').length !== 1) issues.push('h1 ঠিক একটি থাকা চাই');
  heads.forEach((h, i) => {
    const lv = +h.tagName[1], prev = i ? +heads[i - 1].tagName[1] : 0;
    if (lv > prev + 1) issues.push('heading-এর ধাপ লাফ: ' + h.tagName + ' (' + h.textContent + ')');
  });
  document.querySelectorAll('img:not([alt])').forEach(im => issues.push('alt নেই: ' + im.getAttribute('src')));
  document.querySelectorAll('input, select, textarea').forEach(f => {
    if (!f.labels.length) issues.push('label নেই: ' + f.name);
  });
  document.querySelectorAll('a').forEach(a => {
    if (/এখানে ক্লিক/.test(a.textContent)) issues.push('অস্পষ্ট লিংক: ' + a.textContent);
  });
  if (document.querySelector('a button, button a')) issues.push('লিংকের ভেতরে button');
  if (!document.querySelector('nav')) issues.push('nav নেই — মেনু চেনা যাবে না');
  console.log(issues.length ? issues.length.toLocaleString('bn-BD') + 'টি সমস্যা:\n' + issues.join('\n') : 'কোনো সমস্যা পাওয়া যায়নি');
}
</script>

শুরুতে প্রিভিউর নিচে আসবে “৭টি সমস্যা” — h1 নেই, h3 দিয়ে শুরু, ছবিতে alt নেই, ইনপুটের label নেই, “এখানে ক্লিক করুন” লিংক, লিংকের ভেতরে button, আর কোনো nav নেই। একে একে ঠিক করুন: div class="header"-কে <header> করুন আর মেনুটিকে <nav><ul>-এ আসল লিংক দিয়ে লিখুন; <h3>-এর আগে একটি <h1> দিন আর h3-কে h2 করুন; ছবিতে alt; ইনপুটে <label for> আর id; লিংকের লেখা “নতুন বইয়ের তালিকা দেখুন”; আর বোতামটি সরিয়ে শুধু লিংক রাখুন। প্রতিবার সংখ্যা কমবে, শেষে “কোনো সমস্যা পাওয়া যায়নি”। এই পরীক্ষক মাত্র কয়েকটি জিনিস দেখে — আসল validator আর আপনার চোখ অনেক বেশি ধরে।

৯ · AI-এর যুগে — পুরো সাইট AI-কে দিয়ে বানালে কী দেখবেন

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

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

AI-এর ভুলকেন সমস্যাঠিক উপায়
সব কিছু <div> দিয়ে (div-soup)landmark নেই, screen reader-এ পাতা একটি লম্বা দেয়ালheader, nav, main, footer, section
চার পাতায় একই title আর descriptionসার্চে আর ট্যাবে পাতা আলাদা করা যায় নাপ্রতিটি পাতার নিজস্ব head
বানানো ঠিকানা, ফোন নম্বর, “পাঠকের মতামত”মিথ্যা তথ্য — আসল মানুষ ভুল নম্বরে ফোন করবেনপ্রতিটি তথ্য ক্লায়েন্টের কাছ থেকে নিন
<a><button>, div onclick-এ মেনুঅবৈধ HTML, কি-বোর্ডে চলে নাশুধু <a href>
alt="image", alt="photo1"কোনো তথ্য দেয় নাছবির অর্থ লিখুন, সাজের ছবিতে alt=""
C:\Users\… বা file:/// pathশুধু AI-এর কল্পনার কম্পিউটারে চলেrelative path

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

তুমি একজন অ্যাক্সেসিবিলিটি-সচেতন ফ্রন্ট-এন্ড ডেভেলপার। একটি পাড়ার পাঠাগারের জন্য চার পাতার static ওয়েবসাইট বানাও: index.html, about.html, services.html, contact.html. শর্ত: ১. শুধু HTML, কোনো CSS বা JavaScript নয়। সব পাতা একই ফোল্ডারে, শুধু relative লিংক। ২. প্রতিটি পাতায় lang="bn", নিজস্ব title ও meta description, canonical আর Open Graph ট্যাগ (ডোমেইন: shapla-library.example). ৩. প্রতিটি পাতায় skip link, header-এ nav (aria-label সহ), বর্তমান পাতার লিংকে aria-current="page", একটি main আর একটি h1, শেষে footer — চার পাতায় মেনু হুবহু একই ক্রমে। ৪. services.html-এ খোলার সময়ের টেবিল: caption, thead, th scope="col" ও scope="row". ফি dl-এ। ৫. contact.html-এ ফর্ম: প্রতিটি ঘরে label, ঠিক type ও autocomplete, মোবাইলে বাংলাদেশি ১১ অঙ্কের pattern, নিয়মের লেখা aria-describedby দিয়ে জোড়া। ৬. কোনো ঠিকানা, ফোন নম্বর বা মতামত নিজে বানাবে না — [এখানে লিখুন] ধরনের ফাঁকা জায়গা রাখবে। শেষে প্রতিটি শর্তের পাশে লিখে দাও কোন ফাইলের কোন লাইনে সেটি পূরণ হয়েছে।

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

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

  • ফোল্ডারের ঠিকানায় কোন ফাইল খোলে, কেন? — সাধারণত index.html; এটা সার্ভারের ডিফল্ট ফাইলের নিয়ম, ব্রাউজারের নয়।
  • relative আর absolute লিংকের পার্থক্য? og:image-এ কোনটি? — relative বর্তমান পাতার অবস্থান থেকে হিসাব হয়, absolute পূর্ণ ঠিকানা; og:image-এ absolute, কারণ বাইরের সার্ভার পড়ে।
  • একাধিক পাতায় একই header বারবার না লেখার উপায়? — Server Side Include, সার্ভার-ভাষার include, static site generator বা CMS-এর template; শেষে ব্রাউজার পায় পূর্ণ HTML.
  • HTML-এ required থাকলে সার্ভারে যাচাই লাগে কেন? — ব্যবহারকারী বা প্রোগ্রাম ব্রাউজারের যাচাই এড়িয়ে সরাসরি তথ্য পাঠাতে পারে।
  • validator কী ধরে, কী ধরে না? — ব্যাকরণ, নিষিদ্ধ nesting, অনুপস্থিত alt ধরে; alt-এর মান অর্থবহ কি না, লিংকের লেখা স্পষ্ট কি না — এসব ধরে না।

১০ · রুব্রিক, নতুনদের সাধারণ ভুল আর CSS-এর প্রথম ঝলক

প্রজেক্ট শেষ হলো কি না বুঝতে একটি রুব্রিক — নম্বর দেওয়ার স্পষ্ট মাপকাঠি — ধরে নিজের কাজ দেখুন, যেমন পরীক্ষক খাতা দেখেন:

নিজেকে নম্বর দিন — মোট ১০০
মাপকাঠিনম্বরপূর্ণ নম্বর পেতে যা লাগবে
পরিকল্পনা১০brief, সাইটম্যাপ আর ফোল্ডারের নকশা লেখা আছে; ফাইলের নাম ছোট হাতের, হাইফেনে
কঙ্কাল ও semantic২০চার পাতায় একই ছাঁচ; landmark, একটি main, একটি h1, heading-এর ক্রম ঠিক
নেভিগেশন১৫সব লিংক চলে, মেনু একই ক্রমে, প্রতিটি পাতায় সঠিক aria-current, skip link
বিষয়বস্তু ও ছবি১৫মূল কথা আগে, অর্থবহ লিংক-লেখা, প্রতিটি ছবিতে ঠিক alt আর width-height
টেবিল ও তালিকা১০caption, th আর scope; তথ্য অনুযায়ী ul, ol বা dl
ফর্ম১৫প্রতিটি ঘরে label, ঠিক type, autocomplete, required-pattern, নিয়ম আগেই লেখা
head ও শেয়ার১০প্রতিটি পাতার আলাদা title, description, canonical আর OG
যাচাই৫চার পাতায় validator-এ শূন্য error ও warning; কি-বোর্ড পরীক্ষা পাস

৮০-এর ওপরে পেলে পরের মডিউলের জন্য তৈরি। কম হলে যে সারিতে নম্বর কাটা গেছে, সেই পর্বটি আবার দেখুন।

নতুনদের সাধারণ ভুল

ভুলযা ঘটেসমাধান
Index.HTML, About Us.htmlসার্ভারে 404, বা লিংকে %20ছোট হাতের অক্ষর, হাইফেন
একটি পাতায় সব ঠিক করে বাকিগুলোতে কপি করতে ভুলে যাওয়ামেনু বা ফুটার এক পাতায় আলাদাপ্রথম পাতা নিখুঁত করে তারপর কপি; Find in Files দিয়ে মিলিয়ে নেওয়া
কপি করা পাতায় পুরোনো aria-current, title বা canonical রয়ে যাওয়াসব পাতা নিজেকে “হোম” বলেকপির পর head আর মেনু আগে বদলান
ফাঁকা জায়গার জন্য <br><br> বা খালি <p>অর্থহীন কাঠামো; screen reader-এ “ফাঁকা” শোনায়ফাঁকা জায়গা CSS-এর কাজ (পর্ব ১৯)
বড় দেখাতে <h3>, ছোট দেখাতে <h5>heading-এর ক্রম ভাঙেheading বাছুন অর্থে, আকার পরে CSS-এ

শেষে এক ঝলক: CSS এলে কী বদলায়

সাইট এখন সম্পূর্ণ, অ্যাক্সেসিবল, কিন্তু সাদামাটা। শুধু স্বাদ নিতে হোম পাতার ওপরে চার লাইনের একটি <style> বসানো হলো — HTML-এর একটি অক্ষরও বদলায়নি:

<style>
  body { font-family: system-ui, sans-serif; line-height: 1.6; max-width: 40rem; margin: 0 auto; padding: 1rem; }
  header { border-bottom: 3px solid #2e7d32; }
  nav ul { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 1rem; }
  [aria-current="page"] { font-weight: bold; }
</style>
<header><p><a href="index.html">শাপলা গণপাঠাগার</a></p>
  <nav aria-label="প্রধান মেনু"><ul>
    <li><a href="index.html" aria-current="page">হোম</a></li> <li><a href="about.html">আমাদের কথা</a></li>
    <li><a href="services.html">সেবা ও সময়</a></li> <li><a href="contact.html">যোগাযোগ</a></li>
  </ul></nav></header>
<main id="main">
  <h1>পাড়ার বই, সবার জন্য</h1>
  <p>৮ হাজারের বেশি বই, নিরিবিলি পড়ার ঘর আর শিশুদের আলাদা কর্নার।</p>
</main>

লেখা মাঝখানে পড়ার মতো চওড়া কলামে, মেনুর লিংকগুলো বুলেট ছাড়া পাশাপাশি, header-এর নিচে সবুজ দাগ, আর “হোম” মোটা অক্ষরে — সেটি এসেছে aria-current থেকেই, আলাদা class লাগেনি। চেষ্টা করুন: পুরো <style> মুছে দিন — সাইট ভাঙল না, শুধু সাদামাটা হলো। আর gap: 1rem-কে 2rem করুন। এগুলোর মানে পর্ব ১৬ থেকে।

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

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।

প্র ০১HTML-এ অন্য ফাইল থেকে header “এনে বসানোর” কোনো ট্যাগ নেই কেন? ওয়েবের ইতিহাসে এই সমস্যার সমাধান কীভাবে এসেছে?

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

  • Server Side Includes (১৯৯০-এর দশক): সার্ভার পাতা পাঠানোর আগে <!--#include --> লাইনের জায়গায় অন্য ফাইল বসিয়ে দিত। আজও Apache-এ চলে।
  • সার্ভার-ভাষা আর CMS: PHP-র মতো ভাষায় include, আর তার ওপর WordPress-এর মতো CMS — যেখানে header-footer থাকে “theme”-এর ফাইলে, লেখা থাকে ডেটাবেসে। পৃথিবীর বিশাল সংখ্যক সাইট আজও এভাবেই চলে।
  • Static site generator: ২০০৮ সালে GitHub-এর সহ-প্রতিষ্ঠাতা Tom Preston-Werner বানান Jekyll, যা পরে GitHub Pages-এর ভিত্তি হয়। ধারণাটা সরল — সার্ভারে প্রতিবার পাতা বানানোর বদলে আপনার কম্পিউটারেই একবার সব পাতা বানিয়ে নিন। পরে এলো Hugo, Eleventy, Astro.
  • ব্রাউজারে চেষ্টা: Web Components-এর প্রথম সংস্করণে “HTML Imports” নামে একটি ব্যবস্থা ছিল, যা দিয়ে HTML ফাইল আরেক HTML-এ আনা যেত। কিছু সময় Chrome-এ চালু থাকলেও অন্য ব্রাউজারগুলো রাজি হয়নি, পরে এটি সরিয়ে নেওয়া হয়।

প্রতিটি পথেরই শেষ ফল এক: ব্রাউজারের কাছে পৌঁছায় একটি পূর্ণ, সরল HTML ডকুমেন্ট। পার্থক্য শুধু কে, কখন জোড়া লাগায় — সার্ভার প্রতিবার, না build-এর সময় একবার।

মূল উপলব্ধি: HTML হলো ফলাফলের ভাষা, তৈরির প্রক্রিয়ার নয়। যে টুলই ব্যবহার করুন, শেষে যে HTML বের হয় সেটি এই পর্বের মানদণ্ডে ভালো হতে হবে — তাই হাতে-লেখা HTML বোঝাই সব টুলের ভিত্তি।

প্র ০২চারটি আলাদা HTML পাতা, নাকি সব কিছু একটি পাতায় JavaScript দিয়ে বদলানো (single-page app) — কোনটি কখন?

আমাদের সাইটটি একটি multi-page site: প্রতিটি লিংকে ব্রাউজার পুরোনো পাতা ফেলে সার্ভার থেকে নতুন একটি ডকুমেন্ট আনে। এর বিপরীতে single-page application (SPA) একবার একটি পাতা নামায়, তারপর JavaScript দিয়ে ভেতরের অংশ বদলে বদলে নতুন “পাতা” দেখায়, ঠিকানাও বদলে দেয়। ২০০৪ সালে Gmail দেখিয়েছিল ওয়েবেও ডেস্কটপ অ্যাপের মতো অভিজ্ঞতা সম্ভব; পরের বছর Jesse James Garrett এই কৌশলের নাম দেন “Ajax”, আর ২০১০-এর দশকে React-এর মতো framework-এর হাত ধরে SPA খুব জনপ্রিয় হয়।

  • SPA-র সুবিধা: অনেক ইন্টারঅ্যাকশনের অ্যাপে — যেমন ইমেইল, ব্যাংকিং ড্যাশবোর্ড, ছবি সম্পাদনা — পাতা পুরো না বদলে শুধু দরকারি অংশ বদলানো দ্রুত মনে হয়।
  • SPA-র দাম: শুরুতে অনেক JavaScript নামাতে হয়, যা কম দামি ফোনে আর ধীর নেটে বিরক্তিকর। পেছনে যাওয়ার বোতাম, লিংক শেয়ার, screen reader-কে “নতুন পাতা এসেছে” জানানো, ফোকাস ঠিক জায়গায় রাখা — ব্রাউজার যা বিনা মূল্যে দিত, সব নিজে বানাতে হয়। ভুল হলে অ্যাক্সেসিবিলিটি ভাঙে।
  • বহু-পাতার সাইটের সুবিধা: প্রতিটি পাতা নিজেই সম্পূর্ণ — JavaScript বন্ধ থাকলেও চলে, সার্চ ইঞ্জিন সহজে পড়ে, ক্যাশিং সরল। পাতা থেকে পাতায় মসৃণ অ্যানিমেশনের জন্য এখন cross-document View Transitions এসেছে (সব ব্রাউজারে এখনো নয়; পর্ব ৩৭)।

পাঠাগার, স্কুল, রেস্তোরাঁ বা ছোট ব্যবসার তথ্যের সাইটে মানুষ পড়েন, ফর্ম পূরণ করেন, চলে যান — সেখানে বহু-পাতার সরল সাইটই সাধারণত সেরা। জটিল অ্যাপে SPA বা দুইয়ের মিশ্রণ।

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

প্র ০৩ফর্মে required আর pattern দিলাম — তবু সার্ভারে আবার যাচাই কেন? HTML-এর validation তাহলে কী কাজের?

ব্যাংকের কাউন্টারের কথা ভাবুন। জমার স্লিপে লেখা থাকে “হিসাব নম্বর ১৩ অঙ্ক” — গ্রাহক যাতে প্রথমবারেই ঠিক লেখেন। কিন্তু ক্যাশিয়ার তবু নিজে মিলিয়ে দেখেন, কারণ স্লিপের নির্দেশনা কেউ না মানলেও কাগজটা কাউন্টারে পৌঁছাতে পারে। HTML validation হলো সেই ছাপানো নির্দেশনা; সার্ভারের যাচাই হলো ক্যাশিয়ার।

  • এড়ানো খুব সহজ: DevTools খুলে required মুছে দেওয়া, ফর্মে novalidate যোগ করা, বা ব্রাউজার ছাড়াই একটি ছোট প্রোগ্রাম দিয়ে সরাসরি সার্ভারে তথ্য পাঠানো — স্প্যাম-বট ঠিক এটাই করে। সার্ভার জানতেই পারে না তথ্যটি আপনার ফর্ম থেকে এসেছে কি না।
  • নিরাপত্তা: শুধু ব্রাউজারের যাচাইয়ের ওপর ভরসা করা সাইটে ক্ষতিকর ইনপুট ঢুকতে পারে — নিরাপত্তা-বিশেষজ্ঞদের তালিকায় “ইনপুট যাচাই না করা” বহু বছর ধরে সবচেয়ে সাধারণ দুর্বলতাগুলোর একটি।
  • তাহলে HTML validation কেন? ব্যবহারকারীর অভিজ্ঞতার জন্য। ভুলটা সাথে সাথে, সার্ভারে না গিয়েই ধরা পড়ে, ধীর নেটে সময় বাঁচে, আর ব্রাউজার নিজের ভাষায় ও অ্যাক্সেসিবল উপায়ে বার্তা দেখায় — JavaScript ছাড়াই।

একটু ইতিহাস: এই built-in validation এসেছে ২০০০-এর দশকের মাঝামাঝি “Web Forms 2.0” প্রস্তাব থেকে, যা WHATWG-তে Ian Hickson লিখেছিলেন, আর পরে HTML5-এর অংশ হয়। তার আগে প্রতিটি সাইট নিজের JavaScript দিয়ে একই যাচাই বারবার লিখত, প্রায়ই অ্যাক্সেসিবিলিটি ছাড়াই। বাংলা অঙ্কের উদাহরণটিও মনে রাখুন — সার্ভারে যাচাইয়ের আগে বাংলা অঙ্ককে ইংরেজিতে বদলে নেওয়া (normalization) বাংলাদেশি সাইটের একটি বাস্তব দায়িত্ব।

মূল উপলব্ধি: ব্রাউজারের যাচাই সুবিধা, সার্ভারের যাচাই নিয়ম। একটি আরেকটির বিকল্প নয় — দুটোই লাগে, আলাদা কারণে।

প্র ০৪ফাইলের নাম আর URL নিয়ে এত নিয়ম কেন? একবার সাইট প্রকাশের পর একটি পাতার নাম বদলালে কী হয়?

১৯৯৮ সালে ওয়েবের স্রষ্টা Tim Berners-Lee একটি ছোট লেখা প্রকাশ করেন, যার শিরোনামই একটি নীতি: “Cool URIs don’t change” — ভালো ঠিকানা কখনো বদলায় না। তাঁর যুক্তি ছিল, একটি ঠিকানা একটি প্রতিশ্রুতি। কেউ আপনার পাতার লিংক Facebook পোস্টে দিয়েছেন, কোনো পত্রিকা খবরে উল্লেখ করেছে, কেউ বুকমার্ক রেখেছেন, Google সূচিতে রেখেছে — নাম বদলালে এই সবগুলো একসাথে ভেঙে যায়।

  • Link rot: সময়ের সাথে লিংক মরে যাওয়াকে বলে link rot. বিভিন্ন গবেষণায় দেখা গেছে, কয়েক বছরের পুরোনো লিংকের বড় একটি অংশ আর কাজ করে না — একাডেমিক গবেষণাপত্র বা আদালতের রায়ে দেওয়া লিংকও ব্যতিক্রম নয়।
  • নাম বদলাতেই হলে: পুরোনো ঠিকানা থেকে নতুন ঠিকানায় স্থায়ী রিডাইরেক্ট (HTTP 301) দিন — সার্ভার ব্রাউজার আর সার্চ ইঞ্জিনকে বলে “পাতাটি এখন ওখানে”। (এই ওয়েবসাইটের কোর্সগুলোও পুরোনো লিংক বাঁচাতে ঠিক এটাই করে।)
  • নাম বাছাইয়ে দূরদৃষ্টি: নাম রাখুন বিষয় দিয়ে (services.html), প্রযুক্তি বা তারিখ দিয়ে নয় (page2.html, new-site-2026.html) — বিষয় টেকে, বাকিগুলো বদলায়।

ছোট হাতের অক্ষর, হাইফেন আর ইংরেজি অক্ষরের নিয়মও একই ভাবনা থেকে: যত কম অস্পষ্টতা, তত কম ভাঙার সুযোগ। About.html আর about.html-এর পার্থক্য Windows-এ ধরা পড়ে না বলেই এই ভুল এত সাধারণ — আর ধরা পড়ে ঠিক সেই দিন, যেদিন সাইট প্রকাশ হয়।

মূল উপলব্ধি: URL হলো আপনার সাইটের ইন্টারফেস — পৃথিবীর সাথে চুক্তি। পরিকল্পনার সময় দশ মিনিট ভাবলে পরে শত শত ভাঙা লিংক মেরামত করতে হয় না।

প্র ০৫Validator, Lighthouse আর চেকলিস্ট — সব সবুজ। তাহলে কি নিশ্চিত হওয়া যায় সাইটটি সবার জন্য ব্যবহারযোগ্য?

না — আর এটা বোঝা একজন পরিণত ডেভেলপারের লক্ষণ। স্বয়ংক্রিয় টুল কেবল সেই সমস্যাগুলো ধরতে পারে যেগুলো নিয়ম দিয়ে যন্ত্রে মাপা যায়: alt আছে কি না, label জোড়া কি না, রঙের contrast কত। কিন্তু alt-এর লেখাটি অর্থবহ কি না, লিংকের লেখা প্রসঙ্গে বোঝা যায় কি না, ফর্মের ভুলের বার্তা মানুষ বুঝবেন কি না — এগুলো বিচার করতে মানুষ লাগে।

  • একটি বিখ্যাত পরীক্ষা: ২০১৭ সালে যুক্তরাজ্যের সরকারি ডিজিটাল সার্ভিস (GDS) ইচ্ছা করে শতাধিক অ্যাক্সেসিবিলিটি-ভুলে ভরা একটি পাতা বানিয়ে বহুল ব্যবহৃত স্বয়ংক্রিয় টুলগুলো চালায়। সবচেয়ে ভালো টুলটিও অর্ধেকেরও কম বাধা ধরতে পেরেছিল, কয়েকটি ভুল কোনো টুলই ধরেনি।
  • Lighthouse-এর ১০০: Lighthouse-এর স্কোর তার নিজের পরীক্ষাগুলোর ফল — সব পরীক্ষা পাস মানে শুধু ওই পরীক্ষাগুলো পাস। Lighthouse নিজেও রিপোর্টে কিছু বিষয় “হাতে যাচাই করুন” বলে আলাদা দেখায়।
  • মানুষের পরীক্ষা: শুধু কি-বোর্ডে পুরো সাইট চালানো, screen reader-এ একটি পাতা শোনা, লেখা ২০০% বড় করা, আর সম্ভব হলে আসল ব্যবহারকারী — একজন বয়স্ক পাঠক, একজন দৃষ্টিপ্রতিবন্ধী শিক্ষার্থী — কে একটি কাজ দিয়ে দেখা: “সদস্য হওয়ার আবেদন করুন”।

বাংলাদেশে এই প্রশ্নের একটি বাড়তি মাত্রা আছে: বাংলা screen reader-এর উচ্চারণ, বাংলা অঙ্কে ইনপুট, ছোট পর্দার সস্তা ফোন, অস্থির নেটওয়ার্ক — কোনো আন্তর্জাতিক টুল এগুলো আপনার হয়ে ভাববে না।

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

অনুশীলন

চারটি কাজই এই প্রজেক্টের সম্প্রসারণ। উত্তরের ভেতরে পূর্ণ ফাইলগুলো আছে — আগে নিজে করুন, তারপর মিলিয়ে নিন।

  1. সাইটটি নিজের কম্পিউটারে দাঁড় করান: shapla-library আর images ফোল্ডার বানিয়ে চারটি পাতা পূর্ণ ফাইল হিসেবে লিখুন — পুরো head, লোগো-লিংক, skip link, মেনু আর একই ফুটার। ডাবল-ক্লিকে আর local server-এ খুলে সব লিংক ক্লিক করুন, তারপর চার পাতাই validator-এ পাস করান।

    ঠিকানার ঘরে ডাবল-ক্লিকে file:///…, local server-এ http://127.0.0.1:…; লিংক relative বলে দুইভাবেই চলবে। ছবি না রাখলে alt দেখাবে — প্রকাশের আগে আসল ছবি দিন। নিচে পূর্ণ index.html আর about.html; services আর contact পরের দুই উত্তরে। ফুটার চার পাতায় হুবহু এক (WCAG ৩.২.৬)।

    <!doctype html>
    <html lang="bn">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>শাপলা গণপাঠাগার — উত্তরপাড়া, বগুড়া</title>
      <meta name="description" content="৮ হাজারের বেশি বই, বিনা মূল্যে পড়ার ঘর আর শিশু কর্নার — উত্তরপাড়ার শাপলা গণপাঠাগার।">
      <link rel="canonical" href="https://shapla-library.example/">
      <link rel="icon" href="images/favicon.svg" type="image/svg+xml">
      <meta property="og:type" content="website">
      <meta property="og:site_name" content="শাপলা গণপাঠাগার">
      <meta property="og:title" content="শাপলা গণপাঠাগার — পাড়ার বই, সবার জন্য">
      <meta property="og:description" content="৮ হাজারের বেশি বই, বিনা মূল্যে পড়ার ঘর আর শিশু কর্নার — উত্তরপাড়ার শাপলা গণপাঠাগার।">
      <meta property="og:url" content="https://shapla-library.example/">
      <meta property="og:image" content="https://shapla-library.example/images/og-cover.jpg">
      <meta property="og:image:alt" content="পাঠাগারের পড়ার ঘর">
      <meta property="og:locale" content="bn_BD">
      <meta name="twitter:card" content="summary_large_image">
    </head>
    <body>
      <a href="#main">সরাসরি মূল লেখায় যান</a>
      <header>
        <p><a href="index.html"><img src="images/logo.svg" alt="শাপলা গণপাঠাগার — হোম" width="160" height="48"></a></p>
        <nav aria-label="প্রধান মেনু">
          <ul>
            <li><a href="index.html" aria-current="page">হোম</a></li>
            <li><a href="about.html">আমাদের কথা</a></li>
            <li><a href="services.html">সেবা ও সময়</a></li>
            <li><a href="contact.html">যোগাযোগ</a></li>
          </ul>
        </nav>
      </header>
      <main id="main">
        <h1>পাড়ার বই, সবার জন্য</h1>
        <p>৮ হাজারের বেশি বই, নিরিবিলি পড়ার ঘর আর শিশুদের আলাদা কর্নার — শুক্রবার ছাড়া প্রতিদিন খোলা।</p>
        <p><a href="services.html">খোলার সময় আর সদস্য ফি দেখুন</a></p>
        <section aria-labelledby="news">
          <h2 id="news">এই মাসের খবর</h2>
          <ul>
            <li>প্রতি শনিবার বিকেল ৪টায় শিশুদের গল্পের আসর</li>
            <li>নতুন এসেছে ১২০টি বই</li>
          </ul>
        </section>
      </main>
      <footer>
        <p>শাপলা গণপাঠাগার, স্কুল রোড, উত্তরপাড়া, বগুড়া</p>
        <p>ফোন: <a href="tel:+8801700000000">০১৭০০-০০০০০০</a> · ইমেইল: <a href="mailto:info@shapla-library.example">info@shapla-library.example</a></p>
        <p>প্রশ্ন আছে? <a href="contact.html">যোগাযোগ পাতায়</a> লিখুন।</p>
        <p><small>© ২০২৬ শাপলা গণপাঠাগার</small></p>
      </footer>
    </body>
    </html>
    <!doctype html>
    <html lang="bn">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>আমাদের কথা | শাপলা গণপাঠাগার</title>
      <meta name="description" content="১৯৯৮ সালে ৩০০টি বই দিয়ে শুরু — শাপলা গণপাঠাগারের ইতিহাস আর পরিচালনা।">
      <link rel="canonical" href="https://shapla-library.example/about.html">
      <link rel="icon" href="images/favicon.svg" type="image/svg+xml">
      <meta property="og:type" content="website">
      <meta property="og:site_name" content="শাপলা গণপাঠাগার">
      <meta property="og:title" content="আমাদের কথা — শাপলা গণপাঠাগার">
      <meta property="og:description" content="১৯৯৮ সালে ৩০০টি বই দিয়ে শুরু — শাপলা গণপাঠাগারের ইতিহাস আর পরিচালনা।">
      <meta property="og:url" content="https://shapla-library.example/about.html">
      <meta property="og:image" content="https://shapla-library.example/images/og-cover.jpg">
      <meta property="og:image:alt" content="পাঠাগারের পড়ার ঘর">
      <meta property="og:locale" content="bn_BD">
      <meta name="twitter:card" content="summary_large_image">
    </head>
    <body>
      <a href="#main">সরাসরি মূল লেখায় যান</a>
      <header>
        <p><a href="index.html"><img src="images/logo.svg" alt="শাপলা গণপাঠাগার — হোম" width="160" height="48"></a></p>
        <nav aria-label="প্রধান মেনু">
          <ul>
            <li><a href="index.html">হোম</a></li>
            <li><a href="about.html" aria-current="page">আমাদের কথা</a></li>
            <li><a href="services.html">সেবা ও সময়</a></li>
            <li><a href="contact.html">যোগাযোগ</a></li>
          </ul>
        </nav>
      </header>
      <main id="main">
        <h1>আমাদের কথা</h1>
        <p><strong>১৯৯৮ সালে পাড়ার কয়েকজন শিক্ষক আর শিক্ষার্থী মিলে ৩০০টি বই নিয়ে শাপলা গণপাঠাগার শুরু করেন।</strong> আজ এটি একটি স্বেচ্ছাসেবী কমিটির হাতে চলে।</p>
        <figure>
          <img src="images/reading-room.jpg" width="600" height="400"
               alt="জানালার পাশে লম্বা টেবিলে বসে কয়েকজন শিক্ষার্থী বই পড়ছে">
          <figcaption>বিকেলের পড়ার ঘর — পরীক্ষার মৌসুমে এখানে বসার জায়গা পাওয়াই কঠিন।</figcaption>
        </figure>
        <h2>আমরা যা বিশ্বাস করি</h2>
        <ul>
          <li>বই পড়া সবার অধিকার — সদস্য না হলেও পড়ার ঘরে বসা যায়।</li>
          <li>শিশুর প্রথম বইটি হোক আনন্দের, পরীক্ষার চাপের নয়।</li>
        </ul>
        <h2>পরিচালনা</h2>
        <p>প্রতি দুই বছরে সদস্যদের ভোটে ৭ জনের কমিটি নির্বাচিত হয়। স্বেচ্ছাসেবী হতে চাইলে <a href="contact.html">যোগাযোগ পাতায়</a> লিখুন।</p>
      </main>
      <footer>
        <p>শাপলা গণপাঠাগার, স্কুল রোড, উত্তরপাড়া, বগুড়া</p>
        <p>ফোন: <a href="tel:+8801700000000">০১৭০০-০০০০০০</a> · ইমেইল: <a href="mailto:info@shapla-library.example">info@shapla-library.example</a></p>
        <p>প্রশ্ন আছে? <a href="contact.html">যোগাযোগ পাতায়</a> লিখুন।</p>
        <p><small>© ২০২৬ শাপলা গণপাঠাগার</small></p>
      </footer>
    </body>
    </html>

    লোগোর alt-এ “— হোম” কেন? ছবিটিই লিংকের একমাত্র লেখা, তাই alt-ই লিংকের accessible name.

  2. সেবার পাতা সম্প্রসারণ: services.html-এ “প্রায়ই আসা প্রশ্ন” নামে একটি অংশ যোগ করুন — অন্তত দুটি প্রশ্ন, প্রতিটি পর্ব ১১-এর <details> আর <summary> দিয়ে, যাতে উত্তর চাপলে খোলে। meta description-এও বিষয়টি যোগ করুন। প্রশ্নগুলো কি h3 হওয়া উচিত, নাকি summary-ই যথেষ্ট?

    summary নিজেই প্রশ্নের লেবেল, screen reader একে খোলা/বন্ধ বোতামের মতো ঘোষণা করে — ছোট FAQ-তে অংশের মাথায় একটি h2-ই যথেষ্ট। প্রশ্ন অনেক হলে summary-র ভেতরে heading রাখাও বৈধ। পূর্ণ ফাইল:

    <!doctype html>
    <html lang="bn">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>সেবা ও সময়সূচি | শাপলা গণপাঠাগার</title>
      <meta name="description" content="শাপলা গণপাঠাগারের খোলার সময়, সদস্য ফি আর প্রায়ই আসা প্রশ্ন।">
      <link rel="canonical" href="https://shapla-library.example/services.html">
      <link rel="icon" href="images/favicon.svg" type="image/svg+xml">
      <meta property="og:type" content="website">
      <meta property="og:site_name" content="শাপলা গণপাঠাগার">
      <meta property="og:title" content="সেবা ও সময়সূচি — শাপলা গণপাঠাগার">
      <meta property="og:description" content="শাপলা গণপাঠাগারের খোলার সময়, সদস্য ফি আর প্রায়ই আসা প্রশ্ন।">
      <meta property="og:url" content="https://shapla-library.example/services.html">
      <meta property="og:image" content="https://shapla-library.example/images/og-cover.jpg">
      <meta property="og:image:alt" content="পাঠাগারের পড়ার ঘর">
      <meta property="og:locale" content="bn_BD">
      <meta name="twitter:card" content="summary_large_image">
    </head>
    <body>
      <a href="#main">সরাসরি মূল লেখায় যান</a>
      <header>
        <p><a href="index.html"><img src="images/logo.svg" alt="শাপলা গণপাঠাগার — হোম" width="160" height="48"></a></p>
        <nav aria-label="প্রধান মেনু">
          <ul>
            <li><a href="index.html">হোম</a></li>
            <li><a href="about.html">আমাদের কথা</a></li>
            <li><a href="services.html" aria-current="page">সেবা ও সময়</a></li>
            <li><a href="contact.html">যোগাযোগ</a></li>
          </ul>
        </nav>
      </header>
      <main id="main">
        <h1>সেবা ও সময়সূচি</h1>
        <h2>যা যা পাবেন</h2>
        <ul>
          <li>পড়ার ঘর — সবার জন্য, বিনা মূল্যে</li>
          <li>বাড়িতে বই নেওয়া — একসাথে ২টি, ১৪ দিনের জন্য (শুধু সদস্য)</li>
          <li>শিশু কর্নার আর শনিবারের গল্পের আসর</li>
        </ul>
        <h2>খোলার সময়</h2>
        <table>
          <caption>খোলার সময় (শুক্রবার ও সরকারি ছুটির দিনে বন্ধ)</caption>
          <thead>
            <tr><th scope="col">দিন</th><th scope="col">পড়ার ঘর</th><th scope="col">বই নেওয়া-ফেরত</th></tr>
          </thead>
          <tbody>
            <tr><th scope="row">শনি – বুধ</th><td>সকাল ১০টা – রাত ৮টা</td><td>বিকেল ৩টা – ৭টা</td></tr>
            <tr><th scope="row">বৃহস্পতি</th><td>সকাল ১০টা – বিকেল ৫টা</td><td>বিকেল ৩টা – ৫টা</td></tr>
          </tbody>
        </table>
        <h2>সদস্য ফি</h2>
        <dl>
          <dt>সাধারণ সদস্য</dt><dd>বছরে ১২০ টাকা</dd>
          <dt>শিক্ষার্থী (পরিচয়পত্রসহ)</dt><dd>বছরে ৬০ টাকা</dd>
        </dl>
        <h2>প্রায়ই আসা প্রশ্ন</h2>
        <details>
          <summary>বই হারিয়ে গেলে কী করব?</summary>
          <p>একই বই কিনে দিন, অথবা দাম জমা দিন।</p>
        </details>
        <details>
          <summary>সদস্য না হয়েও কি পড়ার ঘরে বসা যায়?</summary>
          <p>হ্যাঁ। শুধু ঢোকার সময় খাতায় নাম লিখুন।</p>
        </details>
        <p><a href="contact.html">সদস্য হওয়ার ফর্ম পূরণ করুন</a></p>
      </main>
      <footer>
        <p>শাপলা গণপাঠাগার, স্কুল রোড, উত্তরপাড়া, বগুড়া</p>
        <p>ফোন: <a href="tel:+8801700000000">০১৭০০-০০০০০০</a> · ইমেইল: <a href="mailto:info@shapla-library.example">info@shapla-library.example</a></p>
        <p>প্রশ্ন আছে? <a href="contact.html">যোগাযোগ পাতায়</a> লিখুন।</p>
        <p><small>© ২০২৬ শাপলা গণপাঠাগার</small></p>
      </footer>
    </body>
    </html>
  3. ফর্ম সম্প্রসারণ: contact.html-এর “বিষয়” select-এর বদলে একটি <fieldset> আর <legend>-সহ radio বোতামের দল বানান: সাধারণ সদস্য, শিক্ষার্থী সদস্য, “শুধু প্রশ্ন”। বার্তা ঐচ্ছিক করুন, ফর্মের ওপরে লিখে দিন কোন ঘর বাধ্যতামূলক। আর মোবাইল নম্বরের pattern এমন করুন যাতে বাংলা অঙ্কেও লেখা যায়।

    radio-দলের একটিতে required দিলেই পুরো দল বাধ্যতামূলক হয়, কারণ একই name. legend দলের প্রশ্নটি দেয় — screen reader প্রতিটি বিকল্পের আগে “সদস্যপদের ধরন” বলে। pattern-এ প্রতিটি অবস্থানে ইংরেজি আর বাংলা দুই অঙ্কের ঘর রাখা হয়েছে: [0০][1১][3-9৩-৯][0-9০-৯]{8}. মনে রাখবেন, সার্ভার তথ্য পেয়ে আগে বাংলা অঙ্ককে ইংরেজিতে বদলে নেবে, তারপর যাচাই করবে। পূর্ণ ফাইল:

    <!doctype html>
    <html lang="bn">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>যোগাযোগ ও সদস্য হওয়া | শাপলা গণপাঠাগার</title>
      <meta name="description" content="ঠিকানা, ফোন আর অনলাইনে সদস্য হওয়ার ফর্ম — শাপলা গণপাঠাগার।">
      <link rel="canonical" href="https://shapla-library.example/contact.html">
      <link rel="icon" href="images/favicon.svg" type="image/svg+xml">
      <meta property="og:type" content="website">
      <meta property="og:site_name" content="শাপলা গণপাঠাগার">
      <meta property="og:title" content="যোগাযোগ ও সদস্য হওয়া — শাপলা গণপাঠাগার">
      <meta property="og:description" content="ঠিকানা, ফোন আর অনলাইনে সদস্য হওয়ার ফর্ম — শাপলা গণপাঠাগার।">
      <meta property="og:url" content="https://shapla-library.example/contact.html">
      <meta property="og:image" content="https://shapla-library.example/images/og-cover.jpg">
      <meta property="og:image:alt" content="পাঠাগারের পড়ার ঘর">
      <meta property="og:locale" content="bn_BD">
      <meta name="twitter:card" content="summary_large_image">
    </head>
    <body>
      <a href="#main">সরাসরি মূল লেখায় যান</a>
      <header>
        <p><a href="index.html"><img src="images/logo.svg" alt="শাপলা গণপাঠাগার — হোম" width="160" height="48"></a></p>
        <nav aria-label="প্রধান মেনু">
          <ul>
            <li><a href="index.html">হোম</a></li>
            <li><a href="about.html">আমাদের কথা</a></li>
            <li><a href="services.html">সেবা ও সময়</a></li>
            <li><a href="contact.html" aria-current="page">যোগাযোগ</a></li>
          </ul>
        </nav>
      </header>
      <main id="main">
        <h1>যোগাযোগ ও সদস্য হওয়া</h1>
        <address>
          স্কুল রোড, উত্তরপাড়া, বগুড়া<br>
          ফোন: <a href="tel:+8801700000000">০১৭০০-০০০০০০</a>
        </address>
        <h2>আমাদের লিখুন</h2>
        <p>যে ঘরের পাশে “ঐচ্ছিক” লেখা নেই, সেটি পূরণ করা বাধ্যতামূলক।</p>
        <form action="/api/contact" method="post">
          <p><label for="name">পুরো নাম</label>
            <input id="name" name="name" autocomplete="name" required></p>
          <p><label for="phone">মোবাইল নম্বর</label>
            <input id="phone" name="phone" type="tel" inputmode="numeric" required
                   pattern="[0০][1১][3-9৩-৯][0-9০-৯]{8}" autocomplete="tel" aria-describedby="phone-hint">
            <small id="phone-hint">১১ অঙ্ক, বাংলা বা ইংরেজি অঙ্কে — যেমন 01712345678</small></p>
          <p><label for="email">ইমেইল (ঐচ্ছিক)</label>
            <input id="email" name="email" type="email" autocomplete="email"></p>
          <fieldset>
            <legend>সদস্যপদের ধরন</legend>
            <label><input type="radio" name="plan" value="general" required> সাধারণ — বছরে ১২০ টাকা</label>
            <label><input type="radio" name="plan" value="student"> শিক্ষার্থী — বছরে ৬০ টাকা</label>
            <label><input type="radio" name="plan" value="none"> সদস্য হতে চাই না, শুধু প্রশ্ন</label>
          </fieldset>
          <p><label for="msg">বার্তা (ঐচ্ছিক)</label>
            <textarea id="msg" name="msg" rows="4" maxlength="500"></textarea></p>
          <p><label><input type="checkbox" name="rules" required> পাঠাগারের নিয়ম পড়েছি ও মেনে চলব</label></p>
          <button type="submit">পাঠান</button>
        </form>
      </main>
      <footer>
        <p>শাপলা গণপাঠাগার, স্কুল রোড, উত্তরপাড়া, বগুড়া</p>
        <p>ফোন: <a href="tel:+8801700000000">০১৭০০-০০০০০০</a> · ইমেইল: <a href="mailto:info@shapla-library.example">info@shapla-library.example</a></p>
        <p>প্রশ্ন আছে? <a href="contact.html">যোগাযোগ পাতায়</a> লিখুন।</p>
        <p><small>© ২০২৬ শাপলা গণপাঠাগার</small></p>
      </footer>
    </body>
    </html>
  4. পঞ্চম পাতা আর template-এর ব্যথা: একটি নতুন পাতা events.html বানান — দুটি অনুষ্ঠান, প্রতিটি একটি <article>, তারিখ <time datetime> দিয়ে। তারপর মেনুতে “অনুষ্ঠান” যোগ করুন। মোট কয়টি ফাইলে, কয়টি জায়গায় হাত দিতে হলো? একটি বাদ পড়লে কীভাবে ধরতেন?

    পাঁচটি ফাইল: নতুন পাতা আর বাকি চারটির মেনু — চারটি আলাদা সম্পাদনা। বাদ পড়া ধরতে Ctrl+Shift+F চেপে events.html খুঁজুন: পাঁচ ফাইলেই পাওয়ার কথা। এই একঘেয়ে, ভুলপ্রবণ কাজই template আর SSG-র জন্মের কারণ। পূর্ণ events.html:

    <!doctype html>
    <html lang="bn">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>অনুষ্ঠান | শাপলা গণপাঠাগার</title>
      <meta name="description" content="গল্পের আসর আর পাঠচক্র — শাপলা গণপাঠাগারের আসন্ন অনুষ্ঠান।">
      <link rel="canonical" href="https://shapla-library.example/events.html">
      <link rel="icon" href="images/favicon.svg" type="image/svg+xml">
      <meta property="og:type" content="website">
      <meta property="og:site_name" content="শাপলা গণপাঠাগার">
      <meta property="og:title" content="অনুষ্ঠান — শাপলা গণপাঠাগার">
      <meta property="og:description" content="গল্পের আসর আর পাঠচক্র — শাপলা গণপাঠাগারের আসন্ন অনুষ্ঠান।">
      <meta property="og:url" content="https://shapla-library.example/events.html">
      <meta property="og:image" content="https://shapla-library.example/images/og-cover.jpg">
      <meta property="og:image:alt" content="পাঠাগারের পড়ার ঘর">
      <meta property="og:locale" content="bn_BD">
      <meta name="twitter:card" content="summary_large_image">
    </head>
    <body>
      <a href="#main">সরাসরি মূল লেখায় যান</a>
      <header>
        <p><a href="index.html"><img src="images/logo.svg" alt="শাপলা গণপাঠাগার — হোম" width="160" height="48"></a></p>
        <nav aria-label="প্রধান মেনু">
          <ul>
            <li><a href="index.html">হোম</a></li>
            <li><a href="about.html">আমাদের কথা</a></li>
            <li><a href="services.html">সেবা ও সময়</a></li>
            <li><a href="events.html" aria-current="page">অনুষ্ঠান</a></li>
            <li><a href="contact.html">যোগাযোগ</a></li>
          </ul>
        </nav>
      </header>
      <main id="main">
        <h1>অনুষ্ঠান</h1>
        <p>সব অনুষ্ঠান বিনা মূল্যে, সবার জন্য খোলা।</p>
        <article aria-labelledby="ev1">
          <h2 id="ev1">শিশুদের গল্পের আসর</h2>
          <p><time datetime="2026-11-07T16:00">৭ নভেম্বর ২০২৬, বিকেল ৪টা</time> · শিশু কর্নার</p>
          <p>৬–১০ বছরের শিশুদের জন্য।</p>
        </article>
        <article aria-labelledby="ev2">
          <h2 id="ev2">মাসিক পাঠচক্র: কিশোর উপন্যাস</h2>
          <p><time datetime="2026-11-14T17:00">১৪ নভেম্বর ২০২৬, বিকেল ৫টা</time> · পড়ার ঘর</p>
          <p>বইটি কাউন্টারে রাখা আছে।</p>
        </article>
      </main>
      <footer>
        <p>শাপলা গণপাঠাগার, স্কুল রোড, উত্তরপাড়া, বগুড়া</p>
        <p>ফোন: <a href="tel:+8801700000000">০১৭০০-০০০০০০</a> · ইমেইল: <a href="mailto:info@shapla-library.example">info@shapla-library.example</a></p>
        <p>প্রশ্ন আছে? <a href="contact.html">যোগাযোগ পাতায়</a> লিখুন।</p>
        <p><small>© ২০২৬ শাপলা গণপাঠাগার</small></p>
      </footer>
    </body>
    </html>

    datetime-এ যন্ত্রের জন্য ISO তারিখ, ভেতরে মানুষের জন্য বাংলায়।

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

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

ক্রমএকটি ছোট ওয়েবসাইট তৈরির ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. 📝 লক্ষ্য আর পাঠক ঠিক করা (brief)
  2. 🗺️ সাইটম্যাপ — কয়টি পাতা, কোনটিতে কী
  3. 📁 ফোল্ডার আর ফাইলের নাম ঠিক করা
  4. 🦴 সব পাতার একই কঙ্কাল বানানো
  5. ✍️ লেখা, ছবি, টেবিল আর ফর্ম বসানো
  6. ✅ validator, কি-বোর্ড আর রুব্রিক দিয়ে যাচাই

একটি ওয়েবসাইটের পাতার ফাইলের নাম হিসেবে কোনটি সবচেয়ে নিরাপদ?

  • About Us.html
  • about-us.html
  • AboutUs.HTML
  • আমাদের-কথা.html

একটি ফোল্ডারের index.html ফাইল ডাবল-ক্লিক করে ব্রাউজারে খোলা হলো। ভেতরের লিংক <a href="/about.html"> কাজ করছে না, যদিও about.html একই ফোল্ডারে আছে। কারণ কী?

  • ব্রাউজার কম্পিউটারের ফাইল খুলতে পারে না
  • লিংকের লেখা বাংলায় হলে কাজ করে না
  • শুরুর “/” ব্রাউজারকে ড্রাইভের গোড়ায় খুঁজতে পাঠায়
  • .html এক্সটেনশনের বদলে .htm লিখতে হয়

একটি সাইটের পাঁচটি পাতাতেই মেনু আছে, কিন্তু এক পাতায় আইটেমগুলোর ক্রম আলাদা আর একটি লিংক নেই। WCAG-এর কোন নিয়ম এখানে ভাঙছে?

  • Consistent Navigation
  • Bypass Blocks
  • Page Titled
  • Reflow

<input type="tel" pattern="01[3-9][0-9]{8}" required> — কোন মানটি জমা দেওয়া যাবে?

  • ০১৭১২৩৪৫৬৭৮
  • 01712345678
  • 1712345678
  • +8801712345678

Facebook বা WhatsApp-এ একটি পাতার লিংক শেয়ার করলে কার্ডে কোন ছবি দেখাবে, সেটি মূলত কোন ট্যাগ ঠিক করে?

  • <link rel="icon" href="favicon.svg">
  • <meta name="description" content="…">
  • পাতার প্রথম <img>-এর alt
  • <meta property="og:image" content="https://…">

একটি ফর্মের প্রতিটি ঘরে required আর pattern দেওয়া আছে। সার্ভারের দিকে কী করা উচিত?

  • কিছুই না — ব্রাউজার তো যাচাই করেই পাঠিয়েছে
  • ব্রাউজারের যাচাই বন্ধ করে শুধু সার্ভারে যাচাই
  • সার্ভারেও আবার একই নিয়মে যাচাই করা
  • শুধু HTTPS চালু রাখা — তাহলেই তথ্য নিরাপদ

শব্দকোষ

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

মনে রাখুন

  1. কোডের আগে নকশা: brief, সাইটম্যাপ, ফোল্ডার — প্রতিটি পাতার একটি কাজ, ফাইলের নাম ছোট হাতের ইংরেজি আর হাইফেনে, হোম মানে index.html.
  2. সব পাতার একই কঙ্কাল: lang="bn", নিজস্ব title, skip link, header-nav, একটি main আর একটি h1, footer; বর্তমান পাতায় aria-current="page".
  3. ঠিক তথ্যে ঠিক element: ul, table (caption, th, scope), dl, অর্থবহ alt; ফর্মে label, ঠিক type, autocomplete, required-pattern — আর সার্ভারে আবার যাচাই।
  4. প্রতিটি পাতার head আলাদা: title, description, canonical, Open Graph (og:image-এ পূর্ণ ঠিকানা)।
  5. বারবার একই header হাতে কপি করলে ভুল হয় — পেশাদাররা template বা SSG ব্যবহার করেন; আর “তৈরি” মানে validator, কি-বোর্ড পরীক্ষা আর রুব্রিক পাস।

পরের পর্বে: কাঠামো তৈরি — এবার সাজ। CSS-এর সাথে পরিচয়: rule, property আর পাতায় CSS যোগ করার তিনটি উপায়। এই পাঠাগারের সাইটটিই পরের পর্বগুলোতে ধীরে ধীরে রঙিন হতে পারে।

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

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