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

JavaScript ছাড়া ইন্টারঅ্যাকটিভ HTML — details, dialog আর popover

Interactive HTML without JavaScript — details/summary, Exclusive Accordions, <dialog>, Popover API & Invoker Commands

Taught in Bangla, this lesson shows interactive HTML without JavaScript. It explains why a div with onclick is an incomplete button, then covers details and summary for FAQs, exclusive accordions with name, the dialog element with showModal, backdrop and Escape, invoker commands with a JavaScript fallback, and the Popover API with auto versus manual, light dismiss and top layer, plus when to choose each.

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

  • div-এ onclick লাগিয়ে বানানো “বাটন” কেন অর্ধেক কাজ করে, আর নিজস্ব element কী কী বিনা খরচে দেয়
  • details-summary দিয়ে FAQ, open attribute, আর name দিয়ে একটি-খোলা accordion
  • dialog — modal বনাম non-modal, showModal(), ::backdrop, Esc, method="dialog" আর focus কোথায় যায়
  • নতুন invoker commands (command/commandfor) আর পুরোনো ব্রাউজারের জন্য JavaScript fallback
  • popover, popovertarget, auto বনাম manual, light dismiss, top layer — আর কখন কোনটি বেছে নেবেন

১ · নিজস্ব element কেন জেতে — div-এর “বাটন” আসলে কতটা অসম্পূর্ণ

একটি অনলাইন দোকানের কথা ভাবুন। পণ্যের পাতায় “সাধারণ প্রশ্ন” অংশে প্রশ্নে চাপ দিলে উত্তর খোলে। “অর্ডার বাতিল” চাপলে মাঝখানে একটি বাক্স আসে — “আপনি কি নিশ্চিত?” আর ওপরের কোণের “⋮” চাপলে একটি ছোট মেনু ভেসে ওঠে। এই তিনটি জিনিসকে বলে ইন্টারঅ্যাকটিভ (interactive) অংশ — পাঠকের কাজে সাড়া দেয়।

বহু বছর ধরে এগুলো বানানো হতো <div> আর JavaScript দিয়ে: একটি div, তাতে onclick, আর কিছু কোড যা অন্য div দেখায় বা লুকায়। মাউস দিয়ে চাপলে কাজ করে, দেখতেও ঠিক লাগে। তাহলে সমস্যা কোথায়?

সমস্যা হলো, সবাই মাউস ব্যবহার করেন না। কেউ শুধু কি-বোর্ড চালান — হাতে ব্যথা, ভাঙা মাউস, অথবা দ্রুত কাজের অভ্যাস। কেউ screen reader শোনেন। কেউ ফোনে বড় লেখা আর সুইচ ডিভাইস ব্যবহার করেন। এঁদের সবার জন্য ব্রাউজার একটি নিয়ম মানে: কোন element-এ focus যাবে (Tab চাপলে কোনটি “সক্রিয়” হবে), কোন key চাপলে কী হবে, আর screen reader-কে কী নাম ও ভূমিকা জানাতে হবে। <button> লিখলে এর সবই আপনা-আপনি আসে। <div onclick> লিখলে কিছুই আসে না।

দুটি দোকানের দরজা ভাবুন। একটিতে ব্যবহার করা হয়েছে কারখানায় বানানো আসল দরজা — কবজা, তালা, হাতল, ধাক্কা দিলে খোলে, ভেতর থেকে বন্ধ করা যায়। অন্যটিতে দেয়ালে দরজার ছবি আঁকা, আর পাশে একজন দারোয়ান দাঁড়িয়ে — কেউ ছবিতে হাত রাখলে তিনি পাশের গোপন পথ খুলে দেন। যতক্ষণ দারোয়ান সজাগ, চলে যায়। কিন্তু অন্ধকারে, ভিড়ে, বা দারোয়ান না থাকলে (JavaScript লোড না হলে) মানুষ আটকে যায়। নিজস্ব HTML element হলো আসল দরজা; div + JavaScript হলো আঁকা দরজা আর দারোয়ান।

নিচের স্টেপারে দেখুন, একটি div-কে সত্যিকারের বাটনের সমান করতে ধাপে ধাপে কী কী যোগ করতে হয় — আর কোডের শেষে <button> কেমন এক লাইনে সব করে দেয়।

ধাপ ১শুধু div আর onclick
<div class="btn" onclick="save()">সংরক্ষণ</div>
ধাপ ২Tab-এ পৌঁছানোর ব্যবস্থা
<div class="btn" tabindex="0" onclick="save()">সংরক্ষণ</div>
ধাপ ৩screen reader-কে ভূমিকা জানানো
<div class="btn" tabindex="0" role="button"
     onclick="save()">সংরক্ষণ</div>
ধাপ ৪Enter আর Space নিজে ধরা
el.addEventListener('keydown', e => {
  if (e.key === 'Enter') save();
  if (e.key === ' ') { e.preventDefault(); save(); }
});
// (আসল বাটন Space ছাড়ার সময় চলে — সেটাও মেলাতে হয়)
// + disabled অবস্থা, focus-এর দাগ, ফর্মে জমা…
ধাপ ৫নিজস্ব element
<button type="button">সংরক্ষণ</button>
  1. শুধু div. মাউসে চলে। কিন্তু Tab চাপলে focus এর ওপর দিয়ে চলে যায় — div স্বভাবত focus পায় না। Screen reader শুধু লেখাটা পড়ে; এটা যে চাপা যায়, তা বোঝার উপায় নেই।
  2. tabindex="0". এখন Tab-এ পৌঁছানো যায়। কিন্তু কি-বোর্ড ব্যবহারকারী স্বাভাবিকভাবে Enter বা Space চাপেন — div-এ সেগুলোর কোনো অর্থ নেই, কিছুই ঘটে না।
  3. role="button". এটি ARIA-র একটি attribute. Screen reader এখন বলে “বাটন”। কিন্তু ARIA শুধু ঘোষণা করে, আচরণ দেয় না — শ্রোতা ভাবছেন বাটন, Enter চাপছেন, অথচ কিছু হচ্ছে না। এটা আগের চেয়েও বিভ্রান্তিকর।
  4. key নিজে ধরা. JavaScript দিয়ে Enter আর Space ধরতে হয়, Space-এ পাতা যেন স্ক্রল না করে তা আটকাতে হয়, নিষ্ক্রিয় (disabled) অবস্থা, focus-এর দৃশ্যমান দাগ, ফর্মের ভেতরে জমা দেওয়ার আচরণ — সবই হাতে। প্রতিটি প্রজেক্টে, প্রতিটি “বাটনে”, আর প্রতিবার ভুলের সুযোগ।
  5. button. এক লাইন। Tab, Enter, Space, “বাটন” ভূমিকা, disabled, ফর্মে জমা — সবই ব্রাউজারের ভেতরে আগে থেকে তৈরি আর লক্ষ লক্ষ মানুষের হাতে পরীক্ষিত। এ কারণেই নিয়মটি সহজ: চাপা যায় এমন জিনিস মানে <button> (অন্য পাতায় যাওয়া হলে <a href>).
মূল ধারণা — ARIA-র প্রথম নিয়ম

W3C-র ARIA নির্দেশিকার “প্রথম নিয়ম” বলে: যে কাজের জন্য নিজস্ব HTML element বা attribute আছে, সেটাই ব্যবহার করুন; div-এ role বসিয়ে নতুন করে বানাবেন না। এই পর্বের তিনটি element — <details>, <dialog> আর popover attribute — ঠিক এমন তিনটি কাজের নিজস্ব সমাধান, যেগুলোর জন্য আগে ভারী JavaScript লাইব্রেরি লাগত। লাভ তিনটি: কি-বোর্ড ও focus ঠিক থাকে, accessibility বিনা খরচে আসে, আর কোড কমে — কম কোড মানে কম বাগ, দ্রুত লোড।

শিরোনামে “JavaScript ছাড়া” লেখা আছে, তবে সেটা পুরো সত্য নয় — আর সৎ থাকা ভালো। details আর popover সত্যিই কোনো স্ক্রিপ্ট ছাড়া চলে। modal dialog খুলতে এতদিন এক লাইন JavaScript লাগত; নতুন invoker commands সেটাও HTML-এ নিয়ে এসেছে, তবে পুরোনো ব্রাউজারের জন্য ছোট একটি fallback রাখতে হয়। এই পর্বে প্রতিটির সাপোর্ট-অবস্থা Baseline শব্দে স্পষ্ট বলা থাকবে।

২ · details আর summary — খোলা-বন্ধের নিজস্ব বাক্স

পরীক্ষার খাতার শেষে “সংক্ষিপ্ত উত্তর” ভাঁজ করে রাখা কাগজের কথা ভাবুন — ওপরে প্রশ্ন দেখা যায়, ভাঁজ খুললে উত্তর। HTML-এ এটাই disclosure widget, যা দুটি element দিয়ে বানানো:

  • <details> — পুরো বাক্সটি। ভেতরের সব কিছু বন্ধ অবস্থায় লুকানো থাকে।
  • <summary> — সব সময় দেখা যাওয়া শিরোনাম; এতে চাপলে বাক্স খোলে-বন্ধ হয়। এটি details-এর প্রথম সন্তান হতে হবে।

ব্রাউজার summary-কে নিজে থেকেই একটি বাটনের মতো আচরণ দেয়: Tab-এ focus আসে, Enter বা Space চাপলে খোলে, screen reader বলে “প্রসারিত” বা “সংকুচিত” (expanded/collapsed). পাশে একটি ছোট ত্রিভুজ চিহ্নও (marker) বসে, যা খোলা অবস্থায় ঘুরে নিচের দিকে তাকায়।

<h3>সাধারণ প্রশ্ন</h3>

<details>
  <summary>ডেলিভারি কত দিনে হয়?</summary>
  <p>ঢাকার ভেতরে সাধারণত দুই-তিন দিনে, বাইরে চার-পাঁচ দিনে।</p>
</details>

<details open>
  <summary>কীভাবে টাকা দেব?</summary>
  <p>ক্যাশ অন ডেলিভারি অথবা মোবাইল ব্যাংকিং।</p>
  <ul>
    <li>পণ্য হাতে পেয়ে টাকা দিতে পারবেন</li>
    <li>অগ্রিম দিলে রসিদ পাবেন</li>
  </ul>
</details>

<details>
  <summary>পণ্য ফেরত দেওয়া যায়?</summary>
  <p>হাতে পাওয়ার সাত দিনের মধ্যে, মোড়ক না খুলে থাকলে।</p>
</details>

তিনটি প্রশ্ন দেখবেন; দ্বিতীয়টি আগে থেকেই খোলা, কারণ তাতে open আছে — এটি একটি boolean attribute, শুধু নাম লিখলেই চালু। প্রশ্নে চাপুন — উত্তর খোলে-বন্ধ হয়। এবার মাউস না ছুঁয়ে প্রিভিউর ভেতরে চাপুন, তারপর Tab আর Enter দিয়ে চেষ্টা করুন — কি-বোর্ডেও পুরো কাজ হয়, এক লাইন JavaScript ছাড়া। চেষ্টা করুন: তৃতীয় details-এ open যোগ করুন। তারপর প্রথমটি থেকে <summary>…</summary> লাইনটি মুছে দিন — ব্রাউজার নিজে একটি সাধারণ লেবেল বসাবে (সাধারণত “Details”), যা পাঠককে কিছুই বলে না।

open — attribute-ই অবস্থা

open attribute শুধু শুরুর অবস্থা নয়, এটাই বর্তমান অবস্থা। পাঠক চাপ দিয়ে খুললে ব্রাউজার নিজেই DOM-এ open যোগ করে, বন্ধ করলে সরিয়ে দেয়। তাই CSS-এ details[open] দিয়ে খোলা অবস্থার আলাদা নকশা করা যায় (পর্ব ১৭-এ attribute selector). আর প্রতিবার অবস্থা বদলালে details-এ একটি toggle ইভেন্ট ঘটে — দরকার হলে JavaScript সেটা শুনতে পারে, কিন্তু খোলা-বন্ধের জন্য JavaScript-এর কোনো দরকার নেই।

summary-র ভেতরে কী রাখবেন, কী রাখবেন না

  • summary নিজেই একটি চাপার জায়গা, তাই এর ভেতরে লিংক বা বাটন রাখবেন না — একটি চাপার জিনিসের ভেতরে আরেকটি থাকলে কি-বোর্ড আর screen reader দুই-ই বিভ্রান্ত হয়।
  • summary-র ভেতরে heading (<h3>) রাখা বৈধ, কিন্তু বেশিরভাগ screen reader তখন summary-কে বাটন হিসেবে পড়ে আর heading-এর ভূমিকা হারিয়ে যেতে পারে। পাতার শিরোনাম-কাঠামোয় প্রশ্নগুলো জরুরি হলে details-এর আগে আলাদা heading দিন।
  • ত্রিভুজটি CSS দিয়ে বদলানো বা সরানো যায় (summary { list-style: none } আর ::marker), তবে সরালে অবশ্যই অন্য কোনো চিহ্ন (যেমন +/−) দিন, নইলে পাঠক বোঝেন না যে এটা খোলা যায়।

সাপোর্ট: <details> আর <summary> Baseline Widely available — বহু বছর ধরে সব প্রধান ব্রাউজারে আছে, নিশ্চিন্তে ব্যবহার করুন। বাড়তি সুবিধা: ভেতরের লেখা পাতার HTML-এই থাকে, তাই সার্চ ইঞ্জিন পড়তে পারে, আর Chromium-ভিত্তিক ব্রাউজারসহ কয়েকটি ব্রাউজারে Ctrl+F দিয়ে খোঁজার সময় বন্ধ details-এর ভেতরের শব্দ মিললে বাক্সটি নিজেই খুলে যায়।

৩ · একটি খুললে বাকিগুলো বন্ধ — name দিয়ে exclusive accordion

কয়েকটি details পরপর সাজালে তাকে বলে accordion — হারমোনিয়ামের ভাঁজের মতো খোলে-বন্ধ হয়। অনেক নকশায় চাওয়া হয়, একসাথে একটিই খোলা থাকবে: নতুনটি খুললে আগেরটি নিজে বন্ধ হবে। এতদিন এর জন্য JavaScript লাগত। এখন আছে exclusive accordion: সবগুলো details-এ একই name দিন।

ধারণাটি পরিচিত — পর্ব ০৯-এর radio button-এর মতো। একই name-এর radio-গুলোর মধ্যে একটিই বাছা যায়; একই name-এর details-গুলোর মধ্যে একটিই খোলা থাকে। আলাদা দলের জন্য আলাদা নাম দিন (যেমন name="delivery", name="payment").

<h3>ভর্তি-সংক্রান্ত প্রশ্ন</h3>

<details name="admission" open>
  <summary>আবেদনের শেষ তারিখ কবে?</summary>
  <p>বিজ্ঞপ্তিতে দেওয়া তারিখ দেখুন (এটি একটি উদাহরণ)।</p>
</details>
<details name="admission">
  <summary>কোন কোন কাগজ লাগবে?</summary>
  <p>ছবি, মার্কশিট আর জন্মনিবন্ধন সনদের কপি।</p>
</details>
<details name="admission">
  <summary>ফি কীভাবে জমা দেব?</summary>
  <p>মোবাইল ব্যাংকিং বা ব্যাংকে।</p>
</details>

<script>
  // শুধু দেখার জন্য: কোনটি খুলল, কোনটি বন্ধ হলো
  document.addEventListener('toggle', e => {
    console.log(e.target.querySelector('summary').textContent + ' → ' + e.newState);
  }, true);
</script>

প্রথম প্রশ্নটি খোলা, আর লগে শুরুতেই একটি লাইন আসে (→ open) — open attribute দিয়ে খোলা অবস্থায় পাতা লোড হলেও toggle ঘটে। দ্বিতীয়টিতে চাপুন — দ্বিতীয়টি খোলার সাথে সাথে প্রথমটি নিজে বন্ধ হয়ে যায়, আর লগে আরও দুটি লাইন আসে: একটি open, একটি closed. ছোট স্ক্রিপ্টটি শুধু ঘটনাটা দেখানোর জন্য; মুছে দিলেও accordion একই রকম চলবে। (toggle ইভেন্ট ওপরের দিকে ছড়ায় না, তাই true দিয়ে capture পর্যায়ে শোনা হয়েছে।) চেষ্টা করুন: তৃতীয় details থেকে name="admission" মুছে দিন — এবার সেটি স্বাধীন, বাকিদের সাথে একসাথে খোলা থাকতে পারে। তারপর দুটি details-এ একসাথে open লিখে দেখুন — ব্রাউজার নিয়ম রক্ষা করতে একটিকে বন্ধ রাখে।

ব্রাউজার ভেতরে ঠিক কী হিসাব করে, ধাপে ধাপে দেখুন:

1<details name="faq" open>…প্রশ্ন ক…</details>2<details name="faq">…প্রশ্ন খ…</details>3<details name="faq">…প্রশ্ন গ…</details>4<details>…প্রশ্ন ঘ (name নেই)…</details>
কোনটিতে open আছে?
ক (faq)
খ (faq)
গ (faq)
ঘ (নামহীন)
  1. শুরুর অবস্থা. তিনটি details-এর নাম “faq” — তারা একটি দল। ক-তে open আছে। চতুর্থটির (ঘ) কোনো নাম নেই, সে দলের বাইরে।
  2. খ-তে চাপ. খ খোলার ঠিক আগে ব্রাউজার একই পাতায় (একই DOM গাছে) একই নামের অন্য details খোঁজে — ঠিক যেভাবে radio button একই নামের সঙ্গীদের খোঁজে।
  3. একটি বন্ধ, একটি খোলা. ক থেকে open সরে যায়, খ-তে বসে। দুটিতেই toggle ইভেন্ট ঘটে। Screen reader ব্যবহারকারী খ-এর জন্য শোনেন “প্রসারিত”।
  4. আবার একই নিয়ম. গ খুললে খ বন্ধ। যে কোনো মুহূর্তে দলে সর্বোচ্চ একটি খোলা — কিন্তু শূন্যও হতে পারে: খোলাটিতে আবার চাপলে সেটি বন্ধ হয়, অন্য কোনোটি খোলে না।
  5. নামহীন details স্বাধীন. ঘ খুললে গ খোলাই থাকে। নাম না দিলে প্রতিটি details নিজের মতো চলে — আগের মতোই।

সাপোর্ট: details-এর name attribute Baseline Newly available — ২০২৪ সালে সব প্রধান ব্রাউজারের নতুন সংস্করণে এসেছে, কিন্তু Widely available হতে আরও কিছু সময় লাগবে। ভালো খবর: পুরোনো ব্রাউজার না-চেনা name-কে শুধু উপেক্ষা করে, ফলে accordion-টি সাধারণ স্বাধীন details হয়ে যায় — সব প্রশ্ন খোলা যায়, কোনো তথ্য হারায় না। একে বলে progressive enhancement: নতুন ব্রাউজারে বাড়তি সুবিধা, পুরোনোয় মূল কাজ ঠিক থাকে। তাই এখানে fallback স্ক্রিপ্ট সাধারণত লাগে না।

exclusive সব সময় ভালো নয়। পাঠক যদি দুটি উত্তর পাশাপাশি মিলিয়ে দেখতে চান (যেমন দুটি প্যাকেজের শর্ত), একটি খুললে অন্যটি বন্ধ হয়ে যাওয়া বিরক্তিকর। আর হঠাৎ একটি অংশ বন্ধ হলে পাতার লেখা ওপরে লাফ দেয়। FAQ-তে প্রশ্ন অনেক আর উত্তর ছোট হলে exclusive ভালো চলে; নইলে সাধারণ স্বাধীন details-ই নিরাপদ।

৪ · dialog — modal আর non-modal বাক্স

bKash-এ টাকা পাঠানোর শেষ ধাপে একটি বাক্স আসে: “আপনি কি ৫০০ টাকা পাঠাতে চান?” — হ্যাঁ না বললে আর কিছু করা যায় না। এটা modal dialog: পাঠকের কাজ থামিয়ে একটি সিদ্ধান্ত চায়, আর পেছনের পাতা ততক্ষণ অচল। এর উল্টো হলো non-modal dialog — একটি ভাসমান বাক্স যা খোলা থাকলেও পেছনের পাতায় কাজ করা যায়, যেমন একটি চ্যাট-সহায়তার জানালা।

HTML-এ দুটোই একটি element দিয়ে: <dialog>. কোন রূপে খুলবে, সেটা ঠিক হয় কীভাবে খোলা হলো তা দিয়ে:

উপায়রূপযা ঘটে
dialog.showModal()modaltop layer-এ ওঠে, পেছনে ::backdrop, বাকি পাতা inert (চাপা যায় না, Tab যায় না), Esc চাপলে বন্ধ
dialog.show()non-modalপাতার স্বাভাবিক স্তরে দেখা যায়, পেছনের পাতা সচল, Esc-এ নিজে বন্ধ হয় না
HTML-এ <dialog open>non-modalshow()-এর মতো; modal খুলতে এটি ব্যবহার করবেন না
dialog.close(value)—বন্ধ করে, চাইলে returnValue-তে একটি মান রাখে

এবার একটি modal নিজে চালিয়ে দেখুন। বাক্সটি বন্ধ করার কোনো JavaScript নেই — ভেতরের ফর্মে method="dialog" আছে। এমন ফর্ম জমা দিলে কোথাও পাঠানো হয় না; ব্রাউজার শুধু dialog বন্ধ করে আর যে বাটন চাপা হলো তার value রেখে দেয় returnValue-তে।

<style>
  body { min-height: 300px; }
  dialog::backdrop { background: rgb(0 0 0 / 0.55); }
</style>
<button type="button" id="send">৫০০ টাকা পাঠান</button>
<button type="button" id="peek">non-modal হিসেবে খুলুন</button>
<p>পেছনের লেখা — modal খোলা থাকলে এটি বাছাই করা যায় না।</p>

<dialog id="confirm" aria-labelledby="confirm-title">
  <h2 id="confirm-title">আপনি কি নিশ্চিত?</h2>
  <p>প্রাপক: ০১৭XX-XXXXXX, পরিমাণ: ৫০০ টাকা (উদাহরণ)</p>
  <form method="dialog">
    <button value="cancel">বাতিল</button>
    <button value="ok">হ্যাঁ, পাঠান</button>
  </form>
</dialog>

<script>
  const box = document.getElementById('confirm');
  document.getElementById('send').addEventListener('click', () => box.showModal());
  document.getElementById('peek').addEventListener('click', () => { if (!box.open) box.show(); });
  box.addEventListener('close', () => console.log('বন্ধ হলো — returnValue: ' + box.returnValue));</script>

“৫০০ টাকা পাঠান” চাপুন — প্রিভিউর মাঝখানে বাক্স আসে, পেছনটা কালচে হয় (::backdrop), আর পেছনের বাটন বা লেখায় চাপ দিলে কিছু হয় না। focus নিজে থেকে বাক্সের প্রথম বাটনে (“বাতিল”) চলে আসে। “হ্যাঁ, পাঠান” চাপলে বাক্স বন্ধ হয়ে লগে আসে returnValue: ok; আবার খুলে Esc চাপুন — এবার বন্ধ হয়, কিন্তু লগে কোনো বাটনের value আসে না (Edge-এ returnValue খালি দেখায়), কারণ Esc কোনো বাটন চাপে না। তাই আসল কোডে “পাঠক হ্যাঁ বলেছেন” ধরবেন কেবল returnValue === 'ok' হলে। এবার “non-modal হিসেবে খুলুন” চাপুন — বাক্সটি পাতার ভেতরে বসে, পেছনটা কালো হয় না, পেছনের লেখা বাছাই করা যায়, আর Esc-এ বন্ধ হয় না। চেষ্টা করুন: ::backdrop-এর রং বদলে rgb(0 80 40 / 0.4) করুন।

focus কোথায় যায় — আর কেন এটা গুরুত্বপূর্ণ

modal খোলার পর পাঠক যদি জানতেই না পারেন যে একটি বাক্স এসেছে, তাহলে বাক্সের কোনো অর্থ নেই। দৃষ্টিপ্রতিবন্ধী একজন ব্যবহারকারীর কাছে “জানা” মানে focus বাক্সের ভেতরে আসা আর screen reader-এর ঘোষণা শোনা। showModal() এই কাজগুলো নিজে করে। নিচের স্টেপারে পুরো জীবনচক্র দেখুন:

  1. বাটনে চাপshowModal()focus বাটনে
  2. top layer::backdropসবার ওপরে
  3. বাকি পাতা inertblockedচাপা ও Tab বন্ধ
  4. focus ভেতরেautofocusঘোষণা হয়
  5. বন্ধclosefocus ফেরে
  1. খোলার অনুরোধ. পাঠক বাটনে চাপলেন (মাউস, Enter বা Space). ব্রাউজার মনে রাখে এই মুহূর্তে focus কোথায় ছিল — পরে ফিরিয়ে দিতে হবে।
  2. top layer. dialog ওঠে একটি বিশেষ স্তরে, যা পাতার সব element-এর ওপরে — কোনো z-index বা overflow: hidden তাকে চাপা দিতে বা কাটতে পারে না। ঠিক তার পেছনে বসে ::backdrop, যা পুরো পর্দা ঢেকে দেয়।
  3. বাকি পাতা অচল. dialog-এর বাইরের সব কিছু “inert” হয়ে যায় — মাউসে চাপা যায় না, Tab সেখানে যায় না, screen reader-এর পড়ার তালিকা থেকেও সরে যায়। পাঠকের সামনে এখন শুধু বাক্সটি।
  4. focus ভেতরে. ব্রাউজার focus সরায় বাক্সের ভেতরে — autofocus দেওয়া element থাকলে সেখানে, না থাকলে প্রথম focus-যোগ্য element-এ। Screen reader dialog-এর নাম (aria-labelledby দিয়ে শিরোনামটি) আর focus পাওয়া বাটন ঘোষণা করে। মুছে ফেলা বা টাকা পাঠানোর মতো ঝুঁকির কাজে নিরাপদ বাটনে (“বাতিল”) autofocus দেওয়া ভালো অভ্যাস।
  5. বন্ধ. Esc চাপলে আগে cancel, তারপর close ইভেন্ট; method="dialog" ফর্ম জমা বা close()-এ শুধু close. বন্ধ হওয়ার পর ব্রাউজার focus ফেরত দেয় সেই বাটনে, যেখান থেকে বাক্স খোলা হয়েছিল — পাঠক পথ হারান না। আগে এই কাজটিও হাতে লিখতে হতো।

সাপোর্ট: <dialog>, showModal(), ::backdrop আর method="dialog" সবই Baseline Widely available — ২০২২ সালের মার্চে সব প্রধান ব্রাউজারে আসার পর অনেক সময় পেরিয়েছে। নিশ্চিন্তে ব্যবহার করুন। বাইরে (backdrop-এ) চাপলে বন্ধ করার নতুন closedby="any" attribute কিছু ব্রাউজারে এসেছে, কিন্তু লেখার সময় সব প্রধান ব্রাউজারে নেই — এখনো Baseline নয় (Can I use দেখে নিন); ব্যবহার করলে পুরোনো ব্রাউজারে সেটা শুধু কাজ করবে না, ক্ষতি হবে না।

আরও গভীরে: “top layer” ধারণাটি প্রথম এসেছিল Fullscreen API-র জন্য — পূর্ণ পর্দার ভিডিওকে যেন পাতার কোনো element ঢাকতে না পারে। পরে dialog আর popover-ও এই স্তর পেল। top layer-এর element-গুলো একটি নিজস্ব স্ট্যাকে থাকে, পাতার সব stacking context-এর বাইরে; যেটি পরে খোলে সেটি ওপরে বসে। DevTools-এর Elements প্যানেলে খোলা modal-এর পাশে একটি top-layer চিহ্ন দেখবেন। আর modal-এর “inert” আচরণ spec-এ একটি নিয়ম হিসেবে লেখা: modal খোলা থাকলে ডকুমেন্টের বাকি অংশ “blocked by a modal dialog” — যা পরে সাধারণ inert attribute হিসেবেও সবার হাতে দেওয়া হয়েছে। তবে কি-বোর্ড পুরোপুরি “বন্দি” নয়: Tab শেষ বাটন পেরিয়ে ব্রাউজারের ঠিকানা-বারে যেতে পারে, যা ইচ্ছাকৃত — ব্যবহারকারী যেন কখনো আটকে না যান।

৫ · Invoker commands — modal খুলতেও আর JavaScript নয়

ওপরের উদাহরণে বাক্স বন্ধ করার জন্য JavaScript লাগেনি, কিন্তু খোলার জন্য একটি লাইন লেগেছিল: box.showModal(). এই শেষ ফাঁকটি পূরণ করেছে invoker commands — বাটনে দুটি attribute:

  • commandfor="id" — কোন element-কে নির্দেশ দেবে (dialog বা popover-এর id).
  • command="…" — কী নির্দেশ: show-modal (modal খোলো), close (বন্ধ করো), popover-এর জন্য toggle-popover, show-popover, hide-popover. নিজের কাজের জন্য -- দিয়ে শুরু হওয়া নামও দেওয়া যায় (যেমন --rotate), যা JavaScript-এ command ইভেন্ট হয়ে আসে।

নিচের OTP বাক্সটি খোলা-বন্ধ পুরোপুরি HTML-এ। স্ক্রিপ্ট অংশটি শুধু fallback — যে ব্রাউজার এখনো commandfor চেনে না, সেখানে একই কাজ JavaScript দিয়ে করে।

<style>
  body { min-height: 300px; }
  dialog::backdrop { background: rgb(0 0 0 / 0.5); }
</style>
<button type="button" command="show-modal" commandfor="otp">OTP যাচাই করুন</button>

<dialog id="otp" aria-labelledby="otp-title">
  <h2 id="otp-title">কোড পাঠানো হয়েছে</h2>
  <label>ফোনে আসা ৬ অঙ্কের কোড
    <input inputmode="numeric" autocomplete="one-time-code" autofocus>
  </label>
  <p><button type="button" command="close" commandfor="otp">বন্ধ করুন</button></p>
</dialog>

<script>
  const native = 'commandForElement' in HTMLButtonElement.prototype;
  console.log('invoker commands নিজে থেকে চলে? ' + native);
  if (!native) {                       // পুরোনো ব্রাউজারের জন্য fallback
    document.addEventListener('click', e => {
      const btn = e.target.closest('button[commandfor]');
      if (!btn) return;
      const target = document.getElementById(btn.getAttribute('commandfor'));
      const cmd = btn.getAttribute('command');
      if (cmd === 'show-modal' && !target.open) target.showModal();
      if (cmd === 'close') target.close();
    });
  }
</script>

লগে প্রথমেই আসে invoker commands নিজে থেকে চলে? true (নতুন ব্রাউজারে) — তার মানে বাক্সটি খুলছে HTML দিয়েই, fallback চুপ থাকে। বাটনে চাপুন: modal খোলে, আর focus সরাসরি কোডের ঘরে যায়, কারণ input-এ autofocus আছে। “বন্ধ করুন” বা Esc — দুটোতেই বন্ধ, আর focus ফেরে বাটনে। চেষ্টা করুন: প্রথম বাটনের command-কে show-modal থেকে বদলে একটি ভুল নাম (যেমন open) লিখুন — কিছুই হবে না, কারণ ব্রাউজার শুধু নির্দিষ্ট নামগুলো চেনে। তারপর input থেকে autofocus মুছে দেখুন, এবার focus কোথায় যায়।

সাপোর্ট: invoker commands Baseline Newly available — সাম্প্রতিক সময়ে সব প্রধান ব্রাউজারের নতুন সংস্করণে এসেছে (সর্বশেষ অবস্থা Can I use-এ দেখে নিন)। কিন্তু অনেকের ফোনে বা অফিসের কম্পিউটারে পুরোনো ব্রাউজার থাকে, তাই এখনো fallback রাখা উচিত। দুটি পথ: ওপরের মতো ছোট নিজের স্ক্রিপ্ট, অথবা invokers-polyfill নামের একটি polyfill. যেটাই হোক, feature detection দিয়ে শুধু দরকার হলেই চালান — 'commandForElement' in HTMLButtonElement.prototype পরীক্ষাটি ঠিক এই কাজ করে। আর মনে রাখবেন, fallback-ও শেষ পর্যন্ত সেই একই নিজস্ব showModal() ডাকে — focus, inert, Esc সবই ব্রাউজারের দেওয়া থাকে।

৬ · popover — মেনু, টিপস আর নোটিফিকেশনের ভাসমান স্তর

সব ভাসমান অংশ পাঠককে থামায় না। প্রোফাইল-ছবিতে চাপলে আসা ছোট মেনু, একটি শব্দের পাশে “?” চাপলে আসা ব্যাখ্যা, বা “কার্টে যোগ হয়েছে” লেখা ছোট বার্তা — এগুলো ক্ষণিকের, পাঠক চাইলে উপেক্ষা করে কাজ চালিয়ে যান। এর জন্য HTML-এর নিজস্ব সমাধান popover attribute. এটি যেকোনো element-এ বসানো যায়:

  • popover (বা popover="auto") — element-টি শুরুতে লুকানো; খুললে top layer-এ ভেসে ওঠে।
  • popovertarget="id" — একটি <button>-এ বসালে সেটি ওই popover খোলে-বন্ধ করে, কোনো স্ক্রিপ্ট ছাড়া।
  • popovertargetaction — বাটনটি কী করবে: toggle (ডিফল্ট, খোলা-বন্ধ দুই-ই), show (শুধু খোলে), hide (শুধু বন্ধ করে)।

auto বনাম manual

popover="auto"

Light dismiss আছে: বাইরে চাপলে বা Esc চাপলে নিজে বন্ধ হয়। একসাথে একটিই auto popover খোলা থাকে — নতুনটি খুললে আগেরটি বন্ধ (তবে একটি popover-এর ভেতর থেকে খোলা “সন্তান” popover খোলা থাকতে পারে, যেমন উপ-মেনু)।

মেনু, টিপস

popover="manual"

নিজে বন্ধ হয় না — শুধু বাটন (popovertargetaction="hide") বা JavaScript (hidePopover()) বন্ধ করে। একসাথে অনেকগুলো খোলা থাকতে পারে, অন্য popover-এর কারণে বন্ধ হয় না।

নোটিফিকেশন, টোস্ট
<style>
  body { min-height: 280px; }
  #toast { inset: auto 1rem 1rem auto; margin: 0; }
</style>
<button popovertarget="menu">আমার অ্যাকাউন্ট ▾</button>
<div id="menu" popover>
  <ul>
    <li><a href="#orders">আমার অর্ডার</a></li>
    <li><a href="#settings">সেটিংস</a></li>
  </ul>
</div>

<button popovertarget="toast" popovertargetaction="show">কার্টে যোগ করুন</button>
<div id="toast" popover="manual">
  <p>পণ্যটি কার্টে যোগ হয়েছে।</p>
  <button popovertarget="toast" popovertargetaction="hide">ঠিক আছে</button>
</div>

<script>
  // শুধু দেখার জন্য: কোন popover কখন খুলল বা বন্ধ হলো
  for (const p of document.querySelectorAll('[popover]')) {
    p.addEventListener('toggle', e => console.log(p.id + ': ' + e.oldState + ' → ' + e.newState));
  }
</script>

“আমার অ্যাকাউন্ট” চাপুন — মেনুটি ভেসে ওঠে প্রিভিউর মাঝখানে (ব্রাউজারের ডিফল্ট জায়গা), লগে menu: closed → open. এবার মেনুর বাইরে যেকোনো জায়গায় চাপুন বা Esc চাপুন — নিজে বন্ধ হয়, এটাই light dismiss. “কার্টে যোগ করুন” চাপুন — বার্তাটি ডান-নিচের কোণে আসে (CSS-এর inset দিয়ে সরানো), আর বাইরে চাপলেও যায় না; শুধু “ঠিক আছে” চাপলে বন্ধ হয়। চেষ্টা করুন: toast খোলা রেখে মেনু খুলুন — দুটোই একসাথে থাকে, কারণ manual popover অন্যদের নিয়মে চলে না। তারপর popover="manual"-কে শুধু popover করে দেখুন — এবার মেনু খুললে বা বাইরে চাপলে বার্তাটিও বন্ধ হয়ে যায়।

popovertarget-ওয়ালা বাটন কিছু accessibility-র কাজও নিজে করে: screen reader-কে জানায় বাটনটি একটি অংশ খোলে-বন্ধ করে আর বর্তমানে খোলা না বন্ধ (aria-expanded-এর সমান তথ্য), আর light dismiss-এ বন্ধ হলে focus ভেতরে থাকলে বাটনে ফিরিয়ে আনে। তবে মনে রাখুন, popover একটি আচরণ, অর্থ নয় — এটি নিজে কোনো ভূমিকা (role) যোগ করে না। মেনুর ভেতরে লিংকের তালিকা হলে তালিকাই লিখুন, যেমন ওপরে <ul>; আর popover-কে modal-এর কাজে লাগাবেন না — এটি পেছনের পাতা অচল করে না, focus-ও আটকায় না।

ডিফল্টে popover পর্দার মাঝখানে বসে। বাটনের ঠিক নিচে বসাতে চাইলে CSS-এর নতুন anchor positioning লাগে — সেটা পর্ব ৩৭-এ। আর খোলা অবস্থার নকশার জন্য আছে :popover-open pseudo-class (পর্ব ৩৪)।

সাপোর্ট: popover, popovertarget আর popovertargetaction Baseline Newly available — সব প্রধান ব্রাউজারের নতুন সংস্করণে আছে, iPhone-এর Safari-সহ। পুরোনো ব্রাউজারে popover element শুধু লুকানো থাকে না, সাধারণ element-এর মতো পাতায় দেখা যায় — তাই জরুরি তথ্য কেবল popover-এর ভরসায় রাখবেন না। পুরো আচরণ চাইলে feature detection ('popover' in HTMLElement.prototype) দিয়ে শুধু দরকার হলে @oddbird/popover-polyfill-এর মতো polyfill চালানো যায়। হোভারে দেখানোর টিপসের জন্য নতুন popover="hint" মানটি এখনো সব ব্রাউজারে নেই — এখনো Baseline নয়।

৭ · details, dialog না popover — কখন কোনটি

তিনটিই “কিছু একটা দেখা যায়, আবার লুকায়” — তাই গুলিয়ে ফেলা সহজ। প্রশ্ন একটি দিয়ে শুরু করুন: লুকানো অংশটি খুললে পাঠককে কি থামতে হবে? হ্যাঁ হলে modal dialog. না হলে আবার জিজ্ঞেস করুন: অংশটি কি পাতার লেখার প্রবাহের মধ্যেই খুলবে, নাকি ওপরে ভাসবে? প্রবাহের মধ্যে হলে details, ওপরে ভাসলে popover.

বিষয়<details>modal <dialog>popover
কোথায় দেখা যায়পাতার প্রবাহে, নিচের লেখা সরে যায়top layer, পর্দার মাঝেtop layer, ভাসমান
পেছনের পাতাসচলঅচল (inert)সচল
focusস্বাভাবিক Tab-ক্রমেভেতরে যায়, বন্ধ হলে ফেরেস্বাভাবিক; বন্ধ হলে বাটনে ফিরতে পারে
কীভাবে বন্ধsummary-তে আবার চাপEsc, method="dialog", close()auto: বাইরে চাপ বা Esc; manual: শুধু বাটন/JS
JavaScript লাগে?নাখুলতে এক লাইন, অথবা commandনা
নিজস্ব ভূমিকা (role)disclosure (summary = বাটনের মতো)dialogকিছু না — অর্থ আপনি দেবেন
সাপোর্টWidely available (name: Newly)Widely available (command: Newly)Newly available
উদাহরণFAQ, “আরও পড়ুন”, ফিল্টারমুছে ফেলার নিশ্চিতকরণ, লগইন বাক্সপ্রোফাইল মেনু, টিপস, টোস্ট

দুটি সূক্ষ্ম কথা। এক, dialog আর popover একসাথেও চলে — <dialog popover> লিখলে dialog-এর অর্থ (role) আর popover-এর light dismiss দুটোই পাওয়া যায়, যেমন একটি non-modal সহায়তার বাক্স। তবে popover দেওয়া element-এ showModal() ডাকবেন না — দুটি আলাদা খোলার পদ্ধতি। দুই, “পর্দার একপাশ থেকে আসা মোবাইল মেনু” (drawer) যদি পেছনের পাতা অচল করে, তাহলে আসলে সেটি modal dialog — CSS দিয়ে বাক্সটিকে পাশে বসিয়ে দিলেই হলো।

৮ · সাধারণ ভুল — দেখতে ঠিক, ব্যবহারে ভাঙা

নিচের প্রিভিউতে দুটি ভুল আর একটি ঠিক জিনিস আছে। মাউস দিয়ে সবই “কাজ করে” — তাই ভুলগুলো ধরতে হলে কি-বোর্ড দিয়ে পরীক্ষা করতে হবে।

<style>
  .fake { display: inline-block; padding: 4px 12px; background: #2563eb;
          color: #fff; border-radius: 6px; cursor: pointer; }
</style>
<p>প্রিভিউতে চেপে Tab দিন — focus কোথায় কোথায় যায়?</p>

<div class="fake" id="fake">নকল বাটন (div)</div>
<button type="button" id="real">আসল বাটন</button>

<details>
  <p>এই details-এ summary নেই।</p>
</details>

<script>
  for (const b of [document.getElementById('fake'), document.getElementById('real')]) {
    b.addEventListener('click', () => console.log(b.textContent + ' — চাপা হলো'));
  }
</script>

মাউসে দুটি বাটনই লগে লেখা পাঠায়। কিন্তু Tab চাপলে focus নীল “নকল বাটন”-কে এড়িয়ে সরাসরি “আসল বাটন”-এ যায়; সেখানে Enter বা Space চাপলে লগ আসে। তারপর Tab details-এর লেবেলে যায় — যার নাম ব্রাউজার নিজে বসিয়েছে (সাধারণত “Details”), পাঠক জানেন না ভেতরে কী। চেষ্টা করুন: div-টিকে <button type="button" class="fake" id="fake"> বানান (শেষ ট্যাগও </button>) — নকশা একই থাকে, কিন্তু এবার Tab আর Enter কাজ করে। আর details-এর প্রথম লাইনে <summary>বিস্তারিত নিয়মাবলি</summary> যোগ করুন।

আরও কিছু ভুল যা প্রায়ই দেখা যায়

ভুলকী সমস্যাঠিক উপায়
<div onclick> বা <span onclick> দিয়ে বাটনTab, Enter, Space, role — কিছুই নেই<button type="button">
details-এ summary নেই, বা summary প্রথমে নেইঅর্থহীন ডিফল্ট লেবেল; ভুল কাঠামোপ্রথম সন্তান হিসেবে স্পষ্ট summary
summary-র ভেতরে লিংক বা বাটনচাপার জিনিসের ভেতরে চাপার জিনিসলিংক details-এর ভেতরের অংশে রাখুন
modal-এর জন্য <dialog open> বা show()backdrop নেই, পেছন সচল, Esc চলে নাshowModal() বা command="show-modal"
CSS-এ dialog { display: flex }বন্ধ dialog-ও পাতায় দেখা যায় — লুকানোর ডিফল্ট নিয়মটি মুছে যায়dialog[open] { display: flex }
dialog-এর কোনো নাম নেইscreen reader শুধু “ডায়ালগ” বলেশিরোনামে id দিয়ে aria-labelledby
popover দিয়ে “আপনি কি নিশ্চিত?” বাক্সপেছনের পাতা সচল, বাইরে চাপলে হারিয়ে যায়modal dialog
popovertarget div বা লিংকেকাজ করে না — শুধু বাটনে চলে<button popovertarget>

সবচেয়ে বড় শিক্ষা: নিজের কাজ কি-বোর্ডে পরীক্ষা করুন। মাউস সরিয়ে রেখে শুধু Tab, Shift+Tab, Enter, Space আর Esc দিয়ে পুরো পাতা চালিয়ে দেখুন। যা কি-বোর্ডে চলে না, তা অনেক মানুষের জন্য চলেই না। (WCAG 2.2-এর ২.১.১ নিয়ম — Keyboard — ঠিক এটাই চায়; পর্ব ১২-এ বিস্তারিত।)

৯ · AI-এর যুগে — AI-এর বানানো মেনু আর modal যাচাই

“একটা modal বানিয়ে দাও”, “একটা FAQ accordion বানাও” — AI কয়েক সেকেন্ডে কোড দেবে। কিন্তু AI শিখেছে ইন্টারনেটের বিশাল পুরোনো কোড থেকে, যেখানে ২০১০-এর দশকের jQuery আর div-ভিত্তিক modal ভরা। তাই প্রায়ই পাবেন ৫০ লাইনের JavaScript, z-index: 9999, হাতে লেখা focus-ফাঁদ — যেখানে কয়েক লাইনের <dialog>-ই যথেষ্ট ছিল। আবার উল্টোটাও ঘটে: AI একেবারে নতুন attribute দেয় কিন্তু সাপোর্টের কথা বলে না।

AI-এর ভুলকীভাবে চিনবেনকী চাইবেন
div-ভিত্তিক modal, হাতে লেখা overlay.modal, .overlay class, display: none/block বদলানো স্ক্রিপ্ট<dialog> + showModal()
JavaScript দিয়ে accordionপ্রতিটি প্রশ্নে click listener, .active classdetails-summary, দরকারে name
span/div-এ onclickবাটনের মতো দেখতে কিন্তু ট্যাগ div<button type="button">
নতুন ফিচার, কিন্তু fallback নেইcommandfor, closedby, popover="hint" ছাড়া কিছু নেইBaseline অবস্থা আর fallback
ভুল ARIArole="button" আসল বাটনে, বা dialog-এ বাড়তি role="dialog"নিজস্ব element-এ বাড়তি ARIA নয়

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

তুমি একজন অ্যাক্সেসিবিলিটি-সচেতন ফ্রন্ট-এন্ড ডেভেলপার। আমার অনলাইন দোকানের পণ্য-পাতার জন্য দুটি জিনিস বানাও: ১. "অর্ডার বাতিল" বাটনে চাপলে একটি modal নিশ্চিতকরণ বাক্স — নিজস্ব <dialog> দিয়ে, div-ভিত্তিক modal নয়। বন্ধ করতে <form method="dialog">, শিরোনাম aria-labelledby দিয়ে যুক্ত, "না, রাখুন" বাটনে autofocus. ২. পাঁচটি প্রশ্নের FAQ — <details> আর <summary> দিয়ে, একই name দিয়ে একটি-খোলা accordion. শর্ত: চাপা যায় এমন সব কিছু <button>; কোনো div-এ onclick নয়; নিজস্ব element-এ বাড়তি role দেবে না; z-index দিয়ে overlay বানাবে না। খোলার জন্য command/commandfor ব্যবহার করলে feature detection-সহ ছোট JavaScript fallback দাও। শেষে বলো: প্রতিটি ফিচারের Baseline অবস্থা কী, আর শুধু কি-বোর্ড দিয়ে (Tab, Enter, Esc) পুরোটা কীভাবে চলবে।

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

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

  • <details> আর <summary> কী কাজে লাগে? — JavaScript ছাড়া খোলা-বন্ধ হওয়া অংশ (FAQ, accordion); summary সব সময় দেখা যাওয়া শিরোনাম, details-এর প্রথম সন্তান।
  • show() আর showModal()-এর পার্থক্য? — showModal top layer-এ modal খোলে, backdrop দেয়, বাকি পাতা inert করে আর Esc-এ বন্ধ হয়; show শুধু non-modal ভাবে দেখায়।
  • <form method="dialog"> কী করে? — জমা দিলে সার্ভারে কিছু পাঠায় না; dialog বন্ধ করে আর চাপা বাটনের value returnValue-তে রাখে।
  • popover="auto" আর "manual"-এর পার্থক্য? — auto light dismiss হয় আর একসাথে একটিই খোলা থাকে; manual শুধু বাটন বা স্ক্রিপ্টে বন্ধ হয়।
  • div-এ onclick দিয়ে বাটন বানানো কেন ভুল? — focus পায় না, Enter/Space চলে না, screen reader বাটন হিসেবে চেনে না; ARIA-র প্রথম নিয়ম — নিজস্ব <button> ব্যবহার করুন।

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

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

প্র ০১modal তো ওয়েবে বহু বছর ধরেই আছে — তাহলে নিজস্ব <dialog> সব ব্রাউজারে আসতে এত দেরি হলো কেন?

কারণ modal দেখতে সহজ, কিন্তু ঠিকভাবে বানানো আশ্চর্য রকম কঠিন — আর ব্রাউজার-নির্মাতারা “ঠিকভাবে” নিয়ে একমত হতে সময় নিয়েছেন।

২০০০-এর দশকে modal মানে ছিল window.alert() বা নতুন পপ-আপ জানালা। পপ-আপ বিজ্ঞাপনের অত্যাচারে ব্রাউজারগুলো পপ-আপ আটকাতে শুরু করল, আর alert-এর চেহারা বদলানো যেত না। তখন jQuery UI, পরে Bootstrap-এর মতো লাইব্রেরি div দিয়ে পাতার ভেতরেই modal বানানো জনপ্রিয় করল। প্রতিটি লাইব্রেরি নিজের মতো সমস্যা সমাধান করত: overlay দিয়ে পেছন ঢাকা, z-index-এর লড়াই, focus ভেতরে আটকানো, Esc ধরা, বন্ধ হলে focus ফেরানো, পেছনের পাতা screen reader থেকে লুকানো। অনেক লাইব্রেরি এর কয়েকটি ভুলে যেত।

<dialog> element-এর প্রস্তাব এসেছিল ২০১০-এর দশকের শুরুতে, আর Chrome ২০১৪ সালেই এটি চালু করে। কিন্তু Firefox আর Safari বহু বছর অপেক্ষা করে। কারণগুলো ছিল আসল: focus কোথায় যাবে, modal খোলা থাকলে পেছনের পাতা ঠিক কতটা অচল হবে, screen reader-কে কী জানানো হবে — এসব প্রশ্নে spec অস্পষ্ট ছিল, আর accessibility বিশেষজ্ঞরা প্রথম দিকের সংস্করণের সমালোচনা করেছিলেন। এক সময় মনে হচ্ছিল dialog বাদই পড়ে যাবে। শেষ পর্যন্ত spec-এ focus-এর নিয়ম, “inert” ধারণা আর top layer স্পষ্ট করা হলো; Firefox আর Safari ২০২২ সালের মার্চে প্রায় একসাথে dialog চালু করল — তখনই এটি Baseline হয়।

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

মূল উপলব্ধি: নিজস্ব element-এর পেছনে বছরের পর বছর বিশেষজ্ঞদের তর্ক আর পরীক্ষা থাকে। আপনি এক লাইনে যা পান, নিজে বানাতে গেলে তার প্রতিটি সমস্যা নতুন করে সমাধান করতে হতো।

প্র ০২“z-index: 9999” দিয়ে তো modal ওপরে আনা যেত — top layer আলাদা করে কেন লাগল?

কারণ z-index সর্বশক্তিমান নয়। এটি কাজ করে একটি stacking context-এর ভেতরে। কোনো element-এ transform, opacity একের কম, position সহ z-index, বা filter থাকলে সে নিজের একটি আলাদা stacking context বানায় — তার ভেতরের কোনো element, z-index এক লাখ দিলেও, বাইরের অন্য context-এর ওপরে উঠতে পারে না। ঠিক যেন একটি বহুতল ভবনের তৃতীয় তলার ফ্ল্যাটে আপনি যত উঁচু আলমারিই রাখুন, সেটি চতুর্থ তলার মেঝে ভেদ করবে না।

বাস্তবে এটা প্রতিদিনের সমস্যা ছিল। একটি কার্ডের ভেতরে modal-এর কোড, আর কার্ডে একটি হালকা অ্যানিমেশনের জন্য transform — হঠাৎ modal হেডারের নিচে চাপা পড়ে। অথবা কন্টেইনারে overflow: hidden, আর modal-এর অর্ধেক কেটে গেল। তাই লাইব্রেরিগুলো modal-কে DOM থেকে তুলে নিয়ে <body>-এর একদম শেষে বসাত (“portal”). আর ডেভেলপাররা z-index-এর প্রতিযোগিতায় নামতেন: ৯৯৯, ৯৯৯৯, ৯৯৯৯৯ — যে টিমে যত বেশি লাইব্রেরি, তত বেশি সংখ্যা।

top layer এই খেলাটাই বন্ধ করে দিয়েছে। এটি পাতার সব stacking context-এর বাইরে একটি আলাদা স্তর। showModal() বা popover খুললে element-টি DOM-এ নিজের জায়গাতেই থাকে (তাই CSS আর JavaScript-এর সম্পর্ক ভাঙে না), কিন্তু আঁকার সময় ব্রাউজার তাকে সবার ওপরে আঁকে, কোনো পূর্বপুরুষের overflow বা transform-এর তোয়াক্কা না করে। top layer-এর ভেতরে ক্রম সরল: যেটি পরে খুলেছে সেটি ওপরে। তাই dialog-এর ভেতর থেকে একটি popover খুললে popover-টি dialog-এর ওপরে আসে — কোনো z-index ছাড়াই।

এর একটি দাম আছে: top layer-এর element-এর অবস্থান নিয়ন্ত্রণ করা একটু আলাদা — এটি পর্দার সাপেক্ষে বসে, পূর্বপুরুষের সাপেক্ষে নয়। এ কারণেই বাটনের পাশে popover বসাতে CSS anchor positioning-এর মতো নতুন টুল এসেছে।

মূল উপলব্ধি: কিছু সমস্যা কৌশল দিয়ে সমাধান হয় না, প্ল্যাটফর্মের কাঠামো বদলাতে হয়। top layer সেই কাঠামোগত সমাধান — একটি সংখ্যার প্রতিযোগিতা শেষ হয়েছে একটি নতুন স্তর দিয়ে।

প্র ০৩popover তো নিজে কোনো role দেয় না — তাহলে এটা “accessible” কীভাবে? আর কখন popover-এর বদলে dialog দরকার?

popover-এর ডিজাইনাররা ইচ্ছা করেই একে আচরণ বানিয়েছেন, অর্থ নয়। কারণ ভাসমান জিনিস অনেক রকম: একটি মেনু, একটি তালিকা, একটি ছোট ফর্ম, একটি বার্তা, একটি ব্যাখ্যা। সবার জন্য একটি role চাপিয়ে দিলে বেশিরভাগ ক্ষেত্রে ভুল হতো। তাই popover শুধু সেই অংশগুলো দেয় যা সবার ক্ষেত্রে এক: top layer-এ দেখানো, light dismiss, Esc, একসাথে একটি auto popover, আর বাটনের সাথে সম্পর্ক।

ওই সম্পর্কটাই accessibility-র বড় অংশ। popovertarget দেওয়া বাটনকে ব্রাউজার screen reader-এর কাছে জানায় “এটি একটি অংশ খোলে, এখন বন্ধ/খোলা” — যা আগে হাতে aria-expanded লিখে আর প্রতিবার JavaScript-এ বদলে করতে হতো (আর প্রায়ই ভুলে যাওয়া হতো)। কি-বোর্ড ব্যবহারকারীর জন্য Tab-ক্রমও যুক্তিসংগত রাখা হয়: popover খোলা থাকলে বাটনের পরে Tab চাপলে popover-এর ভেতরে যাওয়া যায়, যদিও DOM-এ সেটি দূরে থাকতে পারে। light dismiss-এ বন্ধ হলে, focus ভেতরে থাকলে, তা বাটনে ফেরে।

বাকি অর্থ আপনার দায়িত্ব। মেনুতে লিংকের তালিকা হলে <ul> আর <a>; বার্তা হলে দরকারে একটি live region (পর্ব ১২); শিরোনাম-ওয়ালা বাক্স হলে <dialog popover> লিখে dialog-এর role নিন।

কখন popover যথেষ্ট নয়? যখন পাঠককে থামাতেই হবে। “আপনার অ্যাকাউন্ট মুছে যাবে — নিশ্চিত?” প্রশ্নের সময় পেছনের পাতা সচল থাকলে, বা বাইরে ভুল করে চাপ লাগলে বাক্স হারিয়ে গেলে, সেটি বিপজ্জনক। modal dialog পেছনের পাতা inert করে, focus ভেতরে আনে, আর বন্ধ করার স্পষ্ট পথ দেয়। আবার উল্টো ভুলও আছে: ছোট একটি মেনুর জন্য modal দিলে পাঠক অকারণে আটকে যান — প্রতিবার আলাদা করে বন্ধ করতে হয়।

মূল উপলব্ধি: আচরণ আর অর্থ আলাদা স্তর। popover আচরণ দেয়, অর্থ দেয় HTML-এর বাকি element. আর “পাঠককে কি থামাতে হবে?” — এই একটি প্রশ্নই বলে দেয় popover না modal.

প্র ০৪বাংলাদেশের মতো ধীর ও অনিশ্চিত ইন্টারনেটে “HTML-ই আগে” নীতি কেন আরও বেশি জরুরি?

কারণ JavaScript হলো পাতার সবচেয়ে ভঙ্গুর অংশ। একটি HTML পাতা আংশিক লোড হলেও যতটুকু এসেছে ততটুকু দেখায় আর কাজ করে। কিন্তু একটি বড় JavaScript ফাইল পুরো না নামা, পার্স না হওয়া আর চালু না হওয়া পর্যন্ত তার কোনো কাজই হয় না। মোবাইল ডেটা দুর্বল হলে, ট্রেনে বা গ্রামে নেটওয়ার্ক বারবার কেটে গেলে, বিজ্ঞাপন-আটকানো এক্সটেনশন কোনো স্ক্রিপ্ট আটকে দিলে, বা স্ক্রিপ্টের একটি ছোট ভুলে পুরো ফাইল থেমে গেলে — div দিয়ে বানানো accordion আর modal মৃত, কিন্তু details আর popover তখনও চলে।

আরেকটি দিক হলো যন্ত্রের শক্তি। কম দামি Android ফোনে JavaScript পার্স ও চালাতে দামি ফোনের চেয়ে অনেক বেশি সময় লাগে। একটি modal লাইব্রেরির জন্য কয়েক ডজন কিলোবাইট স্ক্রিপ্ট মানে পাতা “দেখা যায় কিন্তু চাপলে সাড়া দেয় না” — এমন বিরক্তিকর সময় বাড়ে। Core Web Vitals-এর INP মাপকাঠি ঠিক এই সাড়া দেওয়ার দেরি মাপে (পর্ব ৪৯)। নিজস্ব element ব্রাউজারের ভেতরের দ্রুত কোডে চলে, আপনার পাঠানো স্ক্রিপ্ট লাগে না।

এই চিন্তার নাম progressive enhancement: ভিত্তি হবে সবার জন্য কাজ করা HTML, তার ওপর CSS-এর সাজ, তার ওপর JavaScript-এর বাড়তি সুবিধা। details-এর name এর সুন্দর উদাহরণ — পুরোনো ব্রাউজার এটি না চিনলেও কিছু ভাঙে না, শুধু একসাথে কয়েকটি খোলা যায়। invoker commands-এর fallback স্ক্রিপ্টও একই চিন্তা — নতুন ব্রাউজারে স্ক্রিপ্ট ঘুমিয়ে থাকে।

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

মূল উপলব্ধি: যে কাজ HTML পারে, সেটা HTML-কেই দিন। JavaScript রাখুন যেখানে সত্যিই দরকার — তাহলে আপনার পাতা সবচেয়ে খারাপ নেটওয়ার্ক আর সবচেয়ে সস্তা ফোনেও কাজ করবে।

প্র ০৫popover আর invoker commands-এর মতো নতুন ফিচার কোথা থেকে আসে — আর কখন নিশ্চিন্তে ব্যবহার করবেন?

অনেক নতুন ইন্টারঅ্যাকটিভ ফিচারের জন্ম Open UI নামের W3C-র একটি community group-এ। এর সদস্যরা — ব্রাউজার-নির্মাতা, ডিজাইন সিস্টেম বানানো কোম্পানির প্রকৌশলী, accessibility বিশেষজ্ঞ — প্রথমে জরিপ করেন জনপ্রিয় UI লাইব্রেরিগুলো একটি উপাদান (যেমন মেনু, টুলটিপ, select) কীভাবে বানায়, কোথায় সবাই একই সমস্যায় পড়ে। তারপর প্রস্তাব যায় WHATWG-এর HTML spec-এ। popover প্রথম দিকে আলাদা একটি element হিসেবে ভাবা হয়েছিল; আলোচনায় দেখা গেল একটি attribute হলে যেকোনো element-এ বসানো যায় — তাই আজকের popover attribute. invoker commands-ও প্রথমে অন্য নামে প্রস্তাবিত হয়েছিল, পরে নাম বদলে command আর commandfor হয় — পুরোনো ব্লগ বা AI-এর উত্তরে আগের নাম দেখলে সাবধান হবেন।

একটি ফিচার একটি ব্রাউজারে আসা মানেই সবার জন্য ব্যবহারযোগ্য নয়। এখানে Baseline কাজে লাগে। Newly available মানে সব প্রধান ব্রাউজারের (Chrome, Edge, Firefox, Safari — ডেস্কটপ ও মোবাইল) সর্বশেষ সংস্করণে আছে। কিন্তু মানুষ সঙ্গে সঙ্গে ব্রাউজার আপডেট করেন না — বিশেষ করে পুরোনো iPhone, যেখানে Safari অপারেটিং সিস্টেমের সাথে বাঁধা। তাই Newly available হওয়ার প্রায় আড়াই বছর (৩০ মাস) পরে আসে Widely available লেবেল।

ব্যবহারের নিয়ম তাই তিন স্তরের। Widely available (details, dialog) — নিশ্চিন্তে। Newly available (popover, details-এর name, invoker commands) — ব্যবহার করুন, কিন্তু ভাবুন পুরোনো ব্রাউজারে কী হবে: কিছু না ভাঙলে (name) সরাসরি; মূল কাজ আটকে গেলে (modal খোলা) fallback সহ। Baseline-নয় (closedby, popover="hint") — শুধু বাড়তি সুবিধা হিসেবে, যার অভাবে কারও কোনো ক্ষতি হয় না।

আর সবচেয়ে বড় সতর্কতা: সাপোর্ট-তথ্য দ্রুত বদলায়। বই, পুরোনো টিউটোরিয়াল, এমনকি এই পর্বও এক বছর পরে কিছুটা পুরোনো হবে। তাই সিদ্ধান্তের আগে MDN-এর পাতার নিচের সাপোর্ট-টেবিল আর Can I use দেখে নেওয়ার অভ্যাস করুন।

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

অনুশীলন

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

  1. কোনটির জন্য কোনটি? (ক) একটি চাকরির বিজ্ঞপ্তির পাতায় “যোগ্যতা”, “বেতন”, “আবেদনের নিয়ম” — প্রতিটি খোলা-বন্ধ হবে (খ) “আপনার খসড়া মুছে যাবে, নিশ্চিত?” (গ) পাতার ওপরে ভাষা বদলের ছোট মেনু: বাংলা / English (ঘ) “ফাইল আপলোড হয়েছে” বার্তা, যা পাঠক নিজে বন্ধ না করা পর্যন্ত কোণে থাকবে।

    (ক) <details> — পাতার প্রবাহের ভেতরে খোলা-বন্ধ; পাঠক হয়তো দুটি একসাথে পড়তে চান, তাই name না দেওয়াই ভালো। (খ) modal <dialog> — পাঠককে থামিয়ে সিদ্ধান্ত চাই; “না, রাখুন” বাটনে autofocus. (গ) popover (auto) — ক্ষণিকের মেনু, বাইরে চাপলে বন্ধ হওয়াই স্বাভাবিক; ভেতরে লিংকের তালিকা। (ঘ) popover="manual" — নিজে বা অন্য popover-এর কারণে বন্ধ হবে না, শুধু “ঠিক আছে” বাটনে। (স্ক্রিন রিডারে ঘোষণা চাইলে ভেতরে একটি live region লাগবে — পর্ব ১২।)

  2. কি-বোর্ড পরীক্ষা: আপনার প্রিয় যেকোনো একটি বাংলাদেশি ওয়েবসাইট (খবর, দোকান বা সরকারি সেবা) খুলুন। মাউস সরিয়ে রেখে শুধু Tab, Enter আর Esc দিয়ে মেনু খুলুন, FAQ খুলুন, কোনো পপ-আপ থাকলে বন্ধ করুন। কোথায় আটকে গেলেন? DevTools-এর Elements প্যানেলে সেই অংশটি কী দিয়ে বানানো?

    অনেক সাইটে দেখবেন: মেনুর কোনো আইটেমে Tab পৌঁছায় না, বা পৌঁছালেও focus-এর কোনো দাগ দেখা যায় না; পপ-আপ Esc-এ বন্ধ হয় না; পপ-আপ খোলা থাকলেও Tab পেছনের পাতায় চলে যায়। Elements প্যানেলে প্রায়ই পাবেন <div class="dropdown" onclick…> বা <div class="modal"> — অর্থাৎ নিজস্ব element নয়। যেখানে <button>, <details> বা <dialog> আছে, সেখানে সাধারণত কি-বোর্ডে সব ঠিকঠাক চলে। এই পরীক্ষাটি একজন পেশাদার accessibility নিরীক্ষকের প্রথম কাজ।

  3. রহস্যময় dialog: একজন ডেভেলপার CSS-এ লিখলেন dialog { display: flex; flex-direction: column; gap: 1rem; }. এরপর পাতা খুলতেই দেখা গেল বন্ধ থাকার কথা যে dialog-এর, সেটি পাতায় দেখা যাচ্ছে। কেন? সমাধান কী?

    ব্রাউজারের নিজের স্টাইলশিটে (user-agent stylesheet) আছে মোটামুটি এমন নিয়ম: dialog:not([open]) { display: none; }. বন্ধ dialog লুকানো থাকে শুধু এই display: none-এর জোরে। ডেভেলপারের dialog { display: flex } নিয়মটি লেখকের (author) নিয়ম, আর cascade-এ লেখকের নিয়ম ব্রাউজারের ডিফল্টের চেয়ে বেশি গুরুত্ব পায় বলে সেটিই জেতে (কেন — পর্ব ১৮-এর cascade), ফলে বন্ধ dialog-ও flex হয়ে দেখা যায়। সমাধান: শুধু খোলা অবস্থায় লেআউট দিন — dialog[open] { display: flex; … }. popover-এর ক্ষেত্রেও একই ফাঁদ: [popover] { display: grid } না লিখে :popover-open-এ লিখুন।

  4. নিজে লিখুন — বই কেনার নিশ্চিতকরণ: একটি বাটন “অর্ডার নিশ্চিত করুন” চাপলে modal আসবে: শিরোনাম “অর্ডার নিশ্চিত?”, নিচে দুটি বাটন “না” আর “হ্যাঁ”। JavaScript ছাড়া খুলবে (invoker commands), method="dialog" দিয়ে বন্ধ হবে, আর “না”-তে autofocus থাকবে। ওপরের যেকোনো লাইভ এডিটরে লিখে পরীক্ষা করুন।

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

    <button type="button" command="show-modal" commandfor="order">
      অর্ডার নিশ্চিত করুন
    </button>
    
    <dialog id="order" aria-labelledby="order-title">
      <h2 id="order-title">অর্ডার নিশ্চিত?</h2>
      <p>মোট: ৩৫০ টাকা (উদাহরণ)</p>
      <form method="dialog">
        <button value="no" autofocus>না</button>
        <button value="yes">হ্যাঁ</button>
      </form>
    </dialog>

    যাচাই: Tab দিয়ে বাটনে এসে Enter — modal খোলে, focus “না”-তে। Enter চাপলে বন্ধ, focus আবার “অর্ডার নিশ্চিত করুন”-এ। পুরোনো ব্রাউজারের জন্য পর্বের ৫ নম্বর অংশের মতো feature detection-সহ fallback স্ক্রিপ্ট যোগ করুন। আর “হ্যাঁ” চাপা হলো কি না জানতে close ইভেন্টে returnValue পড়ুন — সেটি হবে yes বা no.

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

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

ক্রমshowModal() দিয়ে খোলা একটি modal dialog-এ পরপর যা ঘটে, সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. পাঠক “খুলুন” বাটনে চাপেন, ব্রাউজার মনে রাখে focus কোথায় ছিল
  2. dialog top layer-এ ওঠে, পেছনে ::backdrop বসে
  3. বাকি পাতা inert হয় আর focus dialog-এর ভেতরে যায়
  4. পাঠক Esc চাপেন — আগে cancel, তারপর close ইভেন্ট
  5. focus ফিরে যায় সেই বাটনে, যেখান থেকে খোলা হয়েছিল

একটি ওয়েবপেজের FAQ অংশে প্রতিটি প্রশ্নে চাপলে উত্তর খুলবে, আর কোনো JavaScript ব্যবহার করা যাবে না। কোন element জুটি সবচেয়ে উপযুক্ত?

  • <dl> আর <dd>
  • <div>-এ onclick দিয়ে উত্তর দেখানো
  • <details> আর <summary>
  • <dialog> আর <form method="dialog">

একটি পাতায় চারটি <details>-এ একই name="faq" দেওয়া আছে। পাঠক একটি খুললে কী ঘটে?

  • ফর্ম জমা দেওয়ার সময় খোলা details-টির নাম পাঠানো হয়
  • ওই দলের অন্য খোলা details নিজে থেকে বন্ধ হয়ে যায়
  • চারটিই একসাথে খুলে যায়
  • ব্রাউজার ভুল বলে details-গুলো দেখায় না

dialog.show()-এর তুলনায় dialog.showModal() কোন কাজটি করে?

  • শুধু dialog-এ open attribute যোগ করে
  • dialog বন্ধ করে returnValue ফেরত দেয়
  • dialog খোলে, কিন্তু পেছনের পাতা পুরো সচল রাখে
  • top layer-এ তুলে backdrop দেয়, বাকি পাতা inert করে আর Esc-এ বন্ধ হতে দেয়

একটি <dialog>-এর ভেতরে <form method="dialog">, তার ভেতরে <button value="ok">. বাটনটি চাপলে কী হয়?

  • dialog বন্ধ হয়, আর তার returnValue হয় "ok"
  • ফর্মের ডেটা সার্ভারে পাঠানো হয়, পাতা নতুন করে লোড হয়
  • কিছুই হয় না, বন্ধ করতে JavaScript লাগে
  • dialog বন্ধ হয়, কিন্তু কোন বাটন চাপা হলো তা জানার উপায় থাকে না

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

  • <div popover="auto">
  • showModal() দিয়ে খোলা <dialog>
  • <div popover="manual">, আর বাটনে popovertargetaction="hide"
  • <details open>

একটি ওয়েবসাইটে “সংরক্ষণ” লেখা জিনিসটি <div onclick="save()"> দিয়ে বানানো। এর প্রধান সমস্যা কী?

  • div-এর রং বদলানো যায় না
  • কি-বোর্ডে Tab-এ পৌঁছায় না, Enter/Space-এ চলে না, screen reader বাটন হিসেবে চেনে না
  • মাউসে ক্লিক করলে কাজ করে না
  • HTML validator এটিকে অবৈধ বলে পাতা দেখায় না

শব্দকোষ

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

মনে রাখুন

  1. নিজস্ব element আগে: চাপা যায় এমন জিনিস <button>; div-এ onclick মানে কি-বোর্ড আর screen reader-এর জন্য ভাঙা জিনিস।
  2. details + summary = JavaScript-হীন খোলা-বন্ধ; open হলো বর্তমান অবস্থা; একই name = একটি-খোলা accordion (Newly available, পুরোনোয় নিরাপদে স্বাধীন)।
  3. modal dialog = showModal() বা command="show-modal": top layer, ::backdrop, inert পাতা, focus ভেতরে ও ফেরত, Esc; বন্ধে method="dialog" আর returnValue.
  4. popover = ভাসমান, পাঠককে থামায় না; popovertarget বাটনে; auto = light dismiss, manual = শুধু বাটন/স্ক্রিপ্টে বন্ধ; অর্থ (role) আপনাকে দিতে হয়।
  5. সাপোর্ট জেনে: details, dialog Widely; popover, name, invoker commands Newly — feature detection-সহ fallback; আর সব কিছু কি-বোর্ডে পরীক্ষা।

পরের পর্বে: এই পর্বে বারবার screen reader, focus আর ARIA-র কথা এসেছে। এবার সেগুলোর পুরো গল্প — অ্যাক্সেসিবিলিটি কী, screen reader আসলে কীভাবে পাতা পড়ে, WCAG-এর মূল নীতি, আর ARIA কখন সাহায্য করে আর কখন ক্ষতি।

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

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