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

অ্যাক্সেসিবিলিটি — সবার জন্য ওয়েব, screen reader আর ARIA-র সঠিক ব্যবহার

Web Accessibility — WCAG 2.2, Keyboard & Focus, Accessible Names, the Accessibility Tree, ARIA & Screen Reader Testing

Taught in Bangla, this lesson introduces web accessibility: who it helps, WCAG 2.2 with the POUR principles and A, AA and AAA levels, keyboard navigation, focus and tabindex values, and where accessible names come from. It explains the accessibility tree, the first rule of ARIA, aria-expanded, aria-current, aria-hidden and live regions, and testing with the keyboard, NVDA, TalkBack, VoiceOver, DevTools and Lighthouse.

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

  • অ্যাক্সেসিবিলিটি কার কাজে লাগে, WCAG 2.2 কী, POUR নীতি আর A/AA/AAA স্তরের মানে
  • কি-বোর্ড দিয়ে পাতা চালানো — Tab-এর ক্রম, focus, আর tabindex-এর তিন রকম মান
  • accessible name কোথা থেকে আসে — label, alt, aria-label, aria-labelledby, aria-describedby — আর কোনটি কাকে হারায়
  • accessibility tree, ARIA-র প্রথম নিয়ম, aria-expanded, aria-current, aria-hidden আর live region-এর সঠিক ব্যবহার
  • নিজে পরীক্ষা করা — কি-বোর্ড টেস্ট, NVDA/TalkBack/VoiceOver, DevTools-এর Accessibility প্যানেল, Lighthouse আর axe

১ · অ্যাক্সেসিবিলিটি কী — আর আসলে কার জন্য

ঢাকার মেট্রো রেলের স্টেশনে খেয়াল করেছেন? সিঁড়ির পাশে লিফট আর চলন্ত সিঁড়ি, মেঝেতে হলুদ খাঁজকাটা পথ। হলুদ পথটি দৃষ্টিপ্রতিবন্ধী যাত্রীর লাঠির জন্য, লিফট হুইলচেয়ারের জন্য। কিন্তু লিফটে ওঠেন ভারী ব্যাগ হাতে মানুষও, বাচ্চার স্ট্রলার নিয়ে মা, হাঁটুর ব্যথায় কষ্ট পাওয়া দাদু। ভবনকে সবার ব্যবহারযোগ্য করার এই চিন্তাকেই ওয়েবে বলে accessibility — বাংলায় প্রবেশযোগ্যতা বা ব্যবহারযোগ্যতা। ইংরেজিতে অনেকে সংক্ষেপে লেখেন a11y (a, তারপর ১১টি অক্ষর, তারপর y).

ওয়েবের জন্য সংজ্ঞাটা সহজ: যেকোনো মানুষ, যেকোনো উপায়ে — চোখে দেখে বা কানে শুনে, মাউসে বা কি-বোর্ডে, আঙুলে বা কণ্ঠে — পাতার তথ্য পেতে আর কাজ সারতে পারবেন। বিশ্ব স্বাস্থ্য সংস্থা (WHO)-র হিসাবে পৃথিবীর প্রায় প্রতি ছয়জনে একজন — প্রায় ১৩০ কোটি মানুষ — উল্লেখযোগ্য প্রতিবন্ধিতা নিয়ে বাঁচেন। এঁরা আপনার সাইটের সাধারণ পাঠক।

কারা উপকার পান

দৃষ্টি

দৃষ্টিহীন মানুষ screen reader দিয়ে পাতা শোনেন বা ব্রেইল ডিসপ্লেতে পড়েন; কম দেখেন যাঁরা, লেখা বড় করেন; রঙ-অন্ধ মানুষ রং দিয়ে বোঝানো তথ্য হারান।

alt, কাঠামো, contrast

হাতের নড়াচড়া

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

কি-বোর্ড, বড় লক্ষ্য

শ্রবণ

বধির বা কম শোনেন এমন মানুষের জন্য ভিডিওর ক্যাপশন আর অডিওর লিখিত রূপ দরকার — পর্ব ০৬-এ দেখা <track> ঠিক এই কাজেই।

ক্যাপশন, ট্রান্সক্রিপ্ট

বোঝা ও মনোযোগ

ডিসলেক্সিয়া, মনোযোগের সমস্যা — জটিল ভাষা, এলোমেলো নকশা আর কড়া সময়সীমা এঁদের পথ আটকায়।

সহজ ভাষা, স্থির নকশা

আর আছেন বয়স্ক মানুষ — বয়সের সাথে দৃষ্টি, শ্রবণ আর হাতের স্থিরতা সবই কমে। বাবা-মা যখন ফোনে লেখা বড় করে বিদ্যুৎ বিল দেখেন, তাঁরাও অ্যাক্সেসিবিলিটির সুবিধা নিচ্ছেন।

Microsoft-এর Inclusive Design গাইডে একটি সুন্দর ধারণা আছে: প্রতিবন্ধিতা হতে পারে স্থায়ী (এক হাত নেই), সাময়িক (হাত ভেঙে প্লাস্টার), অথবা পরিস্থিতিগত (এক হাতে বাজারের ব্যাগ, অন্য হাতে ফোন)। একে বলে situational disability. দুপুরের রোদে ফাটা স্ক্রিনের ফোনে হালকা ধূসর লেখা পড়েছেন? ভিড়ের বাসে শব্দ ছাড়া ভিডিও দেখেছেন? সেই মুহূর্তে আপনিও একজন “প্রতিবন্ধী ব্যবহারকারী” — আর ভালো contrast, ক্যাপশন আর ছবির alt তখন আপনাকেই বাঁচায়।

যে সফটওয়্যার বা যন্ত্র দিয়ে মানুষ এই বাধাগুলো পেরোন — screen reader, পর্দা বড় করার ম্যাগনিফায়ার, ব্রেইল ডিসপ্লে, কণ্ঠ দিয়ে নিয়ন্ত্রণ, সুইচ — এদের একসাথে বলে assistive technology (সহায়ক প্রযুক্তি)। এদের সবার কাজ নির্ভর করে একটি জিনিসের ওপর: আপনার HTML কতটা সঠিক।

মূল ধারণা

অ্যাক্সেসিবিলিটি শেষে যোগ করার “ফিচার” নয়, বাড়ির ভিতের মতো। সঠিক semantic HTML দিয়ে শুরু করলে কাজের বড় অংশ বিনামূল্যে হয়ে যায়। ভুল কাঠামো বানিয়ে পরে জোড়াতালি দিলে খরচ বহুগুণ, ফলও খারাপ।

২ · WCAG 2.2 — চারটি নীতি (POUR) আর তিনটি স্তর

“অ্যাক্সেসিবল” কথাটা মাপা হয় কীভাবে? W3C-র Web Accessibility Initiative (WAI) এর জন্য একটি আন্তর্জাতিক মান লিখেছে — WCAG (Web Content Accessibility Guidelines). প্রথম সংস্করণ ১৯৯৯ সালে, WCAG 2.0 ২০০৮ সালে, 2.1 ২০১৮ সালে, আর বর্তমান সংস্করণ WCAG 2.2 প্রকাশিত হয় ২০২৩ সালের অক্টোবরে। WCAG 3 নামে সম্পূর্ণ নতুন একটি কাঠামো নিয়ে কাজ চলছে, তবে সেটি এখনো খসড়া — আজকের কাজের মাপকাঠি 2.2.

WCAG-এ আছে কয়েক ডজন success criterion — প্রতিটি একটি যাচাইযোগ্য নিয়ম, নম্বর দিয়ে চেনা যায় (যেমন ১.১.১, ২.১.১)। সব নিয়ম চারটি বড় নীতির নিচে সাজানো, ইংরেজি আদ্যক্ষরে POUR. নিচের স্টেপারে একে একে দেখুন:

  1. Perceivableবোঝার মতো করে পৌঁছানোদেখা, শোনা বা ছুঁয়ে পাওয়া
  2. Operableচালানো যায়মাউস ছাড়াও
  3. Understandableবোঝা যায়ভাষা আর আচরণ
  4. Robustমজবুত কোডসব সহায়ক প্রযুক্তিতে চলে
  1. Perceivable — অনুভব করা যায়. তথ্য অন্তত এক ইন্দ্রিয় দিয়ে পৌঁছাতে হবে। ছবি দেখতে না পেলে তার বিকল্প লেখা (alt), ভিডিও শুনতে না পেলে ক্যাপশন, রং চিনতে না পারলে রঙের সাথে লেখা বা চিহ্ন। “লাল ঘরগুলো ভুল” লিখলে রঙ-অন্ধ পাঠক কিছুই পান না।
  2. Operable — চালানো যায়. প্রতিটি বোতাম, লিংক, মেনু মাউস ছাড়া শুধু কি-বোর্ডে চলতে হবে; কোথাও আটকে যাওয়া চলবে না (keyboard trap); সময়সীমা থাকলে বাড়ানোর সুযোগ; আর দ্রুত ঝলকানো আলো নয়, যা খিঁচুনি ঘটাতে পারে।
  3. Understandable — বোঝা যায়. পাতার ভাষা ঘোষণা করা, সহজ লেখা, প্রতিটি পাতায় মেনু একই জায়গায়, আর ফর্মে ভুল হলে স্পষ্ট করে বলা কী ভুল আর কীভাবে ঠিক করবেন (পর্ব ০৯-এর validation মনে করুন)।
  4. Robust — মজবুত. কোড এমন হবে যাতে আজকের আর আগামীকালের ব্রাউজার ও সহায়ক প্রযুক্তি সঠিকভাবে বুঝতে পারে। মূল নিয়ম ৪.১.২: প্রতিটি কন্ট্রোলের নাম (Name), ভূমিকা (Role) আর অবস্থা (Value/State) যন্ত্রের কাছে পৌঁছাতে হবে — এই পর্বের বাকিটা মূলত এই নিয়মেরই গল্প।
  5. তিনটি স্তর. প্রতিটি নিয়মের একটি conformance level আছে। A না মানলে কিছু মানুষ পাতা ব্যবহারই করতে পারেন না; AA মানলে বেশিরভাগ বড় বাধা দূর হয় — নীতি, আইন আর চুক্তিতে সাধারণত “WCAG 2.x AA” চাওয়া হয়। পুরো সাইটে সব AAA মানা অনেক সময় বাস্তবসম্মত নয়, তাই WCAG নিজেই একে সাধারণ লক্ষ্য হিসেবে সুপারিশ করে না।

WCAG 2.2-এ নতুন কী

2.2-এ নয়টি নতুন নিয়ম যোগ হয়েছে, একটি বাদ পড়েছে। নতুনগুলোর কয়েকটি সরাসরি নকশায় লাগে: Focus Not Obscured (২.৪.১১, AA) — focus পাওয়া অংশ sticky হেডার বা কুকি-ব্যানারের নিচে পুরো ঢাকা পড়বে না; Target Size (Minimum) (২.৫.৮, AA) — ক্লিক বা ছোঁয়ার লক্ষ্য অন্তত 24×24 CSS পিক্সেল, বা আশেপাশে যথেষ্ট ফাঁকা; Accessible Authentication (৩.৩.৮, AA) — লগইনে স্মৃতি বা ধাঁধা-নির্ভর পরীক্ষা ছাড়াও উপায়, যেমন পাসওয়ার্ড পেস্ট করতে দেওয়া। বাদ পড়েছে পুরোনো ৪.১.১ “Parsing” — আধুনিক HTML parser ভুল কোডও একই নিয়মে সামলায় বলে।

আইন ও নীতি: অনেক দেশে ওয়েব অ্যাক্সেসিবিলিটি আইনে বাধ্যতামূলক — যেমন যুক্তরাষ্ট্রে Section 508 আর ADA, ইউরোপীয় ইউনিয়নে European Accessibility Act (২০২৫ সালের জুন থেকে প্রযোজ্য); মাপকাঠি হিসেবে প্রায় সব সময় WCAG বা তার ওপর দাঁড়ানো মান। বাংলাদেশে প্রতিবন্ধী ব্যক্তির অধিকার ও সুরক্ষা নিয়ে আইন আছে, তবে কোনো নির্দিষ্ট ওয়েবসাইটের জন্য আইনি বাধ্যবাধকতা ঠিক কতটা, তা প্রজেক্টের সময় হালনাগাদ সরকারি উৎস থেকে যাচাই করে নেবেন। বিদেশি ক্লায়েন্টের কাজে (ফ্রিল্যান্সিংয়ে প্রায়ই) চুক্তিতে “WCAG 2.2 AA” লেখা থাকা এখন খুব সাধারণ।

৩ · মাউস ছাড়া ওয়েব — কি-বোর্ড, focus আর tabindex

মাউসটা সরিয়ে রেখে শুধু কি-বোর্ড দিয়ে এই পাতায় চলুন। Tab চাপলে পরের লিংক বা বোতামে যায়, Shift+Tab আগেরটায়; লিংকে Enter, বোতামে Enter বা Space; রেডিও বা মেনুর ভেতরে তীর-চিহ্ন; বন্ধ করতে Esc. Screen reader ব্যবহারকারী, হাত কাঁপে এমন মানুষ, দ্রুত কাজ করা প্রোগ্রামাররাও এভাবেই চলেন। WCAG-এর ২.১.১ নিয়ম বলে: মাউসে যা করা যায়, কি-বোর্ডেও তা করা যেতে হবে।

কি-বোর্ডের এই চলাচলের কেন্দ্রে আছে focus — পাতার কোন অংশটি এই মুহূর্তে কি-বোর্ডের কথা শুনছে। একসাথে একটিই element focus পায়। ব্রাউজার সেটিকে সাধারণত একটি দাগ বা আভা (focus ring) দিয়ে দেখায় — এটা মুছে ফেলা মানে কি-বোর্ড ব্যবহারকারীর চোখ বেঁধে দেওয়া। আর Tab চাপলে focus কোন ক্রমে ঘোরে, তাকে বলে tab order — সাধারণত HTML-এ যে ক্রমে লেখা, সেই ক্রমেই।

কে নিজে থেকেই focus পায়

লিংক (href থাকলে), <button>, <input>, <select>, <textarea>, <summary> — এরা জন্ম থেকেই কি-বোর্ড বোঝে। কিন্তু <div>, <span>, <p> কখনো focus পায় না, যত onclick-ই লাগান। focus-এর নিয়ম বদলানোর attribute হলো tabindex, যার তিন রকম মান:

মানকী করেকখন ব্যবহার
tabindex="0"Tab-এর স্বাভাবিক ক্রমে (HTML-এ যেখানে লেখা) ঢোকায়নিজে বানানো কন্ট্রোল, স্ক্রল-বাক্স (পর্ব ০৭)
tabindex="-1"Tab-এ আসে না, কিন্তু JavaScript-এর focus() বা লিংকে লাফ দিয়ে focus আনা যায়skip link-এর গন্তব্য, dialog-এর শিরোনাম
tabindex="1" বা বেশিস্বাভাবিক ক্রম ভেঙে সবার আগে লাফ দেয়কখনো না — প্রায় সব বিশেষজ্ঞ নির্দেশিকা এটি এড়াতে বলে

নিচের এডিটরে এক পাতায় সব রকম জিনিস রাখা হয়েছে। এডিটরের নিচের “কপি” বোতামে Tab দিয়ে আসুন, তারপর বারবার Tab চাপুন — focus প্রিভিউতে ঢুকবে, আর কোথায় যাচ্ছে তা প্রিভিউর নিচে লেখা হবে:

<p>Tab চাপতে থাকুন:</p>
<a href="#news">খবর</a>
<button>খুঁজুন</button>
<div onclick="console.log('div-এ ক্লিক')">লগইন (div)</div>
<div tabindex="0">অফার (tabindex="0")</div>
<button tabindex="-1">বন্ধ (tabindex="-1")</button>
<input aria-label="ইমেইল" placeholder="ইমেইল">
<button tabindex="3">সাবস্ক্রাইব (tabindex="3")</button>

<script>
  document.addEventListener('focusin', (e) => {
    console.log('focus →', e.target.textContent || e.target.placeholder);
  });
</script>

প্রথম Tab-এ focus যায় একদম শেষের “সাবস্ক্রাইব”-এ — ধনাত্মক tabindex="3" তাকে লাইনের সামনে নিয়ে এসেছে। তারপর খবর → খুঁজুন → অফার → ইমেইল। “লগইন (div)” আর “বন্ধ” কখনো focus পায় না। প্রতিটি focus-এর চারপাশে ব্রাউজারের নিজের দাগটিও দেখুন। চেষ্টা করুন: “লগইন”-এর div-এ tabindex="0" যোগ করুন — এবার সে Tab-এ আসবে; তারপর সাবস্ক্রাইবের tabindex="3"-কে 0 করুন — ক্রম আবার HTML-এর লেখার মতো স্বাভাবিক হবে।

এই কোডটিতেই প্রতিটি Tab চাপার সময় ব্রাউজার মনে মনে কী হিসাব করে, দেখুন:

1<a href="#news">খবর</a>2<button>খুঁজুন</button>3<div onclick="…">লগইন (div)</div>4<div tabindex="0">অফার</div>5<button tabindex="-1">বন্ধ</button>6<input aria-label="ইমেইল">7<button tabindex="3">সাবস্ক্রাইব</button>
ব্রাউজারের হিসাব
কতবার Tab
focus এখন
বাদ পড়ল
  1. প্রথম Tab — সাবস্ক্রাইব. ব্রাউজার আগে খোঁজে ধনাত্মক tabindex-ওয়ালা element, ছোট সংখ্যা আগে। তাই পাতার একদম নিচের বোতামটি সবার আগে focus পেল — screen reader ব্যবহারকারী বুঝতেই পারেন না পাতার শুরুটা পেরিয়ে গেলেন কি না।
  2. দ্বিতীয় Tab — খবর. এবার বাকি focus-যোগ্য element, HTML-এ লেখার ক্রমে। প্রথমে href-ওয়ালা লিংক।
  3. তৃতীয় Tab — খুঁজুন. আসল <button> কোনো attribute ছাড়াই focus পায়।
  4. চতুর্থ Tab — অফার. “লগইন (div)” বাদ — onclick থাকলেও div কি-বোর্ডের কাছে অদৃশ্য, কি-বোর্ড ব্যবহারকারী কখনো লগইন করতে পারবেন না। পরের div-এ tabindex="0" আছে বলে সে লাইনে ঢুকল।
  5. পঞ্চম Tab — ইমেইল. “বন্ধ” বোতাম tabindex="-1", তাই বোতাম হলেও Tab-এ বাদ। ইচ্ছা করে দিলে কাজের, ভুলে দিলে বোতামটি কি-বোর্ডে পৌঁছানো অসম্ভব।
  6. ষষ্ঠ Tab — পাতার বাইরে. focus পাতা ছেড়ে ব্রাউজারের ঠিকানা-বারে যায়। শিক্ষা: ক্রম বদলাতে চাইলে ধনাত্মক tabindex নয়, HTML-এ element-এর জায়গা বদলান।

div দিয়ে বানানো “বোতাম” কেন অর্ধেক বোতাম

অনেকে ভাবেন, div-এ tabindex="0" আর role="button" দিলেই সমস্যা শেষ। দেখুন সত্যিই শেষ কি না। প্রথমে তিনটিতেই মাউসে ক্লিক করুন, তারপর Tab দিয়ে প্রতিটিতে গিয়ে Enter আর Space চাপুন:

<div onclick="console.log('১: শুধু div — কাজ করল')">
  ১. শুধু div
</div>

<div role="button" tabindex="0"
     onclick="console.log('২: role + tabindex — কাজ করল')">
  ২. div + role="button" + tabindex="0"
</div>

<button type="button"
        onclick="console.log('৩: আসল button — কাজ করল')">
  ৩. আসল &lt;button&gt;
</button>

মাউসে তিনটিই কাজ করে। কি-বোর্ডে ১ নম্বরে পৌঁছানোই যায় না। ২ নম্বরে focus আসে, screen reader তাকে “বোতাম” বলেও ডাকে — কিন্তু Enter বা Space চাপলে কিছুই হয় না! কারণ role শুধু ঘোষণা করে, বোতামের আচরণ দেয় না; সেটা keydown শুনে নিজেকে লিখতে হয়। ৩ নম্বর আসল button — Enter আর Space দুটোতেই চলে, বাড়তি কোড ছাড়া। চেষ্টা করুন: ৩ নম্বরে disabled লিখুন — focus আর ক্লিক দুটোই নিজে থেকে বন্ধ, screen reader বলবে “অনুপলব্ধ”।

focus-এর দাগ মুছবেন না। পুরোনো অনেক CSS টেমপ্লেটে আছে *:focus { outline: none; } — দেখতে “পরিষ্কার” লাগে বলে। এতে কি-বোর্ড ব্যবহারকারী আর জানতেই পারেন না তিনি কোথায় আছেন — WCAG ২.৪.৭ (Focus Visible) ভাঙে। সুন্দর, স্পষ্ট focus স্টাইল কীভাবে বানাতে হয় (:focus-visible), তা পর্ব ৩৪ আর পর্ব ৪৫-এ দেখবেন।

৪ · প্রতিটি কন্ট্রোলের একটি নাম চাই — label, alt আর aria-*

পর্ব ০৫-এ লিংকের প্রসঙ্গে accessible name শব্দটা শুনেছেন। এবার পুরো ছবিটা দেখুন। Screen reader একটি কন্ট্রোলে এলে তিনটি জিনিস বলে: নাম (কী এটা), ভূমিকা (কোন ধরনের জিনিস — বোতাম, লিংক, ঘর) আর অবস্থা (চেক করা, খোলা, অনুপলব্ধ)। যেমন: “মোবাইল নম্বর, সম্পাদনা ঘর, আবশ্যক”। নাম না থাকলে শোনা যায় শুধু “বোতাম” — কিসের বোতাম, কেউ জানে না। ভাবুন bKash-এর মতো একটি অ্যাপে চারটি বোতাম, সবগুলো শুধু “বোতাম, বোতাম, বোতাম, বোতাম” — টাকা পাঠাবেন কোনটায়?

নামের উৎসগুলো

  • ভেতরের লেখা: <button>জমা দিন</button> — বোতাম আর লিংকের নাম নিজের লেখা থেকেই আসে। সবচেয়ে সহজ আর সবচেয়ে ভালো উৎস।
  • <label>: ফর্মের ঘরের নাম (পর্ব ০৮)। label-এ ক্লিক করলে ঘরটিতে focus যায় — হাত কাঁপে যাঁদের, তাঁদের বড় উপকার।
  • alt: ছবির নাম (পর্ব ০৬)। তথ্য বহন করা ছবিতে অর্থ লিখুন; সাজসজ্জার ছবিতে alt="", screen reader তখন এড়িয়ে যায়। লিংকের ভেতরে শুধু ছবি থাকলে alt-ই লিংকের নাম — তাই লিখুন লিংক কোথায় নেয়।
  • aria-label: চোখে দেখা যায় না এমন নাম, সরাসরি attribute-এ লেখা। দরকার পড়ে যখন পর্দায় কোনো লেখাই নেই — যেমন শুধু 🛒 আইকনের বোতাম: aria-label="কার্ট খুলুন".
  • aria-labelledby: “পাতার ওই লেখাটিই আমার নাম” — এক বা একাধিক element-এর id ফাঁকা দিয়ে লেখা হয়। পর্দার লেখা আর নাম তখন সব সময় এক থাকে।
  • aria-describedby: নাম নয়, বাড়তি বিবরণ — নাম আর ভূমিকার পরে একটু থেমে পড়া হয়। পাসওয়ার্ডের নিয়ম, নম্বরের ফরম্যাট বা ভুলের বার্তার জন্য আদর্শ।

একটি কন্ট্রোলে একাধিক উৎস থাকলে কে জেতে? ব্রাউজার একটি নির্দিষ্ট ক্রমে খোঁজে। একটি খোঁজার ঘরে ধাপে ধাপে উৎস যোগ করে দেখুন:

ধাপ ১কোনো উৎস নেই
<input type="search">
ধাপ ২title যোগ হলো
<input type="search" title="খোঁজার ঘর">
ধাপ ৩দৃশ্যমান label যোগ হলো
<label for="q">পণ্য খুঁজুন</label>
<input type="search" id="q" title="খোঁজার ঘর">
ধাপ ৪aria-label যোগ হলো
<label for="q">পণ্য খুঁজুন</label>
<input type="search" id="q" title="খোঁজার ঘর"
       aria-label="সার্চ">
ধাপ ৫aria-labelledby যোগ হলো
<h2 id="offer">আজকের অফার</h2>
<label for="q">পণ্য খুঁজুন</label>
<input type="search" id="q" title="খোঁজার ঘর"
       aria-label="সার্চ" aria-labelledby="offer">
  1. শূন্য অবস্থা. নাম নেই — screen reader শুধু ভূমিকা বলে, কী খুঁজবেন বোঝা যায় না। Lighthouse বা axe এখানে ভুল দেখাবে।
  2. title — শেষ ভরসা. অন্য কিছু না থাকলে ব্রাউজার title (মাউস রাখলে ভাসা লেখা) থেকে নাম নেয়। কিন্তু title ফোনে বা কি-বোর্ডে দেখা যায় না। placeholder-ও তেমনি দুর্বল শেষ ভরসা।
  3. দৃশ্যমান label — আদর্শ. নাম “পণ্য খুঁজুন”, title নেমে গেল বিবরণে। দেখা আর না-দেখা দুই পাঠক একই কথা পান। এই ধাপেই থামা উচিত।
  4. aria-label label-কে হারায়. নাম এখন “সার্চ”, অথচ পর্দায় “পণ্য খুঁজুন”। কণ্ঠ দিয়ে কম্পিউটার চালান যিনি, “পণ্য খুঁজুন-এ ক্লিক” বললে কিছু হবে না। WCAG ২.৫.৩ (Label in Name) বলে, দৃশ্যমান লেখা নামের ভেতরে থাকতেই হবে।
  5. aria-labelledby সবার ওপরে. id ধরে আনা লেখা সব উৎসকে হারায় — ভুল id দিলে নাম ফাঁকা, অথচ চোখে কিছু ধরা পড়ে না। ক্রম: aria-labelledby → aria-label → নিজস্ব HTML (label, alt, caption, legend) → ভেতরের লেখা (বোতাম-লিংকে) → title/placeholder. (পুরো নিয়মটি W3C-র “Accessible Name and Description Computation” স্পেসিফিকেশনে লেখা, এখানে সরল রূপ।)

এবার একটি ছোট পরীক্ষাগার। নিচের স্ক্রিপ্টটি ওপরের নিয়মের একটি সরল রূপ মেনে প্রতিটি কন্ট্রোলের নাম আর বিবরণ বের করে লিখে দেয় — screen reader মোটামুটি এগুলোই শোনাবে:

// accessible name খোঁজার সরল নিয়ম (আসল নিয়মের ছোট রূপ)
function accName(el) {
  const ids = el.getAttribute('aria-labelledby');
  if (ids) return ids.split(' ').map(i => document.getElementById(i).textContent.trim()).join(' ');
  if (el.hasAttribute('aria-label')) return el.getAttribute('aria-label');
  if (el.labels && el.labels.length) return el.labels[0].textContent.trim();
  if (el.tagName === 'IMG') return el.alt;
  return el.textContent.trim() || el.title || el.placeholder || '';
}
document.querySelectorAll('input, button, a[href], img').forEach((el) => {
  const nm = accName(el);
  const descId = el.getAttribute('aria-describedby');
  let line = el.tagName.toLowerCase() + ' → নাম: ' + (nm ? '"' + nm + '"' : '(নাম নেই!)');
  if (el.tagName === 'IMG' && el.alt === '') line = 'img → ফাঁকা alt: সাজসজ্জা, screen reader এড়িয়ে যাবে';
  if (descId) line += ' | বিবরণ: "' + document.getElementById(descId).textContent.trim() + '"';
  console.log(line);
});

আউটপুটে দেখবেন: মোবাইলের ঘরের নাম label থেকে, আর বিবরণে “১১ অঙ্কের নম্বর লিখুন”; খোঁজার ঘরের নাম শুধু placeholder থেকে (দুর্বল); ইমেইলের ঘর (নাম নেই!); কার্ট বোতাম “কার্ট খুলুন”; ✕ বোতামের নাম স্রেফ “✕” — screen reader এটাকে “গুণ চিহ্ন” বা “multiplication x” পড়তে পারে, বন্ধ করার কথা কেউ বুঝবে না; ডাউনলোড বোতাম “ডাউনলোড মাসিক রসিদ” (নিজের id আর শিরোনামের id জুড়ে); প্রথম ছবি লোগো, দ্বিতীয়টি সাজসজ্জা। চেষ্টা করুন: ইমেইলের ঘরের জন্য একটি <label> যোগ করুন, আর ✕ বোতামে aria-label="বন্ধ করুন" দিন — আবার চালিয়ে দেখুন নাম কীভাবে বদলায়।

৫ · Accessibility tree — screen reader আসলে কী পড়ে

প্রচলিত ভুল ধারণা: screen reader পাতার HTML পড়ে। আসলে NVDA, VoiceOver বা TalkBack আপনার HTML দেখেই না — পড়ে ব্রাউজারের বানানো একটি গাছ, যার নাম accessibility tree. পর্ব ০১-এ দেখেছেন ব্রাউজার HTML থেকে DOM বানায়; DOM থেকে সে বানায় আরেকটি ছোট, পরিষ্কার গাছ — যেখানে শুধু অর্থবহ জিনিস থাকে, প্রত্যেকের নাম, ভূমিকা আর অবস্থাসহ। পুরো যাত্রাটা ধাপে ধাপে দেখুন:

  1. HTML<button>আপনার লেখা
  2. DOMHTMLButtonElementব্রাউজারের গাছ
  3. A11y treebutton "জমা দিন"নাম, ভূমিকা, অবস্থা
  4. OS APIUIA / AX / Androidঅপারেটিং সিস্টেম
  5. Screen reader“জমা দিন, বোতাম”কণ্ঠ বা ব্রেইল
  1. আপনার HTML. শুধু একটি লাইন — <button> আর তার লেখা। কোনো ARIA নেই, দরকারও নেই।
  2. DOM. HTML parser এটিকে একটি node বানাল। CSS আর JavaScript এই DOM-এর ওপরই কাজ করে।
  3. Accessibility tree. ব্রাউজার প্রতিটি DOM node দেখে ঠিক করে তার ভূমিকা (role), নাম আর অবস্থা। শুধু সাজানোর div-span প্রায় বাদ পড়ে; display: none বা hidden করা অংশ পুরো বাদ। <button>-এর role নিজে থেকেই “button” — একে বলে implicit role.
  4. অপারেটিং সিস্টেমের API. ব্রাউজার গাছটি অপারেটিং সিস্টেমের accessibility API দিয়ে প্রকাশ করে — একই API দিয়ে screen reader Word বা ফোনের যেকোনো অ্যাপ পড়ে। তাই ওয়েবের বোতাম আর অ্যাপের বোতাম তার কাছে একই জিনিস।
  5. Screen reader. API থেকে নাম-ভূমিকা-অবস্থা নিয়ে কণ্ঠে বলে, বা ব্রেইল ডিসপ্লেতে দেখায়। শব্দ ও ক্রম screen reader-ভেদে আলাদা, তথ্য একই। শিকলের কোথাও তথ্য হারালে — যেমন div-এ role নেই — শ্রোতার কাছে কিছুই পৌঁছায় না।

এই গাছ নিজের চোখে দেখতে পারেন: Chrome বা Edge-এ যেকোনো element-এ রাইট-ক্লিক করে “Inspect”, তারপর Elements প্যানেলের পাশের Accessibility ট্যাব। সেখানে দেখাবে element-টির Name, Role, আর নামটি কোন উৎস থেকে এসেছে। Firefox-এ আছে আলাদা “Accessibility” প্যানেল; DevTools নিয়ে পুরো আলোচনা পর্ব ৪৭-এ।

আরও গভীরে: HTML-এর কোন element accessibility tree-তে কোন role পাবে, তা লেখা আছে W3C-র “HTML Accessibility API Mappings” (HTML-AAM) স্পেসিফিকেশনে, আর নাম গণনার পুরো নিয়ম “Accessible Name and Description Computation”-এ — এখানে একটি element নিজের ভেতরের লেখা থেকে নাম পাবে কি না, লুকানো লেখা গোনা হবে কি না, এমন খুঁটিনাটিও আছে। ব্রাউজার গাছটি তৈরি করে কিছুটা অলসভাবে — সাধারণত কোনো সহায়ক প্রযুক্তি চালু না থাকলে পুরো গাছ বানায় না, যাতে পারফরম্যান্স না কমে। আর Windows-এ পুরোনো MSAA থেকে শুরু করে IAccessible2 আর UI Automation — কয়েক প্রজন্মের API পাশাপাশি টিকে আছে, কারণ বিভিন্ন screen reader বিভিন্ন API-তে অভ্যস্ত।

৬ · ARIA — প্রথম নিয়ম, আর কেন খারাপ ARIA-র চেয়ে ARIA না থাকা ভালো

২০০০-এর দশকের মাঝামাঝি ওয়েব হঠাৎ “অ্যাপ” হয়ে উঠল — Gmail, Google Maps, ড্রপডাউন মেনু, ট্যাব, স্লাইডার, সবই JavaScript আর div দিয়ে বানানো। HTML-এ তখন এসব কন্ট্রোলের element ছিল না, ফলে screen reader-এর কাছে এগুলো অর্থহীন div. সমস্যা মেটাতে W3C বানাল WAI-ARIA (Accessible Rich Internet Applications) — কিছু attribute, যা দিয়ে কোনো element-কে accessibility tree-তে বাড়তি অর্থ দেওয়া যায়। ২০১৪ সালে ARIA 1.0 আনুষ্ঠানিক মান হয়, আর এখনকার সংস্করণ ARIA 1.2.

ARIA-র তিন রকম জিনিস আছে:

  • Role (ভূমিকা): role="button", role="dialog", role="tablist", role="alert" — “আমি কী”।
  • Property (বৈশিষ্ট্য): aria-label, aria-describedby, aria-controls — সাধারণত খুব বেশি বদলায় না।
  • State (অবস্থা): aria-expanded, aria-checked, aria-pressed, aria-current — ব্যবহারকারীর কাজে বদলায়, আর বদলানোর দায়িত্ব আপনার JavaScript-এর।
ARIA কেবল accessibility tree বদলায় — চেহারা নয়, আচরণ নয়।

role="button" দিলে screen reader বলবে “বোতাম”, কিন্তু element-টি focus পাবে না, Enter-এ চলবে না — অংশ ৩-এর এডিটরেই দেখেছেন। তাই W3C-র “Using ARIA” নির্দেশিকায় পাঁচটি নিয়ম আছে, যার প্রথমটি সবচেয়ে বিখ্যাত:

ARIA-র প্রথম নিয়ম

যে অর্থ ও আচরণ আপনার দরকার, তা যদি কোনো নিজস্ব HTML element বা attribute-এ আগে থেকেই থাকে — তাহলে ARIA দিয়ে অন্য element-কে নতুন ভূমিকা না দিয়ে সেই নিজস্ব element-টিই ব্যবহার করুন। <div role="button"> নয়, <button>. <div role="navigation"> নয়, <nav>. <span role="checkbox"> নয়, <input type="checkbox">.

বাকি চারটি নিয়ম সংক্ষেপে: (২) একান্ত দরকার না হলে নিজস্ব element-এর অর্থ বদলাবেন না (<h2 role="tab"> নয়); (৩) ARIA দিয়ে বানানো প্রতিটি ইন্টারঅ্যাকটিভ কন্ট্রোল কি-বোর্ডে চলতে হবে; (৪) focus পায় এমন element-এ কখনো aria-hidden="true" বা role="presentation" দেবেন না; (৫) প্রতিটি ইন্টারঅ্যাকটিভ element-এর একটি accessible name থাকতে হবে।

W3C-র ARIA Authoring Practices Guide-এর শুরুতেই একটি সতর্কবাণী লেখা: “No ARIA is better than bad ARIA” — খারাপ ARIA-র চেয়ে ARIA না থাকা ভালো। কেন? ARIA ছাড়া div-কে screen reader অন্তত সাধারণ লেখা হিসেবে পড়ে। কিন্তু ভুল ARIA মিথ্যা প্রতিশ্রুতি দেয় — “আমি বোতাম” বলে চলে না, “খোলা” বলে আসলে বন্ধ। মিথ্যা তথ্য অনুপস্থিত তথ্যের চেয়ে বেশি বিপজ্জনক। WebAIM প্রতি বছর ১০ লাখ জনপ্রিয় ওয়েবসাইটের হোমপেজ পরীক্ষা করে (WebAIM Million) — সেখানে বারবার দেখা গেছে, যেসব পাতায় ARIA বেশি, সেগুলোতে গড়ে ধরা-পড়া ভুলও বেশি। ARIA নিজে খারাপ নয়; সমস্যা হলো না বুঝে ব্যবহার।

ভুল ARIAকী হয়ঠিক উপায়
<div role="button"> (tabindex, keydown ছাড়া)বোতাম বলে, কি-বোর্ডে চলে না<button>
<button aria-label="button">শোনায় “button, বোতাম” — অর্থহীনকাজটা লিখুন: “সার্চ করুন”
<a href="…" aria-hidden="true">focus পায় কিন্তু নীরব — “ভূত লিংক”লুকাতে চাইলে পুরো সরান বা hidden
<ul role="menu"> সাইটের মেনুতেscreen reader ডেস্কটপ অ্যাপের মেনুর মতো তীর-চিহ্নের আচরণ আশা করে<nav> > <ul> > লিংক (পর্ব ০৭)

৭ · role আর state — aria-expanded, aria-current, aria-hidden আর live region

প্রথম নিয়ম মেনেও কিছু জায়গায় ARIA লাগে — যেখানে HTML-এ সেই অর্থ প্রকাশের উপায় নেই। সবচেয়ে বেশি কাজে লাগে চারটি।

aria-expanded — খোলা না বন্ধ

প্রশ্ন-উত্তরের (FAQ) একটি অংশ, যেখানে বোতাম চাপলে উত্তর খোলে। চোখে দেখা পাঠক তীর-চিহ্নের দিক দেখে বোঝেন খোলা না বন্ধ। Screen reader-কে সেটি জানায় aria-expanded — আর মানটি বদলাতে হয় আপনার স্ক্রিপ্টকেই। বোতামটি আসল <button>, তাই কি-বোর্ড বিনামূল্যে:

<h3>
  <button id="faqBtn" type="button" aria-expanded="false" aria-controls="faq1">
    <span aria-hidden="true">▸</span> ডেলিভারি চার্জ কত?
  </button>
</h3>
<div id="faq1" hidden>
  ঢাকার ভেতরে ৬০ টাকা, বাইরে ১২০ টাকা (উদাহরণ)।
</div>

<script>
  const faqBtn = document.getElementById('faqBtn');
  faqBtn.addEventListener('click', () => {
    const isOpen = faqBtn.getAttribute('aria-expanded') === 'true';
    faqBtn.setAttribute('aria-expanded', String(!isOpen));
    document.getElementById('faq1').hidden = isOpen;
    faqBtn.firstElementChild.textContent = isOpen ? '▸' : '▾';
    console.log('aria-expanded =', faqBtn.getAttribute('aria-expanded'));
  });
</script>

বোতামে ক্লিক (বা Tab দিয়ে এসে Enter/Space) করলে উত্তর খোলে, তীর ঘুরে যায়, আর নিচে লেখা হয় aria-expanded = true; আবার চাপলে বন্ধ আর false. Screen reader শোনাবে “ডেলিভারি চার্জ কত?, বোতাম, সংকুচিত” বা “প্রসারিত”। তীর-চিহ্নে aria-hidden="true" আছে, তাই নামের মধ্যে “ত্রিভুজ” জাতীয় কিছু পড়া হয় না। চেষ্টা করুন: স্ক্রিপ্ট থেকে setAttribute-এর লাইনটি মুছে দিন — চেহারা ঠিকই বদলাবে, কিন্তু মান চিরকাল false থাকবে; শ্রোতা শুনবেন “সংকুচিত”, অথচ উত্তর খোলা। এটাই “খারাপ ARIA”. মনে রাখুন, পর্ব ১১-এর নিজস্ব <details>/<summary> এই পুরো কাজটা কোনো স্ক্রিপ্ট ছাড়াই করে — প্রথম নিয়ম অনুযায়ী সেটিই প্রথম পছন্দ।

aria-current — “আপনি এখানে”

পর্ব ০৭-এ মেনুতে দেখেছেন: <a href="/contact.html" aria-current="page"> জানায় এটি বর্তমান পাতা। মান হতে পারে page (মেনুতে বর্তমান পাতা), step (ধাপে ধাপে ফর্মের বর্তমান ধাপ), location (breadcrumb বা মানচিত্রে), date (ক্যালেন্ডারে আজকের দিন)। একটি তালিকায় একটিই “বর্তমান” থাকবে। আর একই attribute ধরে CSS-এ স্টাইল দেওয়া যায় ([aria-current="page"]) — ফলে চেহারা আর অর্থ কখনো আলাদা হয়ে যায় না।

aria-hidden — শুধু screen reader থেকে লুকানো

aria-hidden="true" একটি অংশকে accessibility tree থেকে সরিয়ে দেয়, কিন্তু পর্দায় রেখে দেয়। কাজে লাগে সাজসজ্জার আইকনে, যার পাশে আগে থেকেই লেখা আছে — এই পাতার প্রতিটি Font Awesome আইকনেও তাই এটি দেওয়া। সাবধান: এটি focus আটকায় না, তাই লিংক-বোতামে বা তাদের পূর্বপুরুষে কখনো নয়; আর সবার কাছ থেকে লুকাতে চাইলে hidden attribute বা CSS-এর display: none. উল্টো কাজটি — পর্দায় না দেখিয়ে শুধু screen reader-কে পড়ানো — একটি CSS কৌশল (“visually hidden”), যা পর্ব ৪৫-এ শিখবেন।

Live region — না সরেও খবর পাওয়া

অনলাইন দোকানে “কার্টে যোগ করুন” চাপলেন, পাতার কোণে লেখা এল “কার্টে যোগ হয়েছে”। কিন্তু screen reader-এর focus বোতামেই — সে জানেই না অন্য কোথাও কিছু বদলেছে। এর সমাধান live region: পাতার একটি অংশকে আগেই চিহ্নিত করে রাখা, “এখানে লেখা বদলালে শ্রোতাকে জানিও”।

  • aria-live="polite" বা role="status" — শ্রোতা এখন যা শুনছেন, তা শেষ হলে বলবে। বেশিরভাগ খবরের জন্য এটিই ঠিক।
  • aria-live="assertive" বা role="alert" — যা চলছে থামিয়ে সঙ্গে সঙ্গে বলবে। শুধু জরুরি ভুল বা সতর্কতার জন্য; বেশি দিলে বিরক্তিকর।
<p>খাঁটি সরিষার তেল, ১ লিটার</p>
<button type="button" id="addBtn">কার্টে যোগ করুন</button>

<!-- পাতা খোলার সময়েই থাকবে, শুরুতে ফাঁকা -->
<p role="status" id="cartMsg"></p>

<script>
  let cartCount = 0;
  document.getElementById('addBtn').addEventListener('click', () => {
    cartCount++;
    const msg = 'কার্টে যোগ হয়েছে। কার্টে এখন মোট ' + cartCount + 'টি পণ্য';
    document.getElementById('cartMsg').textContent = msg;
    console.log('status-এ লেখা হলো →', msg);
  });
</script>

বোতাম চাপলে নিচে বার্তাটি আসে, আর প্রতিবার সংখ্যা বাড়ে। চোখে দেখতে দুটোর পার্থক্য নেই, কিন্তু role="status" থাকায় screen reader focus বোতাম থেকে না সরিয়েই বার্তাটি পড়ে শোনাবে — WCAG ৪.১.৩ (Status Messages) ঠিক এটাই চায়। চেষ্টা করুন: role="status"-কে role="alert" করুন — এখন বার্তা আসবে জরুরি সুরে, যা চলছিল থামিয়ে। খেয়াল করুন: live region পাতায় আগে থেকেই থাকতে হয় — বার্তার সাথে নতুন element বানিয়ে ঢোকালে অনেক screen reader ঘোষণাই করে না।

৮ · কাঠামো আর ভাষা — heading, landmark, skip link আর lang

চোখে দেখা পাঠক পাতায় ঢুকে এক পলকে চোখ বুলিয়ে নেন। Screen reader ব্যবহারকারী একই কাজ করেন কাঠামো দিয়ে — NVDA-তে H চাপলে পরের heading-এ, D চাপলে পরের landmark-এ লাফ। WebAIM-এর screen reader ব্যবহারকারী জরিপে বারবার দেখা গেছে, লম্বা পাতায় তথ্য খুঁজতে বেশিরভাগ ব্যবহারকারী প্রথমে heading ধরেই চলেন।

  • Heading (পর্ব ০৪): পাতায় একটি <h1>, তারপর ক্রম না ভেঙে h2, h3 — বইয়ের সূচিপত্রের মতো। লেখা বড় দেখানোর জন্য heading নয়; অংশের শিরোনাম বলেই heading.
  • Landmark (পর্ব ১০): <header>, <nav>, <main>, <aside>, <footer> — পাতার বড় অঞ্চলগুলো। একই ধরনের দুটি থাকলে aria-label দিয়ে আলাদা নাম দিন (“প্রধান মেনু”, “পাদদেশের মেনু”)।
  • Skip link: পাতার একদম শুরুতে একটি লিংক — “সরাসরি মূল লেখায় যান”। প্রতিটি পাতায় ২০টি মেনু-লিংক Tab দিয়ে পেরিয়ে তবে লেখায় পৌঁছানো কি-বোর্ড ব্যবহারকারীর জন্য ক্লান্তিকর; WCAG ২.৪.১ (Bypass Blocks) এই শর্টকাট চায়। এই পাতারও একদম শুরুতে একটি আছে — পাতা খুলে প্রথমবার Tab চাপলেই দেখবেন।

ভাষা — বাংলা আর ইংরেজির মিশ্রণে lang

Screen reader-এর কণ্ঠ জানে না লেখাটি কোন ভাষার — জানে lang attribute থেকে। <html lang="bn"> না থাকলে সে হয়তো ইংরেজি কণ্ঠে বাংলা পড়তে চেষ্টা করবে, বা অংশটি বাদ দেবে। বাংলা পাতার মাঝে পুরো একটি ইংরেজি বাক্য থাকলে তাকে <span lang="en"> দিয়ে চিহ্নিত করুন — ভাষা বদলাতে পারে এমন screen reader (যেমন NVDA) তখন ঠিক উচ্চারণে পড়ে। WCAG ৩.১.১ পাতার ভাষা আর ৩.১.২ অংশের ভাষা চায়। (“HTML”, “Wi-Fi”-এর মতো বাংলায় মিশে যাওয়া শব্দের জন্য আলাদা lang দরকার নেই।) বাংলা লেখার বাকি দিক — UTF-8, ফন্ট — পর্ব ১৪-এ।

<!doctype html>
<html lang="bn">
<head><meta charset="utf-8"><title>ভর্তি বিজ্ঞপ্তি</title>
  <style> :target { outline: 3px solid orange; } </style>
</head>
<body>
  <a href="#main">সরাসরি মূল লেখায় যান</a>
  <header>
    <nav aria-label="প্রধান মেনু">
      <a href="#home">হোম</a> · <a href="#notice">নোটিশ</a> · <a href="#help">সাহায্য</a>
    </nav>
  </header>
  <main id="main" tabindex="-1">
    <h1>ভর্তি বিজ্ঞপ্তি (উদাহরণ)</h1>
    <p>আবেদন করতে <span lang="en">Online Application Form</span> পূরণ করুন।</p>
  </main>
  <footer>যোগাযোগ: হেল্পলাইন</footer>
  <script>
    console.log('পাতার ভাষা:', document.documentElement.lang);
    document.querySelectorAll('[lang]').forEach((n) => console.log(n.tagName, '→', n.lang));
  </script>
</body>
</html>

নিচে দেখবেন পাতার ভাষা: bn, তারপর HTML → bn আর SPAN → en. প্রিভিউতে প্রথম লিংক “সরাসরি মূল লেখায় যান”-এ ক্লিক করুন (বা Tab দিয়ে এসে Enter) — <main>-এর চারপাশে কমলা দাগ আসবে, আর পরের Tab শুরু হবে মূল লেখা থেকে, মেনু থেকে নয়। tabindex="-1" থাকায় main নিজে focus নিতে পারে, Tab-এর তালিকায় না ঢুকেও — কিছু ব্রাউজার-screen reader জুটিতে লাফটা এতে আরও নির্ভরযোগ্য হয়। চেষ্টা করুন: ফুটারের লেখায় একটি ইংরেজি বাক্য যোগ করে তাকে <span lang="en"> দিয়ে মুড়ুন — তালিকায় আরেকটি লাইন আসবে। বাস্তব সাইটে skip link-কে সাধারণত লুকিয়ে রাখা হয়, focus পেলে দেখা যায়; সেই CSS পর্ব ৪৫-এ।

৯ · পরীক্ষা করবেন কীভাবে — কি-বোর্ড, screen reader, DevTools আর automated টুল

অ্যাক্সেসিবিলিটি মুখস্থ করার বিষয় নয়, পরীক্ষা করে দেখার বিষয়। পেশাদাররা চার স্তরে পরীক্ষা করেন — সহজ থেকে গভীরে।

সবচেয়ে সস্তা, সবচেয়ে কাজের পরীক্ষা — পাঁচ মিনিট লাগে। মাউস সরিয়ে রেখে পাতার শুরু থেকে শুধু Tab, Shift+Tab, Enter, Space, তীর আর Esc দিয়ে চলুন। খেয়াল করুন:

  • প্রতিটি লিংক, বোতাম, ঘরে পৌঁছানো যায়? মাউসে যা করা যায়, সব করা যায়?
  • focus সব সময় চোখে পড়ে? কোনো sticky হেডারের নিচে ঢাকা পড়ে না?
  • ক্রম যৌক্তিক — ওপর থেকে নিচে, বাঁ থেকে ডানে? হঠাৎ লাফ নেই?
  • কোথাও আটকে যান না? খোলা পপআপ Esc-এ বন্ধ হয়, আর focus যেখান থেকে খুলেছিলেন সেখানে ফেরে?

নিজে একবার শুনে দেখুন — বিনামূল্যেই সম্ভব:

  • NVDA (Windows): বিনামূল্যের, open-source; nvaccess.org থেকে নামান। H দিয়ে heading, D দিয়ে landmark, Tab দিয়ে কন্ট্রোল, Insert+F7 দিয়ে লিংক-heading-এর তালিকা। Windows-এ নিজস্ব Narrator-ও আছে (Ctrl+Win+Enter).
  • TalkBack (Android): Settings → Accessibility → TalkBack. ডানে-বাঁয়ে সোয়াইপে পরের-আগের অংশ, দুবার টোকায় চাপা। বাংলাদেশের বেশিরভাগ পাঠক Android-এ — তাই এটি সবচেয়ে বাস্তব পরীক্ষা।
  • VoiceOver (Mac, iPhone): অপারেটিং সিস্টেমে ভেতরেই আছে; Mac-এ Cmd+F5, iPhone-এ Settings → Accessibility → VoiceOver.
  • Accessibility ট্যাব (Chrome/Edge-এর Elements প্যানেলে, Firefox-এ আলাদা প্যানেল): যেকোনো element-এর Name, Role, State আর নামের উৎস।
  • Lighthouse (Chrome DevTools-এর একটি প্যানেল): পাতার একটি Accessibility স্কোর আর ভুলের তালিকা দেয়; এর ভেতরের পরীক্ষাগুলো চালায় axe-core নামের open-source ইঞ্জিন।

Lighthouse, axe DevTools (Deque-এর ব্রাউজার এক্সটেনশন), WebAIM-এর WAVE, Microsoft-এর Accessibility Insights — সবই বিনামূল্যে শুরু করা যায়। এরা দ্রুত ধরে: alt নেই, label নেই, ভুল ARIA, contrast কম, heading-এর ক্রম ভাঙা, পাতায় lang নেই।

কিন্তু alt-এর অর্থ ঠিক কি না, Tab-এর ক্রম যৌক্তিক কি না — এসব এরা ধরতে পারে না। বিভিন্ন গবেষণায় দেখা গেছে, automated টুল মোট সমস্যার একটি অংশই ধরে — অনেক হিসাবে অর্ধেক বা তার কম।

Lighthouse-এ ১০০ মানে অ্যাক্সেসিবল নয়। সব বোতামে aria-label="button" লিখলে স্কোর বাড়তে পারে, কিন্তু শ্রোতার কাছে পাতা আরও খারাপ হয়। স্কোর হলো ন্যূনতম পরীক্ষা পার হওয়ার প্রমাণ — শেষ রায় দেয় মানুষ: আপনার কি-বোর্ড টেস্ট, screen reader-এ শোনা, আর সম্ভব হলে প্রতিবন্ধী ব্যবহারকারীদের নিয়ে সরাসরি পরীক্ষা।

আসছে পর্ব ৪৫-এ — CSS-এর দিক: এই পর্বে HTML-এর দিক দেখলেন। অ্যাক্সেসিবিলিটির বড় একটি অংশ CSS-এর হাতেও: লেখা আর পটভূমির রঙের contrast (সাধারণ লেখায় অন্তত 4.5:1), সুন্দর কিন্তু স্পষ্ট focus স্টাইল, যাঁদের নড়াচড়া দেখলে মাথা ঘোরে তাঁদের জন্য prefers-reduced-motion, লেখা ২০০% বড় করলেও না ভাঙা লেআউট, আর visually-hidden কৌশল। এগুলো পর্ব ৪৫ (অ্যাক্সেসিবল CSS)-এ বিস্তারিত।

১০ · AI-এর যুগে — অ্যাক্সেসিবল HTML-এর কাজ AI-কে দিলে

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

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

AI-এর ভুলকেন সমস্যাঠিক উপায়
div-soup: <div onclick> দিয়ে বোতাম, মেনু, ট্যাবকি-বোর্ডে চলে না, accessibility tree-তে অর্থ নেই<button>, <a href>, <nav>
সব জায়গায় ARIA ছিটানো: role="button" আসল button-এ, aria-label দৃশ্যমান লেখার ওপরঅপ্রয়োজনীয় বা পরস্পরবিরোধী তথ্যপ্রথম নিয়ম — আগে নিজস্ব HTML
শুধু placeholder, কোনো label নেইনাম দুর্বল, লিখতে শুরু করলে নির্দেশনা হারায়দৃশ্যমান <label>
আইকন-বোতামে নাম নেই, বা alt="image"শ্রোতা শোনেন শুধু “বোতাম” বা “image”কাজ বোঝানো নাম বা alt
tabindex="1", outline: noneTab-এর ক্রম ভাঙে, focus অদৃশ্য0/-1 আর স্পষ্ট focus স্টাইল
“এটা WCAG compliant” বলে দাবিAI নিজে screen reader-এ শোনেনি, পরীক্ষা করেনিনিজে পরীক্ষা করুন

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

তুমি একজন অ্যাক্সেসিবিলিটি-সচেতন ফ্রন্ট-এন্ড ডেভেলপার, WCAG 2.2 AA মেনে কাজ করো। আমার অনলাইন দোকানের জন্য একটি পণ্যের কার্ড বানাও: ছবি, নাম, দাম, "কার্টে যোগ করুন" বোতাম, আর একটি আইকন-বোতাম (পছন্দের তালিকায় রাখা)। শর্ত: ১. প্রথম নিয়ম মানবে: আসল button আর a ব্যবহার করবে, div-এ onclick নয়; দরকার ছাড়া কোনো ARIA দেবে না। ২. ছবির অর্থবহ alt, আইকন-বোতামে aria-label, আইকনে aria-hidden="true". ৩. "কার্টে যোগ হয়েছে" বার্তা একটি role="status" অংশে দেখাবে, যা পাতায় আগে থেকেই থাকবে। ৪. tabindex-এ ধনাত্মক সংখ্যা দেবে না, outline: none দেবে না। ৫. পাতার lang="bn". শেষে একটি তালিকা দাও: প্রতিটি কন্ট্রোলের accessible name আর role কী হবে, এবং কোন ARIA কেন দিলে বা কেন দিলে না।

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

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

  • WCAG-এর চার নীতি কী? — POUR: Perceivable, Operable, Understandable, Robust; স্তর A, AA, AAA — সাধারণ লক্ষ্য AA.
  • tabindex="0" আর tabindex="-1"-এর পার্থক্য? — 0 স্বাভাবিক Tab-ক্রমে ঢোকায়; -1 Tab-এ আনে না, শুধু স্ক্রিপ্টে focus দেওয়া যায়; ধনাত্মক মান এড়াতে হয়।
  • ARIA-র প্রথম নিয়ম কী? — নিজস্ব HTML element বা attribute দিয়ে কাজ হলে ARIA নয়, সেটিই ব্যবহার করুন।
  • aria-label, aria-labelledby আর aria-describedby-এর পার্থক্য? — প্রথম দুটি নাম দেয় (লেখা সরাসরি বনাম অন্য element-এর id থেকে), তৃতীয়টি বাড়তি বিবরণ দেয়।

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

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

প্র ০১ARIA তো অ্যাক্সেসিবিলিটি বাড়ানোর জন্যই বানানো — তাহলে “খারাপ ARIA-র চেয়ে ARIA না থাকা ভালো” কেন বলা হয়?

ARIA-র জন্ম একটি বাস্তব সংকট থেকে। ২০০০-এর দশকের মাঝামাঝি AJAX-এর যুগে ওয়েবসাইটগুলো ডেস্কটপ অ্যাপের মতো আচরণ করতে শুরু করল — ড্রপডাউন, ট্যাব, ট্রি, স্লাইডার — অথচ HTML-এ এগুলোর কোনো element ছিল না। ডেভেলপাররা div আর JavaScript দিয়ে সব বানাতেন, আর screen reader-এর কাছে সেগুলো ছিল অর্থহীন লেখার স্তূপ। W3C-র WAI তাই একটি “অনুবাদের ভাষা” বানাল: element যা-ই হোক, accessibility tree-তে তাকে একটি role, state আর property দেওয়া যাবে। ২০১৪ সালে এটি আনুষ্ঠানিক মান হয়।

কিন্তু ARIA-র নকশাতেই একটি সূক্ষ্ম ফাঁদ আছে: এটি শুধু ঘোষণা করে, কিছু করে না। role="checkbox" দিলে screen reader বলবে “চেকবক্স, চেক করা নেই” — কিন্তু Space চাপলে চেক হবে না, aria-checked নিজে বদলাবে না, ফর্মের সাথে মানও যাবে না। প্রতিটি আচরণ হাতে লিখতে হয়, আর একটি বাদ পড়লেই ব্যবহারকারী এমন কিছুর সামনে দাঁড়ান যা নিজেকে চেকবক্স বলে কিন্তু চেকবক্সের মতো চলে না।

এখানেই অনুপস্থিত আর মিথ্যা তথ্যের পার্থক্য। ARIA না থাকলে screen reader ব্যবহারকারী একটি অচেনা লেখা পান — অভিজ্ঞ ব্যবহারকারীরা তখন অনুমান করেন, চারপাশ খোঁজেন, বিকল্প পথ নেন। কিন্তু ভুল ARIA তাঁকে নিশ্চিত করে বলে “এটা বোতাম”, “মেনু খোলা”, “এখানে কিছু নেই” — তিনি সেই কথায় বিশ্বাস করে কাজ করেন, আর ব্যর্থ হন। role="menu" একটি সাধারণ উদাহরণ: ডেস্কটপ অ্যাপের মেনুর মতো তীর-চিহ্নে চলার প্রতিশ্রুতি দেয়, অথচ সাধারণ সাইটের লিংক-তালিকায় সেই আচরণ থাকে না — screen reader Tab-এর বদলে তীর-চিহ্নের মোডে চলে যায়, আর ব্যবহারকারী আটকে পড়েন।

মূল উপলব্ধি: ARIA হলো চিকিৎসকের ওষুধের মতো — সঠিক রোগে সঠিক মাত্রায় জীবন বাঁচায়, ভুল জায়গায় ক্ষতি করে। আগে নিজস্ব HTML-কে কাজ করতে দিন; HTML যেখানে থামে, সেখানে বুঝে-শুনে ARIA.

প্র ০২Lighthouse বা axe-এর মতো automated টুল কেন সব অ্যাক্সেসিবিলিটি সমস্যা ধরতে পারে না — আর তাহলে এদের দাম কী?

কারণ অ্যাক্সেসিবিলিটির অনেক প্রশ্ন আসলে অর্থের প্রশ্ন, আর অর্থ বোঝা যন্ত্রের পক্ষে কঠিন। একটি টুল সহজেই দেখতে পারে ছবিতে alt attribute আছে কি না। কিন্তু alt="ছবি", alt="IMG_2041.jpg" আর alt="বন্যায় ডুবে যাওয়া সিলেটের একটি রাস্তা" — তিনটিতেই attribute আছে, টুল তিনটিকেই পাস দিতে পারে। কোনটি সত্যিকারের তথ্য দেয়, সেটা বোঝে মানুষ।

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

এর প্রমাণও আছে। ২০১৭ সালে যুক্তরাজ্যের সরকারি ডিজিটাল সেবা (GDS) ইচ্ছা করে অনেক রকম ভুলে ভরা একটি পরীক্ষার পাতা বানিয়ে জনপ্রিয় automated টুলগুলো দিয়ে পরীক্ষা করেছিল — সেরা টুলটিও সব ভুলের অর্ধেকও ধরতে পারেনি, আর কিছু ভুল কোনো টুলই ধরেনি। পরবর্তী বিভিন্ন হিসাবেও সংখ্যাটা মোটামুটি একই ঘরে থাকে: অর্ধেক বা তার কম।

তবু টুলের দাম অনেক: এরা সবচেয়ে সাধারণ ভুলগুলো (label নেই, contrast কম, alt নেই) সেকেন্ডে হাজার পাতায় ধরে, কোড বদলানোর সময় স্বয়ংক্রিয়ভাবে চালিয়ে পুরোনো ভুল ফিরে আসা আটকায়, আর প্রতিটি ভুলের সাথে ঠিক করার উপায় শেখায়।

তাই পেশাদার দলগুলো সাধারণত তিন স্তরে কাজ করে: কোডে স্বয়ংক্রিয় পরীক্ষা, প্রতিটি নতুন অংশে হাতে কি-বোর্ড ও screen reader পরীক্ষা, আর বড় প্রকাশের আগে প্রতিবন্ধী ব্যবহারকারীদের নিয়ে সরাসরি পরীক্ষা।

মূল উপলব্ধি: automated টুল হলো বানান-পরীক্ষকের মতো — ভুল বানান ধরে, কিন্তু রচনাটি ভালো হলো কি না বলতে পারে না। টুল দিয়ে শুরু করুন, শেষ করুন মানুষের পরীক্ষা দিয়ে।

প্র ০৩অ্যাক্সেসিবিলিটি কি শুধু প্রতিবন্ধী মানুষের জন্য একটি “বাড়তি খরচ” — নাকি সবার লাভ?

ইতিহাস বারবার উল্টো প্রমাণ দিয়েছে। নগর-পরিকল্পনায় একটি বিখ্যাত ধারণা আছে — curb-cut effect. যুক্তরাষ্ট্রে বিশেষ করে ১৯৭০-এর দশকে প্রতিবন্ধী অধিকারকর্মীদের আন্দোলনের ফলে হুইলচেয়ারের জন্য ফুটপাতের কিনারা কেটে ঢাল বানানো ছড়িয়ে পড়ে। দেখা গেল, সেই ঢাল সবচেয়ে বেশি ব্যবহার করছেন স্ট্রলার ঠেলা বাবা-মা, ট্রলি টানা যাত্রী, সাইকেল আরোহী, ডেলিভারির লোক। একটি গোষ্ঠীর জন্য বানানো সমাধান সবার জীবন সহজ করল।

ওয়েবে উদাহরণ অসংখ্য। ক্যাপশন বধিরদের জন্য শুরু, এখন শব্দ বন্ধ রেখে ভিডিও দেখা বিপুল মানুষ পড়েন। ছবির alt screen reader-এর জন্য, কিন্তু ধীর ইন্টারনেটে সবাইকে তথ্য দেয়, সার্চ ইঞ্জিনকেও। ভালো heading-কাঠামো চোখ বুলিয়ে পড়া সবার জন্য। এমনকি ওয়েব পড়া AI টুলও অনেকটা screen reader-এর মতো কাঠামো ধরে পড়ে।

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

আর ভুলবেন না, আজকের তরুণ ডেভেলপারও একদিন বয়স্ক ব্যবহারকারী হবেন — চোখ দুর্বল হবে, হাত ধীর হবে। আজ যে পাতা আপনি বানাচ্ছেন, কাল হয়তো সেটি আপনাকেই ব্যবহার করতে হবে।

মূল উপলব্ধি: অ্যাক্সেসিবিলিটি দানের কাজ নয়, ভালো প্রকৌশল। কিনারার মানুষের জন্য নকশা করলে মাঝখানের সবাই বিনামূল্যে উপকার পান।

প্র ০৪ধনাত্মক tabindex (১, ২, ৩…) দিয়ে নিজের পছন্দমতো Tab-এর ক্রম বানানো যায় — তাহলে প্রায় সবাই এটি এড়াতে বলে কেন? ক্রম ঠিক করার সঠিক উপায় কী?

পুরোনো HTML-এ tabindex ছিল মূলত কয়েকটি element-এ ধনাত্মক সংখ্যা দিয়ে ক্রম বলে দেওয়ার উপায়। পরে ব্রাউজারগুলো যেকোনো element-এ 0 আর -1-এর আচরণ চালু করে, যা HTML5 মান হিসেবে নেয় — আর দেখা গেল, এই দুটিই প্রায় সব প্রকৃত প্রয়োজন মেটায়।

সমস্যাটা কাঠামোগত। ধনাত্মক মান পুরো পাতার ওপর একটি আলাদা ক্রম বানায় — সব ধনাত্মক element আগে, তারপর বাকিরা। একটিতে tabindex="1" দিলে ক্রম ঠিক রাখতে বাকি সব কন্ট্রোলেও সংখ্যা দিতে হয়; পরে কেউ নতুন বোতাম, বিজ্ঞাপন বা চ্যাট-উইজেট যোগ করলেই পুরো হিসাব ভেঙে যায়।

দ্বিতীয় সমস্যা মানুষের। চোখে দেখা কি-বোর্ড ব্যবহারকারী পর্দায় যে ক্রম দেখেন (ওপর থেকে নিচে), focus তার বিপরীতে লাফালে তিনি দিশা হারান — WCAG ২.৪.৩ (Focus Order) বলে focus-এর ক্রম অর্থ ও ব্যবহারের সাথে মিলতে হবে। আর screen reader ব্যবহারকারী পড়েন DOM-এর ক্রমে, Tab করেন tabindex-এর ক্রমে — দুটি আলাদা হলে পাতার মানসিক ছবিটাই ভেঙে যায়।

সঠিক উপায় হলো HTML-এর ক্রমটাই ঠিক করা — যা আগে পড়া/চাপা উচিত, তা HTML-এ আগে লিখুন। সতর্ক থাকুন CSS-এর সাথেও: Flexbox-এর order, flex-direction: row-reverse বা Grid-এ জায়গা বদলালে চোখের ক্রম বদলায়, কিন্তু Tab-এর ক্রম HTML-এরই থাকে — পর্ব ২৫ আর ২৭-এ এ নিয়ে সতর্কবার্তা পাবেন। আর পপআপ বা dialog খুললে focus সেখানে নিয়ে যাওয়া, বন্ধ করলে আগের জায়গায় ফেরানো — এই focus management করা হয় JavaScript-এর focus() আর tabindex="-1" দিয়ে; নিজস্ব <dialog> element-এর showModal() (পর্ব ১১) এর অনেকটাই নিজে করে।

মূল উপলব্ধি: Tab-এর ক্রম হলো উৎসের ক্রম। চোখের ক্রম, পড়ার ক্রম আর Tab-এর ক্রম যত মিলবে, পাতা তত সহজ। সংখ্যা দিয়ে জোড়াতালি নয় — কাঠামো ঠিক করুন।

প্র ০৫একজন দৃষ্টিপ্রতিবন্ধী ব্যবহারকারী screen reader দিয়ে একটি বাংলা ওয়েবপেজ আসলে কীভাবে “পড়েন”? এখানে ডেভেলপারের দায়িত্ব কোথায়?

প্রথম চমক: বেশিরভাগ ব্যবহারকারী পাতা শুরু থেকে শেষ পর্যন্ত একটানা শোনেন না — যেমন আপনি সংবাদপত্রের প্রতিটি শব্দ পড়েন না। Windows-এ NVDA বা JAWS ওয়েবপেজ খুললে একটি “browse mode”-এ যায়: accessibility tree থেকে পাতার একটি পড়ার উপযোগী রূপ বানায়, যেখানে এক অক্ষরের শর্টকাটে লাফ দেওয়া যায় — H পরের heading, K পরের লিংক, F পরের ফর্ম-ঘর, T পরের টেবিল, D পরের landmark. ব্যবহারকারী প্রথমে heading-এর তালিকা শুনে পাতার একটি মানচিত্র বানান, তারপর দরকারি অংশে লাফ দেন। ফর্মের ঘরে এলে screen reader “focus mode”-এ যায়, যাতে লেখা অক্ষরগুলো শর্টকাট না হয়ে ঘরে বসে। ফোনে TalkBack বা VoiceOver-এ একই কাজ হয় আঙুলের সোয়াইপ আর একটি “rotor” বা মেনু দিয়ে।

এখান থেকেই ডেভেলপারের দায়িত্ব বোঝা যায়। heading না থাকলে মানচিত্র নেই; landmark না থাকলে লাফের জায়গা নেই; লিংকের নাম “এখানে ক্লিক করুন” হলে লিংক-তালিকায় দশটি “এখানে ক্লিক করুন” — কোনটা কোথায়, অর্থহীন। ফর্মে label না থাকলে প্রতিটি ঘর “সম্পাদনা, ফাঁকা”।

বাংলা পাতায় আরও একটি স্তর আছে — কণ্ঠ। Screen reader নিজে কথা বলে না; সে একটি text-to-speech (TTS) কণ্ঠ ব্যবহার করে। Android-এ Google-এর TTS-এ বাংলা কণ্ঠ আছে, আর NVDA-র সাথে আসা eSpeak NG-তেও বাংলা আছে, যদিও উচ্চারণ সব সময় স্বাভাবিক নয়। সঠিক কণ্ঠটি বাছতে screen reader নির্ভর করে আপনার lang attribute-এর ওপর। পাতায় lang="en" লেখা (অনেক টেমপ্লেটে ডিফল্ট থাকে) অথচ লেখা বাংলা — তাহলে ইংরেজি কণ্ঠ বাংলা অক্ষর পড়তে গিয়ে হয় চুপ থাকে, নয়তো অর্থহীন শব্দ বলে। ইউনিকোড ছাড়া পুরোনো “বিজয়” ধরনের এনকোডিংয়ে লেখা হলে তো লেখাটি screen reader-এর কাছে বাংলাই নয়, এলোমেলো ইংরেজি অক্ষর (পর্ব ১৪ আর ICT কোর্সের বাংলা টাইপিং পর্ব দেখুন)।

মূল উপলব্ধি: Screen reader ব্যবহারকারী আপনার পাতা “দেখেন” কাঠামো দিয়ে — heading, landmark, নাম আর ভাষা। এই চারটি ঠিক থাকলে বাংলা পাতাও শ্রোতার কাছে একটি পরিষ্কার মানচিত্র হয়ে ওঠে।

অনুশীলন

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

  1. পাঁচ মিনিটের কি-বোর্ড টেস্ট: আপনি প্রায়ই ব্যবহার করেন এমন একটি সাইট বেছে নিন (একটি অনলাইন দোকান, পরীক্ষার ফল দেখার সাইট বা কোনো সংবাদপত্র)। মাউস সরিয়ে রেখে শুধু কি-বোর্ড দিয়ে একটি কাজ শেষ করার চেষ্টা করুন — যেমন একটি পণ্য খুঁজে কার্টে যোগ করা। কোথায় আটকালেন, আর কেন?

    সাধারণত যেসব সমস্যা পাবেন: (ক) focus দেখা যায় না (outline: none); (খ) কিছু বোতামে পৌঁছানোই যায় না — div বা span দিয়ে বানানো; (গ) পপআপ খোলা রেখে focus পেছনের পাতায় ঘোরে, বা Esc কাজ করে না; (ঘ) skip link নেই, তাই প্রতি পাতায় ৩০ বার Tab; (ঙ) ক্রম এলোমেলো — CSS দিয়ে জায়গা বদলানো বা ধনাত্মক tabindex. এভাবে লিখে রাখা তালিকাই একটি পেশাদার “accessibility audit”-এর শুরু।

  2. নাম ফিরিয়ে দিন: নিচের অংশে তিনটি কন্ট্রোলের accessible name নেই বা দুর্বল। প্রতিটি ঠিক করুন — কোথায় দৃশ্যমান label, কোথায় aria-label, কোথায় alt?
    <input type="text" placeholder="নাম"> · <button><i class="fa fa-search"></i></button> · <a href="/"><img src="logo.png"></a>

    একটি সম্ভাব্য উত্তর:

    <!-- ১. দৃশ্যমান label; placeholder থাকলে শুধু উদাহরণ হিসেবে -->
    <label for="fullname">আপনার নাম</label>
    <input type="text" id="fullname" autocomplete="name">
    
    <!-- ২. শুধু আইকন: বোতামে নাম, আইকনকে লুকানো -->
    <button type="submit" aria-label="খুঁজুন">
      <i class="fa fa-search" aria-hidden="true"></i>
    </button>
    
    <!-- ৩. লিংকের ভেতরে শুধু ছবি: alt-ই লিংকের নাম, তাই গন্তব্য লিখুন -->
    <a href="/"><img src="logo.png" alt="ABCL TECH হোম পেজ"></a>

    খেয়াল করুন: দ্বিতীয়টিতে চাইলে পাশে দৃশ্যমান লেখা “খুঁজুন” রাখাও ভালো সমাধান — তখন aria-label লাগবে না। তৃতীয়টিতে alt-এ “লোগো” লিখলে শ্রোতা শুনতেন “লিংক, লোগো” — কোথায় নেবে, জানতেন না।

  3. খারাপ ARIA ধরুন: নিচের প্রতিটি লাইনে কী ভুল? (ক) <button role="button">পাঠান</button> (খ) <a href="/offer" aria-hidden="true">অফার</a> (গ) <div role="checkbox">শর্তে রাজি</div> (ঘ) <button aria-label="অর্ডার">অর্ডার নিশ্চিত করুন</button>

    (ক) অপ্রয়োজনীয় — button-এর role আগে থেকেই button; ক্ষতি নেই, কিন্তু কোড অগোছালো আর দেখায় লেখক নিয়মটা বোঝেননি। (খ) বিপজ্জনক — লিংকটি Tab-এ focus পায়, কিন্তু screen reader-এর কাছে নীরব; চতুর্থ নিয়ম ভাঙে। লুকাতে চাইলে hidden দিন বা সরিয়ে ফেলুন। (গ) প্রথম নিয়ম ভাঙে — focus নেই, Space-এ বদলায় না, aria-checked নেই, ফর্মের সাথে মান যায় না; লিখুন <label><input type="checkbox" name="terms"> শর্তে রাজি</label>. (ঘ) দৃশ্যমান লেখা “অর্ডার নিশ্চিত করুন”, অথচ নাম “অর্ডার” — WCAG ২.৫.৩ (Label in Name)-এর ঝুঁকি, আর অপ্রয়োজনীয়ও; aria-label মুছে দিন, ভেতরের লেখাই নাম।

  4. নিজের কানে শুনুন: আপনার Android ফোনে TalkBack (বা কম্পিউটারে NVDA) চালু করে এই পর্বের পাতাটিতে আসুন। (১) পাতার শিরোনামগুলো ধরে চলুন। (২) ওপরের “পড়েছি” বা “লেখা বড় করুন” বোতামে এলে কী শোনেন? (৩) একটি লাইভ এডিটরের প্রিভিউতে ঢুকুন। কী লক্ষ করলেন?

    প্রথমে TalkBack চালু-বন্ধ করার উপায়টি শিখে নিন (অনেক ফোনে দুই volume বোতাম একসাথে কয়েক সেকেন্ড চেপে ধরা — Settings-এ শর্টকাট চালু থাকলে)। (১) heading ধরে চললে শুনবেন h1, তারপর “১ · অ্যাক্সেসিবিলিটি কী…” এভাবে প্রতিটি h2 — এটাই পাতার মানচিত্র। (২) “লেখা বড় করুন, বোতাম” — বোতামের ভেতরে লেখা “অ+”, কিন্তু aria-label থাকায় অর্থবহ নাম শোনা যায়; এখানে aria-label ঠিক ব্যবহার, কারণ দৃশ্যমান “অ+” নিজে অর্থ বহন করে না। আর আইকনগুলো নীরব, কারণ তাতে aria-hidden="true". (৩) প্রিভিউ একটি iframe — screen reader তার নাম (title) বলে, তারপর ভেতরের পাতাটি আলাদা পাতার মতো পড়ে। প্রথম দিনে কণ্ঠের গতি কমিয়ে নিন।

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

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

ক্রমএকটি বোতামের তথ্য HTML থেকে screen reader ব্যবহারকারীর কাছে পৌঁছানোর ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. লেখক HTML-এ <button> লেখেন
  2. ব্রাউজার HTML parse করে DOM বানায়
  3. DOM থেকে accessibility tree তৈরি হয় — role, name, state
  4. অপারেটিং সিস্টেমের accessibility API দিয়ে তথ্য প্রকাশ হয়
  5. Screen reader কণ্ঠে বা ব্রেইলে শোনায়

একটি বোতামে tabindex="2" দেওয়া হলো, আর পাতার অন্য কোথাও কোনো ধনাত্মক tabindex নেই। Tab চাপলে কী ঘটবে?

  • বোতামটি Tab-এ কখনো focus পাবে না
  • বোতামটি HTML-এর লেখার ক্রমেই focus পাবে
  • পাতার সব কন্ট্রোলের আগে, প্রথম Tab-এই বোতামটি focus পাবে
  • ঠিক দ্বিতীয়বার Tab চাপলে বোতামটি focus পাবে, যেখানেই থাকুক

ARIA-র “প্রথম নিয়ম” অনুযায়ী একটি ক্লিকযোগ্য বোতাম বানানোর সবচেয়ে ভালো উপায় কোনটি?

  • <div role="button" tabindex="0"> আর তাতে click ও keydown শোনার স্ক্রিপ্ট
  • <button type="button">
  • <span onclick="…">
  • href ছাড়া একটি <a onclick="…">

<button aria-label="ঝুড়ি দেখুন">🛒 কার্ট</button> — screen reader এই বোতামের accessible name হিসেবে কী শোনাবে?

  • “🛒 কার্ট”
  • “ঝুড়ি দেখুন 🛒 কার্ট”
  • কোনো নাম নেই, শুধু “বোতাম”
  • “ঝুড়ি দেখুন”

WCAG-এর চারটি নীতির (POUR) মধ্যে “সব কাজ মাউস ছাড়া শুধু কি-বোর্ডে করা যাবে” নিয়মটি কোন নীতির অধীনে?

  • Operable
  • Perceivable
  • Understandable
  • Robust

অনলাইন দোকানে “কার্টে যোগ করুন” চাপার পর পাতার এক কোণে “যোগ হয়েছে” বার্তা আসে, কিন্তু focus বোতামেই থাকে। Screen reader ব্যবহারকারী যেন বার্তাটি শোনেন, তার সঠিক উপায় কোনটি?

  • বার্তার অংশে aria-hidden="true" দেওয়া
  • বার্তার অংশে tabindex="1" দেওয়া
  • পাতায় আগে থেকে রাখা একটি role="status" অংশে বার্তাটি লেখা
  • বার্তাটি উজ্জ্বল সবুজ রঙে দেখানো

একটি ওয়েবপেজ Lighthouse-এর Accessibility পরীক্ষায় ১০০ স্কোর পেয়েছে। এ থেকে কোন সিদ্ধান্তটি ঠিক?

  • পাতাটি নিশ্চিতভাবে WCAG 2.2 AA মানে
  • স্বয়ংক্রিয়ভাবে ধরা যায় এমন ভুল পাওয়া যায়নি, কিন্তু হাতে-কলমে পরীক্ষা এখনো বাকি
  • পাতাটি সব screen reader-এ পরীক্ষা করা হয়ে গেছে
  • পাতার HTML-এ আর কোনো পরিবর্তনের দরকার নেই

শব্দকোষ

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

মনে রাখুন

  1. অ্যাক্সেসিবিলিটি সবার জন্য — স্থায়ী, সাময়িক আর পরিস্থিতিগত প্রতিবন্ধিতা; মাপকাঠি WCAG 2.2, নীতি POUR, লক্ষ্য সাধারণত AA.
  2. সব কাজ কি-বোর্ডে; আসল button/a/input নিজেই কি-বোর্ড বোঝে; tabindex শুধু 0 আর -1; focus-এর দাগ মুছবেন না।
  3. প্রতিটি কন্ট্রোলের নাম: দৃশ্যমান label আর অর্থবহ alt সবচেয়ে ভালো; ক্রম — aria-labelledby → aria-label → label/alt → ভেতরের লেখা → title.
  4. Screen reader পড়ে accessibility tree; ARIA-র প্রথম নিয়ম — নিজস্ব HTML আগে; ARIA শুধু ঘোষণা করে, আচরণ দেয় না; aria-expanded বদলানো আপনার দায়িত্ব; live region আগে থেকেই পাতায়।
  5. heading, landmark, skip link আর lang দিয়ে কাঠামো; পরীক্ষা — কি-বোর্ড, NVDA/TalkBack/VoiceOver, DevTools, Lighthouse/axe — আর মনে রাখুন, টুল সব ধরে না।

পরের পর্বে: পাতার যে অংশটি পাঠক দেখেন না, কিন্তু Google, Facebook আর ব্রাউজার খুঁটিয়ে পড়ে — <head>. title, meta description, SEO-র ভিত্তি আর শেয়ার করলে সুন্দর প্রিভিউয়ের জন্য Open Graph.

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

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