পাতা সাজানো হচ্ছে•••
পাঠকের খেলাঘরছোট্ট বুদ্ধির আসর৬টি টেক প্রশ্ন · প্রতি খেলায় নতুন সেট
ধাঁধা ১ / ৬স্কোর ০ / ৬
আমি ইন্টারনেটের ঠিকানা-বই: নাম থেকে সার্ভারের IP ঠিকানা খুঁজে দিই। আমি কে?

বিজ্ঞাপনের স্থানহেডারের নিচে

বিষয়ভিত্তিক লেখা

Accessibility

এই বিভাগের লেখাগুলো একসঙ্গে পড়ুন।

Wednesday, October 21, 2026

নিরাপদ Accessible Notice Box-এর জন্য Custom WordPress Shortcode Plugin

নিরাপদ Accessible Notice Box-এর জন্য Custom WordPress Shortcode Plugin

বারবার সতর্কতা, টিপস বা সাফল্যের বার্তা লিখতে HTML কপি-পেস্ট করা বিরক্তিকর। একটি ছোট shortcode plugin এই কাজকে সম্পাদকের জন্য সহজ করে, আবার theme বদলালেও কাজটি রেখে দেয়। এই উদাহরণে [bns_notice] tag, তিনটি সীমিত type এবং accessible aside ব্যবহার করব। শুরুতেই staging-এ plugin চালান; production-এ নেওয়ার আগে backup রাখুন।

কেন plugin, theme নয়?

Shortcode হলো content-এর ছোট placeholder, যা render-এর সময় callback-এ যায়। Theme-এর functions.php-তে রাখলে theme বদলালে হারাতে পারে; plugin-এ রাখলে content portability ভালো থাকে। Tag-এ নিজের prefix ব্যবহার করুন, কারণ একই নামের shortcode হলে পরে load হওয়া callback আগেরটিকে override করতে পারে।

ফাইল ও কোড

wp-content/plugins/bengali-notice-shortcode/bengali-notice-shortcode.php বানিয়ে এই কোড বসান:

<?php
/**
 * Plugin Name: Bengali Notice Shortcode
 * Description: Accessible notice box shortcode.
 * Version: 1.0.0
 */
if ( ! defined( 'ABSPATH' ) ) { exit; }

function bns_notice_shortcode( $atts, $content = null ) {
    $atts = shortcode_atts(
        array( 'type' => 'info', 'title' => '' ),
        $atts,
        'bns_notice'
    );
    $allowed = array( 'info', 'success', 'warning' );
    $type = in_array( $atts['type'], $allowed, true ) ? $atts['type'] : 'info';
    $title = sanitize_text_field( $atts['title'] );
    $body  = wp_kses_post( do_shortcode( $content ?? '' ) );
    $label = $title ? '<strong class="bns-title">' . esc_html( $title ) . '</strong>' : '';
    return '<aside class="bns-notice bns-' . esc_attr( $type ) . '" role="status">' . $label . '<div>' . $body . '</div></aside>';
}
add_shortcode( 'bns_notice', 'bns_notice_shortcode' );

কোডটি কীভাবে নিরাপদ?

shortcode_atts() শুধু অনুমোদিত type ও title রাখে এবং default পূরণ করে। type-কে allow-list দিয়ে মিলিয়েছি; অজানা value হলে info হবে। title plain text, তাই sanitize_text_field() দিয়ে পরিষ্কার করে output-এ esc_html() করেছি। class attribute-এ esc_attr() আছে। ভেতরের content-এ সাধারণ formatting দরকার বলে wp_kses_post() ব্যবহার করেছি—এটি arbitrary script ঢুকতে দেয় না। Shortcode callback-এ echo নয়, string return করা উচিত।

ব্যবহার

[bns_notice type="warning" title="ব্যাকআপ নিন"]লাইভ সাইটে পরিবর্তনের আগে staging পরীক্ষা করুন।[/bns_notice]

[bns_notice type="success" title="সম্পন্ন"]ফাইলটি আপলোড হয়েছে।[/bns_notice]

[bns_notice]শুধু তথ্যের বার্তা।[/bns_notice]

Plugin activate করে একটি post-এ shortcode দিন। Output দেখে keyboard focus, contrast এবং screen reader-এ অর্থপূর্ণ ঘোষণা হচ্ছে কি না পরীক্ষা করুন। role="status" সাধারণ status বার্তার জন্য উপযোগী; জরুরি বিপদ হলে আলাদা আচরণ দরকার, তাই নির্বিচারে alert ব্যবহার করবেন না। CSS না থাকলেও semantic aside পাঠযোগ্য থাকবে। চাইলে plugin-এ enqueue করা ছোট stylesheet যোগ করুন—inline style দিয়ে content ভারী করবেন না।

সীমা ও রক্ষণাবেক্ষণ

এই shortcode title-এ markup ইচ্ছাকৃতভাবে নিষিদ্ধ। body-তে allowed HTML রাখা হয়েছে, তবুও untrusted shortcode nesting বা third-party filter থাকলে staging-এ পরীক্ষা জরুরি। Function prefix করা হয়েছে যাতে global namespace সংঘর্ষ কমে। ভবিষ্যতে নতুন type যোগ করলে allow-list, CSS এবং documentation একসঙ্গে বদলান।

সম্পাদকের জন্য ছোট নিয়ম

একটি notice-এ একটাই উদ্দেশ্য রাখুন। title সংক্ষিপ্ত, body-তে সরাসরি নির্দেশনা এবং প্রয়োজন হলে একটি descriptive link দিন। একই post-এ অনেক nested notice দিলে screen reader-এর reading flow ভারী হতে পারে। তাই editorial guideline-এ type-এর অর্থ লিখে দিন: info সাধারণ তথ্য, success সম্পন্ন কাজ, warning সতর্কতা।

CSS যোগ করার সময় শুধু রঙের উপর নির্ভর করবেন না; border, icon-এর accessible label বা heading-ও ব্যবহার করুন। contrast checker দিয়ে foreground ও background পরীক্ষা করুন। HTML output পরিবর্তন করলে view-source এবং keyboard navigation দুটোই যাচাই করুন। Shortcode content-এ user-generated text থাকলে allowed markup সীমিত রাখাই নিরাপদ।

Plugin update করার আগে staging-এ পুরোনো post render হচ্ছে কি না দেখুন। shortcode tag rename করলে পুরোনো content ভেঙে যাবে, তাই দরকার হলে পুরোনো tag-এর compatibility alias রাখুন। Function name-এ prefix এবং unique CSS class ব্যবহার করলে অন্য plugin-এর সঙ্গে সংঘর্ষের সম্ভাবনা কমে।

ছোট কিন্তু জরুরি যাচাই

কোড বসানোর পরে শুধু editor-এ সবুজ দেখালেই শেষ নয়। আলাদা browser-এ logged-out অবস্থায় page খুলুন, keyboard দিয়ে link ও control চালান, এবং mobile width-এ horizontal scroll হচ্ছে কি না দেখুন। PHP ও WordPress version-এর compatibility নোট করুন। staging-এ error log দেখে warning থাকলে সমাধান করুন; live সাইটে অযথা debug output দেখাবেন না। Backup ফেরত আনার পদ্ধতিও আগে পরীক্ষা করে রাখুন। কোনও third-party plugin একই hook বা class ব্যবহার করছে কি না দেখলে prefix বদলান। ছোট পরিবর্তন একবারে deploy করলে সমস্যা হলে কোন অংশ rollback করতে হবে তা স্পষ্ট থাকে। এই নিয়মগুলি theme, shortcode এবং CPT—তিন ক্ষেত্রেই প্রযোজ্য।

নোট লিখে রাখুন কোন file কোথায় রাখা হয়েছে এবং কোন shortcode বা URL পরীক্ষা করা হয়েছে। এতে ভবিষ্যতের update-এ ভুল কমে এবং অন্য developer দ্রুত দায়িত্ব নিতে পারেন। এই অভ্যাসটি রাখুন।

আরও পড়ুন

সতর্কতা: লাইভ সাইটে বদলানোর আগে staging কপি, পূর্ণ backup এবং rollback পরিকল্পনা রাখুন। কোডটি নিজের WordPress/PHP সংস্করণে পরীক্ষা করুন।

Tuesday, October 20, 2026

HTML ও CSS দিয়ে Contact Form: JavaScript ভ্যালিডেশনসহ বাংলা গাইড

HTML ও CSS ফর্ম—ইনপুট ও যাচাই চিহ্নের মৌলিক চিত্র

এই লেখার কোড একটি শিক্ষামূলক, front-end-only ডেমো। এটি কোনো বার্তা পাঠায় না, কোনো API-তে request করে না এবং কোনো backend submit নেই। Submit চাপলে সফল দেখালেও স্পষ্টভাবে “NOT sent” লেখা হয়—তাই এটিকে production contact system মনে করবেন না।

কেন contact form-এ শুধু সুন্দর input যথেষ্ট নয়

Contact form দেখতে ছোট হলেও এটি ব্যবহারকারীর ভাষা, browser-এর native validation, keyboard navigation, assistive technology এবং ভবিষ্যৎ server নিরাপত্তার মাঝখানে একটি চুক্তি তৈরি করে। একটি input-এর পাশে placeholder বসালেই সেই চুক্তি পূর্ণ হয় না। Placeholder ফাঁকা হলে label হারিয়ে যায়; লেবেল না থাকলে screen reader ব্যবহারকারী কোন তথ্য চাইছে বুঝতে পারেন না; error কেবল লাল border হলে রঙ না দেখা বা কম contrast-এর ব্যবহারকারী কারণটি জানতে পারেন না। তাই এখানে লক্ষ্য হল—একই markup থেকে আগে HTML-এর স্বাভাবিক সুবিধা পাওয়া, পরে অল্প JavaScript দিয়ে বার্তা ও interaction উন্নত করা।

এই article-এ আমরা নাম, email, বিষয় এবং বার্তার চারটি field দিয়ে একটি ছোট contact form বানাব। প্রতিটি field-এর দৃশ্যমান label থাকবে, required এবং type="email" browser-কে প্রাথমিক constraint দেবে, CSS :focus-visible keyboard focus আলাদা করে দেখাবে, আর aria-live status ফলাফল জানাবে। JavaScript প্রথমে native validity-কে সম্মান করবে; invalid হলে browser-এর reportValidity() চালিয়ে প্রথম ভুল field-এ মনোযোগ দেবে। সব ঠিক থাকলে কোনো network call নয়, কেবল demonstration message দেখাবে। এই progressive নকশায় HTML constraints (required, email ও minlength) native validation-এর নিয়ম হিসেবে থাকে। তবে এই local-only demo-তে submit button JavaScript চালু না হওয়া পর্যন্ত disabled থাকে; তাই JavaScript বন্ধ থাকলে কোনো submission বা success message হয় না, এবং কোনো বার্তাও পাঠানো হয় না।

প্রথম সিদ্ধান্ত: form-এর semantic চুক্তি

<form> element ব্যবহারকারীর interactive controls-এর একটি document section। বাস্তব form-এ action ও method দিয়ে endpoint ও HTTP আচরণ নির্ধারিত হয়। এই শিক্ষামূলক demo-তে method="dialog" রাখা হয়েছে, কিন্তু form-টির কোনো <dialog> ancestor নেই; তাই এটি dialog close করার form নয় এবং browser-এর কোনো form network submissionও হবে না। JavaScript listener validation ও demo status চালায়, কিন্তু no-network নিশ্চয়তার একমাত্র ভিত্তি preventDefault() নয়। ভবিষ্যতে backend যোগ করার সময় এই demo-র method, message ও privacy notice নতুন করে লিখতে হবে।

প্রতিটি label-এর for value তার input-এর id-এর সঙ্গে মেলে। এতে label-এ click করলে field focus হয় এবং screen reader relationship বুঝতে পারে। name attribute বাদ দিইনি: আজ request না গেলেও বাস্তব backend-এ কোন key পাঠানো হবে সেটি name নির্ধারণ করে। Name, email ও message-এ autocomplete-এর অর্থপূর্ণ মান দিয়েছি; subject-এর জন্য off বা custom value ব্যবহারের বদলে browser-কে অপ্রয়োজনীয় autofill না করতে বলেছি। aria-describedby field-কে ছোট hint এবং error-এর সঙ্গে যুক্ত করবে, যদিও error element শুরুতে hidden।

দেখুন MDN-এর form element reference। সেখানে action, method, enctype, novalidate এবং form-এর native আচরণ সম্পর্কে browser-সম্মত ব্যাখ্যা আছে। এই article-এ novalidate ব্যবহার করা হয়নি, কারণ native constraint validation-ই আমাদের প্রথম প্রতিরক্ষা।

Field বাছাই এবং constraint-এর যুক্তি

নামের ক্ষেত্রে minlength="2" দিয়েছি—এক অক্ষরের নাম সবসময় ভুল নয়, কিন্তু এই sample-এর product rule হিসেবে দুই অক্ষর চেয়েছি। Email input-এ type="email" browser-কে email syntax যাচাই করতে সাহায্য করে, আর maxlength অস্বাভাবিক দীর্ঘ input কমায়। Subject-এ required এবং সীমিত maxlength; বার্তার textarea-তে minlength="20" রেখেছি যাতে “হাই” ধরনের অস্পষ্ট request না যায়। এটি কোনো universal truth নয়—বাস্তব product-এর ভাষা, ব্যবহারকারী এবং business rule অনুযায়ী সীমা বদলাবেন।

required শুধু UI সাজানোর চিহ্ন নয়; browser validity state-এ valueMissing সেট করে। type=email ভুল syntax হলে typeMismatch তৈরি করে। minlength ও maxlength client-side feedback উন্নত করে, কিন্তু malicious বা hand-crafted HTTP request আটকায় না। একজন ব্যবহারকারী DevTools দিয়ে HTML বদলাতে পারেন, কিংবা form বাদ দিয়ে সরাসরি request পাঠাতে পারেন। সেই কারণে client constraint-কে সুবিধা হিসেবে দেখুন, security boundary হিসেবে নয়।

Error-এর জন্য আমি প্রতিটি field-এর নিচে একটি <p> রেখেছি। JavaScript error string লিখবে এবং hidden খুলবে; aria-describedby আগে থেকেই সেই node-কে সম্পর্কিত করে। role="alert" সব error-এ দিলে typing-এর সময় অতিরিক্ত interruption হতে পারে, তাই field error-কে polite live region এবং আলাদা global status-কে role="status" রাখা হয়েছে। Submit ব্যর্থ হলে browser-এর native popup এবং দৃশ্যমান error—দুটির মধ্যে বিরোধ না তৈরি করতে প্রথমে reportValidity() ব্যবহার করেছি, তারপর custom message কেবল প্রয়োজনীয় ক্ষেত্রে আপডেট করেছি।

CSS: focus এবং error-কে শুধু রঙে আটকে না রাখা

ফর্মের visual hierarchy ইচ্ছাকৃতভাবে ছোট: card, label, input, hint, error, action। এখানে কোনো generic responsive design tutorial নেই; CSS-এর কেন্দ্র field state। :focus-visible কেবল keyboard বা modality-তে দরকার হলে outline দেখায়, তাই mouse user-এর অপ্রত্যাশিত ring-এর বদলে keyboard user স্পষ্ট indication পান। Outline সরিয়ে ফেললে তা অবশ্যই নিজস্ব, দৃশ্যমান alternative দিয়ে পূরণ করতে হবে—এখানে outline বজায় রেখেছি।

:user-invalid সব browser-এ একইভাবে পুরোনো নয়, তাই demo-তে JavaScript-এর .has-error class-এর সঙ্গে :focus এবং :required ব্যবহার করেছি। Error field-এ border color বদলেছে, কিন্তু পাশে text message এবং icon-এর বদলে “সমস্যা” শব্দও আছে—এতে color-only dependency কমে। High-contrast mode বা forced-colors-এ user-agent-এর system color সম্মান করতে @media (forced-colors: active)-এ CanvasText ও Highlight ব্যবহার করেছি। Reduced-motion preference-এ animation নেই; কারণ validation message-এর জন্য animation কোনো দরকারি তথ্য যোগ করে না।

Progressive JavaScript flow

Script-এর flow চার ধাপে পড়ুন। প্রথমে form ও field references নেওয়া হয়। দ্বিতীয়ত, showFieldError() value, validity এবং custom message দেখে text বসায়। তৃতীয়ত, input event-এ user আবার লেখা শুরু করলে stale error সরানো হয়; এতে আগের ভুল বার্তা আটকে থাকে না। চতুর্থত, submit handler form.checkValidity() দিয়ে সামগ্রিক ফল পায়। false হলে form.reportValidity() browser-কে native message দেখাতে দেয়, তারপর প্রথম invalid element-এ focus() করা হয়। এই call-গুলো Constraint Validation API-এর অংশ; বিস্তারিত MDN Constraint validation guide পড়ুন।

সব field valid হলে handler event.preventDefault()-এর পরও কোনো fetch, XMLHttpRequest, form submit বা storage API কল করে না। status.textContent-এ লেখা হয়: “Demo success: validation passed, but message NOT sent.” এই বাক্যটি ইচ্ছাকৃতভাবে success শব্দ এবং non-delivery দুটোই বলে। Form reset না করায় learner চাইলে input দেখে DOM inspect করতে পারেন; reset করলে value হারানোর ঝুঁকি থাকে। বাস্তব app-এ server response আসা পর্যন্ত button disabled, idempotency এবং retry policy লাগতে পারে—এই demo সেগুলোর ভান করে না।

Custom validity কখন ব্যবহার করবেন? দুই field-এর সম্পর্ক যাচাই করতে setCustomValidity() ভালো উপায়, যেমন confirm email বা date range। কিন্তু এই sample-এ প্রতিটি field-এর rule native attribute-এই যথেষ্ট, তাই কৃত্রিম custom validity বসাইনি। এতে একটি গুরুত্বপূর্ণ শিক্ষা থাকে: JavaScript দিয়ে browser-এর built-in constraint আবার কপি না করে, native rule-কে feedback layer দিয়ে সমর্থন করুন। একই সঙ্গে validation message localization, browser-specific wording এবং accessible explanation-এর ভারসাম্য রাখুন।

সম্পূর্ণ standalone index.html

নিচের একটিমাত্র file save করে সরাসরি browser-এ খুলুন। কোনো package, build step বা external JavaScript দরকার নেই। Internet ছাড়াও demo চলবে, কারণ CSS ও script inline। method="dialog" এখানে কেবল demo-র জন্য; কোনো <dialog> ancestor না থাকায় form কোনো network submission করবে না। JavaScript চালু হলে তবেই demo button সক্রিয় হয়।

<!doctype html>
<html lang="bn">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Accessible Contact Form Demo</title>
  <style>
    :root { color-scheme: light; font-family: system-ui, sans-serif; line-height: 1.5; }
    * { box-sizing: border-box; }
    body { margin: 0; background: #eef2ff; color: #172033; }
    main { width: min(100% - 2rem, 42rem); margin: 4rem auto; }
    .card { background: #fff; padding: clamp(1.25rem, 4vw, 2.5rem); border: 1px solid #cbd5e1; border-radius: 1rem; box-shadow: 0 1rem 2rem #17203318; }
    h1 { margin-top: 0; }
    .notice { padding: .8rem 1rem; border-left: .3rem solid #7c3aed; background: #f5f3ff; }
    .field { margin-block: 1.25rem; }
    label { display: block; font-weight: 700; margin-bottom: .35rem; }
    input, textarea { width: 100%; border: 2px solid #94a3b8; border-radius: .5rem; padding: .7rem .8rem; font: inherit; color: inherit; background: #fff; }
    textarea { min-height: 9rem; resize: vertical; }
    input:focus-visible, textarea:focus-visible, button:focus-visible { outline: 3px solid #f59e0b; outline-offset: 3px; }
    input:invalid:not(:placeholder-shown), textarea:invalid:not(:placeholder-shown), .has-error { border-color: #b42318; }
    .hint, .error { font-size: .9rem; margin: .35rem 0 0; }
    .hint { color: #475569; }
    .error { color: #b42318; font-weight: 650; }
    button { border: 0; border-radius: .5rem; padding: .75rem 1.1rem; font: inherit; font-weight: 700; cursor: pointer; background: #3730a3; color: #fff; }
    button:hover { background: #312e81; }
    #status { min-height: 1.6rem; margin-top: 1rem; font-weight: 700; }
    .success { color: #166534; }
    @media (forced-colors: active) { input, textarea { border: 2px solid CanvasText; } input:focus-visible, textarea:focus-visible, button:focus-visible { outline-color: Highlight; } }
  </style>
</head>
<body>
  <main>
    <section class="card" aria-labelledby="form-title">
      <h1 id="form-title">যোগাযোগের ডেমো</h1>
      <p class="notice">এটি শেখার জন্য front-end demo। Submit করলে কোনো বার্তা পাঠানো হবে না।</p>
      <form id="contact-form" method="dialog">
        <div class="field">
          <label for="name">নাম <span aria-hidden="true">*</span></label>
          <input id="name" name="name" type="text" autocomplete="name" minlength="2" maxlength="80" required aria-describedby="name-hint name-error">
          <p id="name-hint" class="hint">কমপক্ষে ২ অক্ষর লিখুন।</p>
          <p id="name-error" class="error" hidden></p>
        </div>
        <div class="field">
          <label for="email">ইমেইল <span aria-hidden="true">*</span></label>
          <input id="email" name="email" type="email" autocomplete="email" maxlength="254" required aria-describedby="email-hint email-error">
          <p id="email-hint" class="hint">উত্তরের জন্য একটি বৈধ email দিন।</p>
          <p id="email-error" class="error" hidden></p>
        </div>
        <div class="field">
          <label for="subject">বিষয় <span aria-hidden="true">*</span></label>
          <input id="subject" name="subject" type="text" maxlength="120" required aria-describedby="subject-hint subject-error">
          <p id="subject-hint" class="hint">আপনার প্রশ্নের সংক্ষিপ্ত শিরোনাম।</p>
          <p id="subject-error" class="error" hidden></p>
        </div>
        <div class="field">
          <label for="message">বার্তা <span aria-hidden="true">*</span></label>
          <textarea id="message" name="message" minlength="20" maxlength="2000" required aria-describedby="message-hint message-error"></textarea>
          <p id="message-hint" class="hint">কমপক্ষে ২০ অক্ষরে সমস্যাটি লিখুন।</p>
          <p id="message-error" class="error" hidden></p>
        </div>
        <button id="submit-button" type="submit" disabled>ডেমো যাচাই করুন</button>
        <p id="status" role="status" aria-live="polite"></p>
      </form>
    </section>
  </main>
  <script>
    const form = document.querySelector('#contact-form');
    const fields = [...form.querySelectorAll('input, textarea')];
    const status = document.querySelector('#status');
    const submitButton = document.querySelector('#submit-button');

    function messageFor(field) {
      if (field.validity.valueMissing) return 'এই ঘরটি পূরণ করুন।';
      if (field.validity.typeMismatch) return 'একটি বৈধ email format দিন।';
      if (field.validity.tooShort) return `কমপক্ষে ${field.minLength} অক্ষর লিখুন।`;
      if (field.validity.tooLong) return `সর্বোচ্চ ${field.maxLength} অক্ষর রাখা যাবে।`;
      return '';
    }

    function showFieldError(field) {
      const error = document.querySelector(`#${field.id}-error`);
      const text = messageFor(field);
      error.textContent = text;
      error.hidden = !text;
      field.classList.toggle('has-error', Boolean(text));
      field.setAttribute('aria-invalid', text ? 'true' : 'false');
      return !text;
    }

    fields.forEach((field) => {
      field.addEventListener('input', () => {
        showFieldError(field);
        if (fields.every((item) => item.validity.valid)) status.textContent = '';
      });
    });

    form.addEventListener('submit', (event) => {
      event.preventDefault(); // Demo: deliberately prevents any network submission.
      status.className = '';
      const valid = form.checkValidity();
      fields.forEach(showFieldError);
      if (!valid) {
        form.reportValidity();
        const firstInvalid = fields.find((field) => !field.validity.valid);
        firstInvalid?.focus();
        status.textContent = 'কিছু ঘর ঠিক করুন, তারপর আবার চেষ্টা করুন।';
        return;
      }
      status.className = 'success';
      status.textContent = 'Demo success: validation passed, but message NOT sent.';
    });

    // JavaScript is required for this local-only demonstration button.
    submitButton.disabled = false;
  </script>
</body>
</html>

কোড পড়ার সময় যে ছোট সিদ্ধান্তগুলো খেয়াল করবেন

aria-invalid="false" শুরুতেই লেখা নেই; user প্রথম submit বা input করার পর script সেট করে। এতে untouched field-এ শুরুতেই error state ঘোষণা হয় না। Error paragraph-এর hidden attribute screen reader এবং visual user—দুজনের জন্যই শুরুতে content সরিয়ে রাখে। Text বদলানোর পর aria-describedby-এর সম্পর্ক একই থাকে, তাই error প্রকাশিত হলে assistive technology সেটি পড়তে পারে। role="status" polite হওয়ায় typing-এর মাঝখানে জরুরি alert-এর মতো interrupt করবে না। Submit-এর পরে browser native bubble দেখালেও আমাদের status-এ সংক্ষিপ্ত নির্দেশ থাকে, ফলে keyboard user বুঝতে পারেন যে কী করবেন।

input listener-এ আমরা custom regular expression দিয়ে email বানাইনি। Email format-এর জন্য browser-এর type=email যথেষ্ট প্রাথমিক rule; messageFor()-এর typeMismatch message কেবল বাংলা feedback। Browser-এর validity property-কে source of truth রাখায় rule এবং message আলাদা হয়ে অসঙ্গত হওয়ার সম্ভাবনা কম। maxlength user input-এ browser সাধারণত সীমা মানে, কিন্তু server-এ একই সীমা আবার enforce করতে হবে। কোনো field-এ whitespace-only policy দরকার হলে backend-এ trim ও business validation করুন; এই demo সেই policy গোপনে ধরে নেয় না।

Validation test cases: ইচ্ছাকৃতভাবে ভাঙুন

প্রথম test-এ সব ঘর খালি রেখে button চাপুন। Browser প্রথম required field দেখাবে, script সব error paragraph প্রকাশ করবে এবং status বলবে কিছু ঘর ঠিক করতে। এরপর name-এ এক অক্ষর দিন; tooShort message দেখা উচিত। দুই বা তার বেশি অক্ষর দিলে সেই error অদৃশ্য হবে। এই sequence-টি নিশ্চিত করে যে invalid state আটকে নেই এবং user input-এ feedback আপডেট হচ্ছে।

দ্বিতীয় test-এ email-এ hello লিখুন। Browser typeMismatch জানাবে এবং বাংলা message “বৈধ email format” দেখাবে। [email protected] দিলে email error সরে যাওয়ার কথা। তৃতীয় test-এ subject ফাঁকা রাখুন, message-এ ১৯টি অক্ষর দিন; message-এর minimum constraint আলাদা করে কাজ করবে। অনেক বড় text paste করে maxlength-এর আচরণও দেখুন।

চতুর্থ test হল keyboard-only: mouse না নিয়ে Tab দিয়ে label-এর পর field-এ যান, Enter/Space-এ submit করুন। কমলা focus-visible outline দেখা উচিত এবং invalid হলে প্রথম ভুল field focus পাওয়া উচিত। পঞ্চম test-এ browser DevTools থেকে JavaScript নিষ্ক্রিয় করে page reload করুন। Script-এর বাংলা custom error ও demo success থাকবে না, কিন্তু required, email, minlength-এর native validation চলবে। এই fallback-এ browser-এর native constraints দেখা যায়, কিন্তু demo button ইচ্ছাকৃতভাবে disabled থাকায় JavaScript ছাড়া submission শুরু হয় না; ফলে network-এ কিছু পাঠানোর দাবিও নেই।

ষষ্ঠ test-এ screen reader বা browser accessibility tree দিয়ে status ও error পড়ে দেখুন। Error text কেবল color নয় এবং label/hint/error সম্পর্কিত কিনা যাচাই করুন। সপ্তম test-এ forced-colors mode এবং zoom 200% চালু করুন; content কাটা বা focus হারানো উচিত নয়। সব test সফল হলেও এটি security test নয়—network, authorization, abuse prevention ও data retention আলাদা যাচাই।

Production-এ গেলে server validation অপরিহার্য

এই page-এ client-side validation user experience-এর জন্য, বিশ্বাসের জন্য নয়। Production endpoint-এ server অবশ্যই request body parse করে নাম, email, subject ও message-এর type, length, encoding এবং business rule যাচাই করবে। Unknown fields বাদ দিন, canonicalize করার সময় data নষ্ট না করে নীতিমালা লিখুন, এবং error response-এ sensitive details ফাঁস করবেন না। Server-side validation client rule-এর সঙ্গে সামঞ্জস্যপূর্ণ হতে পারে, কিন্তু client code কপি করে নিরাপত্তা সম্পন্ন হয়েছে ভাবা যাবে না।

বাস্তব POST form-এ CSRF প্রতিরোধ আলাদা বিষয়। Cookie-based session থাকলে server-side CSRF token তৈরি করে form-এ যুক্ত করুন এবং server-এ token মিলিয়ে দেখুন; SameSite cookie, Origin/Referer যাচাই এবং framework-এর vetted CSRF middleware সহায়ক প্রতিরক্ষা। এই demo-তে token নেই, কারণ backend নেই—তাই এটিকে authenticated production form হিসেবে ব্যবহার করবেন না। এই demo-র method="dialog" কোনো CSRF protection নয়; বাস্তব endpoint যোগ করলে action, method, CSRF ও privacy policy নতুন করে নির্ধারণ করতে হবে।

Contact form সাধারণত spam target। Rate limit, IP বা account ভিত্তিক quota, exponential backoff, captcha/turnstile-এর মতো risk-based challenge এবং abuse monitoring দরকার হতে পারে। Rate limit server বা edge-এ প্রয়োগ করুন; JavaScript-এ button একবার disable করলেই attacker থামে না। Message email-এ forward করলে header injection, HTML escaping, attachment policy এবং outbound provider-এর failure handling ভাবুন। সফল response তখনই বলবেন যখন server সত্যিই গ্রহণ করেছে; এই demo-র “NOT sent” ভাষা সেই distinction শেখায়।

Privacy, retention এবং error আচরণ

Form-এ email ও message ব্যক্তিগত তথ্য হতে পারে। Production-এ কেন তথ্য নিচ্ছেন, কতদিন রাখবেন, কে দেখবে, delete/access request কীভাবে হবে—সংক্ষিপ্ত privacy notice-এ বলুন। Consent checkbox দরকার হলে তা optional marketing consent-এর সঙ্গে বাধ্যতামূলক contact request মেশাবেন না। TLS ছাড়া sensitive form পাঠাবেন না; logs-এ সম্পূর্ণ message বা email না রাখাই ভালো, আর analytics tool যেন field value capture না করে তা যাচাই করুন।

Error response-এ “email already exists” বা account enumeration-এর মতো তথ্য প্রকাশের আগে threat model করুন। Accessibility-এর জন্য error message স্পষ্ট, সংক্ষিপ্ত এবং করণীয়মুখী রাখুন; “invalid” বলার বদলে “একটি বৈধ email format দিন” ভালো। Server 400, 429 বা 500 দিলে UI আলাদা state দেখাবে—network failure-কে validation error বলবে না। Retry-এর আগে user-এর entered value অক্ষুণ্ণ রাখুন, তবে shared/public device-এ sensitive data ধরে রাখার trade-off ব্যাখ্যা করুন।

Demo থেকে বাস্তব integration-এর checklist

  1. action-এ HTTPS endpoint দিন এবং method="post" রাখুন; GET-এ message পাঠাবেন না। ২. Server-side schema validation, CSRF token, authentication/authorization এবং rate limit যোগ করুন। ৩. Success message server-এর authoritative response থেকে বানান, front-end অনুমান থেকে নয়। ৪. Error payload-এ field-level safe messages দিন এবং unknown exception user-কে দেখাবেন না। ৫. Privacy notice, retention deletion এবং log redaction লিখিত policy-তে আনুন। ৬. Keyboard, screen reader, zoom, forced-colors, slow network এবং JavaScript-off test চালান। ৭. fetch ব্যবহার করলে timeout, abort, retry policy ও duplicate submission সামলান—এই file-এ সেগুলো ইচ্ছাকৃতভাবে নেই।

শেষ কথা: একটি ভালো form-এর মূল্য submit button-এর gradient-এ নয়; user কী চাইছে বুঝতে পারছেন কিনা, ভুল হলে কীভাবে ফেরত আসবেন, keyboard-এ সব reachable কিনা, এবং data কোথায় যাচ্ছে তা সত্যি বলা হচ্ছে কিনা—এসবের সমষ্টিতে। এই standalone demo native HTML দিয়ে শুরু করে CSS focus feedback ও JavaScript status যোগ করেছে, কিন্তু কোনো fake backend বা misleading success বানায়নি। সেই সীমা বজায় রেখেই পরের ধাপে নিজের server contract যোগ করুন।

রেফারেন্স

মোবাইলবান্ধব ওয়েবসাইট বানাবেন কীভাবে: Responsive Design ও Accessibility গাইড

সবার জন্য ওয়েবসাইট—ল্যাপটপ, ট্যাবলেট ও ফোনে নমনীয় নকশা

মোবাইলে ওয়েবসাইট খোলা এখন স্বাভাবিক অভ্যাস। তবু অনেক সাইটে লেখা এত ছোট, মেনু এত সরু, ছবি এত ভারী বা ফর্ম এত বিভ্রান্তিকর যে পাঠক কয়েক সেকেন্ডেই ফিরে যান। মোবাইলবান্ধব সাইট মানে শুধু ডেস্কটপ পেজকে ছোট করে দেখানো নয়। এর অর্থ হলো, যে পর্দা, ব্রাউজার, জুম, ইনপুট পদ্ধতি বা সহায়ক প্রযুক্তিই ব্যবহার করা হোক, মানুষ যেন তথ্য পড়তে এবং কাজ করতে পারে। এই গাইডে ছোট ব্যবসা, ব্যক্তিগত ব্লগ বা সংস্থার ওয়েবসাইটের মালিকদের জন্য Responsive Design এবং Accessibility-এর বাস্তব পদ্ধতি দেওয়া হলো। লক্ষ্য হলো পরিষ্কার, নমনীয়, দ্রুত বোঝা যায় এমন অভিজ্ঞতা; কোনো নির্দিষ্ট আইনি সম্মতি বা সার্চ র‌্যাঙ্কিংয়ের নিশ্চয়তা নয়।

Responsive Design আসলে কী

MDN-এর Responsive Design গাইড মনে করিয়ে দেয়, HTML স্বভাবতই কিছুটা তরল: পেজের আকার বদলালে লেখা নতুন প্রস্থে ভেঙে যায়। সমস্যা শুরু হয় যখন আমরা নির্দিষ্ট প্রস্থের বাক্স, অতি লম্বা লাইন বা এমন ছবি বসাই যা পাত্রের বাইরে বেরিয়ে যায়। Responsive Design হলো এমন নকশা-পদ্ধতি, যেখানে লেআউট উপলব্ধ জায়গা, ডিভাইস ও ব্যবহারকারীর সেটিং অনুযায়ী মানিয়ে নেয়। এটি আলাদা কোনো একক প্রযুক্তি নয়; নমনীয় গ্রিড, তরল মিডিয়া, আপেক্ষিক মাপ এবং প্রয়োজনমতো media query মিলিয়ে তৈরি একটি অভ্যাস।

একটি গুরুত্বপূর্ণ নীতি হলো, ডিভাইসের মডেল ধরে নকশা না করা। “এই ফোনের জন্য ৩৭৫ পিক্সেল” বা “এই ল্যাপটপের জন্য ১৩৬৬ পিক্সেল”—এমন অনুমান দ্রুত পুরোনো হয়। ব্রাউজার উইন্ডো সরু হতে পারে, কেউ ২০০ বা ৪০০ শতাংশ জুম করতে পারেন, আবার বড় অক্ষর ব্যবহারের জন্য মোবাইলের accessibility setting চালু থাকতে পারে। কনটেন্ট কোথায় অসুবিধায় পড়ছে, সেই জায়গায় breakpoint দিন; জনপ্রিয় স্ক্রিন-সাইজের তালিকা মুখস্থ করে নয়।

Mobile-first দিয়ে শুরু করুন

প্রথমে একটি সরু পর্দায় মূল কাজটি সহজ করুন। লোগো, শিরোনাম, পরিচয়, প্রধান বোতাম ও প্রয়োজনীয় নেভিগেশন রাখুন; পাশের তথ্য নিচে নামিয়ে দিন। এক কলামের প্রাথমিক CSS-কে ভিত্তি ধরে চওড়া জায়গায় media query দিয়ে দুই বা তিন কলাম যোগ করা যায়। MDN-ও সরু ডিভাইসে single-column দিয়ে শুরু করে পর্যাপ্ত জায়গা পাওয়া গেলে বহু-কলাম করার এই mobile-first পদ্ধতির কথা বলে। এতে ছোট পর্দায় অপ্রয়োজনীয় জিনিস লুকিয়ে রেখে মূল তথ্য হারিয়ে ফেলার ঝুঁকি কমে।

@media (min-width: 48rem)-এর মতো আপেক্ষিক একক ব্যবহার করুন। px একেবারে নিষিদ্ধ নয়, কিন্তু সবকিছু কঠিন pixel width করলে জুম ও বড় ফন্টের সময় লেআউট ভেঙে যেতে পারে। max-width: 70rem; margin-inline: auto; padding-inline: 1rem; ধরনের container বড় স্ক্রিনে লাইনের দৈর্ঘ্য নিয়ন্ত্রণ করে। Flexbox ও CSS Grid সাধারণত নমনীয়; সন্তানদের flex: 1 বা grid-এর fr একক জায়গা ভাগ করতে সাহায্য করে। কোনো কার্ডে দীর্ঘ বাংলা শিরোনাম এলে তা কেটে ফেলার বদলে পরের লাইনে যেতে দিন।

Viewport, reflow এবং horizontal scroll

HTML-এ viewport meta tag রাখুন: <meta name="viewport" content="width=device-width, initial-scale=1">। এটি মোবাইল ব্রাউজারকে পেজের CSS প্রস্থ ডিভাইসের সঙ্গে মিলিয়ে নিতে সাহায্য করে। কিন্তু zoom বন্ধ করতে user-scalable=no বা অতিরিক্ত কঠিন maximum-scale ব্যবহার করবেন না; যাঁদের বড় লেখা দরকার তাঁদের নিয়ন্ত্রণ থাকা উচিত।

W3C-এর Reflow নির্দেশনা অনুযায়ী, সাধারণ কনটেন্টকে ৩২০ CSS পিক্সেল প্রস্থের সমতুল্য অবস্থায় তথ্য বা কাজ হারানো ছাড়াই এক দিকের স্ক্রলে পড়া সম্ভব হওয়া উচিত। এর মানে প্রতিটি টেবিল বা মানচিত্রকে জোর করে ভাঙতে হবে না; অর্থপূর্ণভাবে দুই-মাত্রিক থাকা ডেটা টেবিল, মানচিত্র, গেম বা বড় ডায়াগ্রামের ব্যতিক্রম থাকতে পারে। তবে টেবিলের চারপাশে স্ক্রল-ইঙ্গিত, ছোট পর্দায় বিকল্প সারাংশ বা স্তূপীকৃত তথ্য দিলে বোঝা সহজ হয়। ফিক্সড header, বিজ্ঞাপন বা floating chat যেন জুম করা লেখা ও keyboard focus ঢেকে না দেয়।

বাংলা পাঠযোগ্যতা আগে

বাংলা লেখার জন্য এমন font বাছুন যার যুক্তাক্ষর, কারচিহ্ন ও মাত্রা পরিষ্কার। ওয়েবফন্ট ব্যবহার করলে font-display: swap দিন, যাতে ফন্ট আসা পর্যন্ত অদৃশ্য লেখা না থাকে। একটি বাংলা font-এর সঙ্গে fallback হিসেবে sans-serif বা আপনার পরীক্ষিত বাংলা fallback লিখুন। শুধু ইংরেজি অক্ষরে সুন্দর দেখায় বলে font বাছবেন না; দীর্ঘ বাংলা অনুচ্ছেদ, শিরোনাম, সংখ্যা, বিরামচিহ্ন এবং bold অবস্থায় দেখে নিন।

মূল লেখায় পর্যাপ্ত line-height রাখুন—সাধারণভাবে 1.6 থেকে শুরু করে বাস্তব ফোনে পরীক্ষা করা যায়। অতি সরু column-এ এক লাইনে দুটি শব্দ রেখে পড়া কঠিন করবেন না, আবার বড় পর্দায় পুরো স্ক্রিনজুড়ে লম্বা লাইনও রাখবেন না। অনুচ্ছেদ ছোট রাখুন, একটি অনুচ্ছেদে একটি ভাব বলুন, এবং হালকা ধূসর লেখায় contrast নষ্ট করবেন না। ব্যবহারকারী browser zoom করলে লেখা বড় হবে, নতুন লাইনে reflow হবে এবং কোনো বাক্য কাটা যাবে না।

Semantic HTML ও heading-এর সিঁড়ি

সাজসজ্জার জন্য শুধু div ব্যবহার না করে অর্থপূর্ণ HTML নিন: header, nav, main, article, section, footer, button এবং a। একটি পেজে পরিষ্কার প্রধান h1 রাখুন, তারপর বিষয়ভিত্তিক h2, তার ভেতরে দরকার হলে h3। শুধু বড় দেখানোর জন্য heading বাদ দিয়ে bold paragraph করবেন না। স্ক্রিন রিডার ব্যবহারকারী heading list শুনে পেজে দ্রুত চলেন; তাই heading-এর লেখা সংক্ষিপ্ত কিন্তু অর্থবহ হওয়া দরকার। “আরও জানুন” পাঁচ জায়গায় না লিখে “ডেলিভারি নীতি পড়ুন” লিখুন।

মেনু খোলার বোতাম সত্যিকারের button হোক, ক্লিকযোগ্য div নয়। বোতামে কাজের নাম এবং খোলা বা বন্ধের অবস্থা programmatically বোঝা যায় এমনভাবে দিন। লিঙ্কের নতুন ট্যাব খোলা হলে আগে জানানো ভালো। tabindex দিয়ে স্বাভাবিক keyboard ক্রম বদলানোর বদলে DOM-এর ক্রম ঠিক করুন। W3C WAI tutorials ডেভেলপার, ডিজাইনার ও content author—সবার জন্য ছবি, টেবিল, ফর্মসহ সাধারণ কাজের accessibility পদ্ধতি দেখায়।

Keyboard, focus ও স্পর্শ

মাউস বা touch না ব্যবহার করে Tab, Shift+Tab, Enter, Space এবং arrow key দিয়ে কাজটি করুন। WCAG keyboard নির্দেশনা বলে, নির্দিষ্ট সময়ের চাপ ছাড়া সব কার্যকারিতার keyboard সমতুল্য থাকা দরকার। custom dropdown, carousel, modal, accordion বা search box-এ শুধু click event লিখে থেমে যাবেন না। Escape-এ modal বন্ধ করা, focus কোথায় ফিরবে এবং tab ক্রম কেমন হবে—এসব নির্ধারণ করুন।

Focus outline সরিয়ে ফেলবেন না। বরং :focus-visible-এ স্পষ্ট দুই রঙের outline দিন, যা পটভূমি থেকে আলাদা এবং নিজেই যথেষ্ট দৃশ্যমান। sticky header যেন focus করা লিঙ্ক ঢেকে না দেয়; প্রয়োজন হলে scroll-margin-top ব্যবহার করুন। touch target খুব ছোট হলে ভুল চাপ বাড়ে, তাই বোতামে পর্যাপ্ত padding ও ফাঁক রাখুন। ভিন্ন আঙুলের আকার, zoom এবং landscape অবস্থায় পরীক্ষা করুন।

ফর্ম, label ও error message

প্রতিটি input-এর পাশে দৃশ্যমান label রাখুন এবং for-এর মান input-এর id-এর সঙ্গে মিলান। placeholder-কে label-এর বিকল্প বানাবেন না; ব্যবহারকারী লিখতে শুরু করলে placeholder হারিয়ে যায়। প্রয়োজনীয় ঘর হলে “আবশ্যক” লিখুন, কেবল লাল তারকা দিয়ে নির্ভর করবেন না। ফোন, ইমেইল, ঠিকানা বা পাসওয়ার্ডের জন্য স্পষ্ট নির্দেশনা দিন এবং ভুলের উদাহরণ দেখান।

Submit-এর পরে শুধু “ভুল হয়েছে” লিখবেন না। কোন ঘরে কী ভুল এবং কীভাবে ঠিক করতে হবে, তা text-এ জানান; error summary থাকলে প্রতিটি বার্তার সঙ্গে ঘরে লিঙ্ক দিন। server-side validation রাখুন, কারণ JavaScript ব্যর্থ হলেও মানুষকে কাজ শেষ করতে হবে। সফল ফলাফল এবং loading অবস্থাও বোঝান। keyboard focus এমন জায়গায় আনুন যাতে ব্যবহারকারী ফলাফল বা প্রথম ভুল ঘরটি পান, কিন্তু তাঁর লেখা হারাবেন না।

ছবির alt এবং decorative image

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

শুধু সাজসজ্জার রেখা, texture বা একই তথ্য পুনরাবৃত্তি করা ছবিতে alt="" ব্যবহার করুন, যাতে screen reader অপ্রয়োজনীয় ঘোষণা না করে। CSS background-এ রাখা decoration-এ সাধারণত alt লাগে না, কিন্তু সেখানে তথ্য লুকিয়ে রাখবেন না। WAI Images Tutorial সহ WAI-এর tutorial-গুলো ছবিকে context অনুযায়ী meaningful, functional বা decorative হিসেবে লেখার পদ্ধতি ব্যাখ্যা করে।

Responsive images ও ভিডিও

ছবিকে container-এর বাইরে যেতে দেবেন না: img, picture, video { max-width: 100%; height: auto; }। কিন্তু শুধু বড় ছবিকে ছোট করে দেখালে মোবাইল অযথা বেশি ডেটা ডাউনলোড করে। MDN Responsive Images অনুযায়ী srcset এবং sizes দিয়ে একই ছবির বিভিন্ন প্রস্থ দিন, যাতে ব্রাউজার viewport, pixel density, zoom ও নেটওয়ার্ক বিবেচনা করে উপযুক্ত ফাইল নেয়। picture ব্যবহার করে সরু পর্দায় আলাদা crop বা portrait art direction দেওয়া যায়; শেষ fallback হিসেবে অর্থপূর্ণ img ও alt রাখুন।

ছবির intrinsic width-height জানালে layout shift কমে। WebP বা AVIF ব্যবহার করতে পারেন, তবে fallback, compression ও বাস্তব ফোনে মান দেখুন। lazy loading-এর আগে প্রথম viewport-এর প্রয়োজনীয় ছবি দেরি করাবেন না। বড় infographic-এর পাঠ্য শুধু ছবিতে আটকে রাখবেন না; HTML summary বা downloadable data দিন। ভিডিওতে প্লে-নিয়ন্ত্রণ, transcript এবং প্রি-রেকর্ডেড কথোপকথন ও গুরুত্বপূর্ণ শব্দের synchronized captions দিন। W3C captions guidance captions-এ বক্তা, অর্থপূর্ণ sound effect ও প্রয়োজনীয় audio তথ্য রাখার কথা বলে।

রং ও contrast

রঙকে একমাত্র সংকেত বানাবেন না। “লাল ঘরটি ঠিক করুন” বললে color-vision deficiency থাকা ব্যক্তি আটকে যেতে পারেন; label, icon এবং text-ও দিন। স্বাভাবিক আকারের লেখা ও তার background-এর contrast ratio অন্তত 4.5:1, আর বড় লেখা হলে অন্তত 3:1 রাখার WCAG AA নির্দেশনা W3C-এর Contrast Minimum ব্যাখ্যায় আছে। এখানে বড় text-এর সংজ্ঞা font ও weight-এর ওপর নির্ভর করে; পাতলা বা অস্বাভাবিক font-কে বড় ধরে ছাড় নেবেন না। লোগো, pure decoration বা inactive control-এর ব্যতিক্রম আছে, কিন্তু সাধারণ body text-এর ক্ষেত্রে নয়।

Contrast checker দিয়ে text, link, placeholder, disabled-looking হলেও পড়তে হয় এমন লেখা, focus outline এবং ছবির ওপর বসানো heading পরীক্ষা করুন। hover-এ শুধু রং বদলালে keyboard focus ও স্পষ্ট underline রাখুন। dark mode যোগ করলে দুই theme-এই পরীক্ষা করুন। background image বদলালে text-এর পেছনে solid বা gradient layer দিন; যে ছবির ওপর লেখা বসাবেন তা সব crop-এ যথেষ্ট contrast রাখে কি না দেখুন। contrast পাস করলেই accessibility সম্পূর্ণ হয় না—font, spacing, ভাষা, hierarchy ও বাস্তব ব্যবহারও গুরুত্বপূর্ণ।

Motion, captions ও পড়ার নিয়ন্ত্রণ

Auto-playing carousel, parallax, bouncing banner ও scroll-এ হঠাৎ উড়ে আসা card মনোযোগ নষ্ট করতে পারে, কারও মাথা ঘুরতে পারে। অপ্রয়োজনীয় animation বাদ দিন; দরকার হলে Pause বা Motion off নিয়ন্ত্রণ দিন। prefers-reduced-motion সম্মান করুন:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

W3C-এর Animation from Interactions ব্যাখ্যা করে, preference বা control দিয়ে non-essential motion বন্ধ করা যায়; essential তথ্য বা কাজের animation-এর বিষয় আলাদা। কোনো সংবাদে স্বয়ংক্রিয়ভাবে moving ticker থাকলে Pause দিন, ফ্ল্যাশিং এড়িয়ে চলুন। ভিডিও autoplay হলে শব্দ বন্ধ ও দৃশ্যমান control রাখুন; audio-এর বিকল্প transcript এবং prerecorded synchronized captions দিন।

দ্রুত পরীক্ষা করার বাস্তব তালিকা

  1. ফোনে portrait ও landscape দুটিতে পেজ খুলুন। ২. browser zoom ২০০ শতাংশ করুন, তারপর আরও বড় text setting চালু করুন। ৩. ৩২০ CSS পিক্সেল-সমতুল্য সরু view-তে horizontal scroll আছে কি না দেখুন; ব্যতিক্রমী table বা map হলে তার ব্যবহার ব্যাখ্যা করুন। ৪. ইচ্ছা করে দীর্ঘ বাংলা শিরোনাম, ইংরেজি শব্দ, বড় সংখ্যা এবং error message বসান। ৫. কেবল keyboard দিয়ে Tab করে সব লিঙ্ক, menu, modal, form ও carousel ব্যবহার করুন; focus হারায় কি না দেখুন। ৬. ছবির alt সাময়িকভাবে পড়ে দেখুন, decorative ছবি skip হচ্ছে কি না যাচাই করুন। ৭. screen reader বা অন্তত accessibility tree দিয়ে heading, label, button name এবং error সম্পর্ক পরীক্ষা করুন। ৮. contrast tool-এ normal ও large text মাপুন। ৯. prefers-reduced-motion চালু করে animation বন্ধ হচ্ছে কি না দেখুন। ১০. ধীর মোবাইল নেটওয়ার্কে ছবি, font, ভিডিও ও layout shift পরীক্ষা করুন।

প্রকাশের পরও উন্নতি করুন

Accessibility একবারের checkbox নয়। নতুন theme, বিজ্ঞাপন, plugin, popup, form field বা campaign banner যোগ হলে আগের ভারসাম্য ভাঙতে পারে। একটি ছোট checklist version control-এ রাখুন এবং release-এর আগে কয়েকটি বাস্তব device, browser zoom ও keyboard pass করুন। যাঁরা আপনার সাইট ব্যবহার করেন তাঁদের মধ্যে keyboard, screen reader, low vision বা motor limitation থাকা মানুষ থাকলে তাঁদের অভিজ্ঞতা শুনুন; কিন্তু কাউকে নিজের ব্যক্তিগত তথ্য প্রকাশে চাপ দেবেন না।

পরিমাপের dashboard থাকলে কেবল bounce rate বা device ভাগ নয়, support message, failed form, search query এবং কোন জায়গায় মানুষ আটকে যায় তা দেখুন। Accessibility tool-এর automated report সহায়ক, চূড়ান্ত প্রমাণ নয়; automated test অনেক context, ভাষা এবং keyboard সমস্যা ধরতে পারে না। এই গাইডের কৌশলগুলো WCAG-এর কিছু সাফল্য-মানদণ্ড বোঝার ও বাস্তবায়নের সহায়তা, আইনি পরামর্শ বা compliance guarantee নয়। আপনার দেশ, খাত, চুক্তি ও ব্যবহারকারীর প্রয়োজন অনুযায়ী বিশেষজ্ঞ মূল্যায়ন লাগতে পারে।

সবশেষে, mobile-first মানে ছোট স্ক্রিনকে কম গুরুত্বপূর্ণ ভাবা নয়; এটি কনটেন্টের অগ্রাধিকার পরিষ্কার করার সুযোগ। নমনীয় container, reflow হওয়া বাংলা লেখা, দৃশ্যমান focus, অর্থপূর্ণ heading, label ও error, সঠিক alt, contrast, captions এবং reduced-motion preference—এই ছোট সিদ্ধান্তগুলো একসঙ্গে সাইটকে বেশি মানুষের জন্য ব্যবহারযোগ্য করে। ডিভাইসের নাম অনুমান না করে কনটেন্টের প্রয়োজন দেখুন, নিয়মিত পরীক্ষা করুন, এবং মানুষকে zoom, keyboard ও পছন্দের সাহায্য-প্রযুক্তি ব্যবহার করার স্বাধীনতা দিন।

তথ্যসূত্র

বিজ্ঞাপনের স্থানপোস্ট ১
বিজ্ঞাপনের স্থানপোস্ট ২
বিজ্ঞাপনের স্থানপোস্ট ৩
About Me
পরিচয়
নাম

নাজমুল ইসলাম

ভূমিকা

Tech Specialist

আরও পরিচিতি
শিক্ষা / পড়াশোনার বিষয়
কাজ / প্রযুক্তির ক্ষেত্র / দক্ষতা
Web Designer , Web Developer & Blog Content Writer.
শহর / জেলা
Natore , Rajshahi
শখ / আগ্রহ
Taste Something Different 😜 always.
ব্লগের বিষয়
পাবলিক ওয়েবসাইট / সোশ্যাল লিংক
শেষের পরিচিতি
নাজমুল ইসলাম · Tech Specialist

লেখার আর্কাইভ

মাস অনুযায়ী পুরোনো লেখাগুলো খুঁজে নিন।