توسعه فرانت‌اند

Accessibility در React: ساخت اپ‌های قابل‌دسترس

HTML معنایی، useId، Label، خطا و Status با پروژه کامل فرم محلی React؛ بدون ارسال ساختگی داده یا ادعای انطباق خودکار WCAG.

1404/12/01 3 دقیقه مطالعه 1,229 بازدید

یک فرم ممکن است با ماوس کار کند، اما کاربر کیبورد نتواند محل تمرکز را ببیند یا کاربر صفحه‌خوان نام ورودی را تشخیص ندهد. دسترس‌پذیری از همین جزئیات واقعی ساخته می‌شود: ساختار معنایی، نام کنترل، ترتیب تعامل، پیام وضعیت و امکان اصلاح خطا. React این اصول را حذف یا خودکار کامل نمی‌کند. خروجی برنامه در نهایت HTML و رفتار مرورگر است و باید برای شیوه‌های مختلف استفاده قابل فهم بماند.

شروع مناسب انتخاب یک مسیر واقعی است؛ مثلاً پرکردن و ارسال فرم. فقط افزودن چند ویژگی aria به عناصر عمومی کافی نیست. ابتدا HTML مناسب را انتخاب کنید، سپس در صورت نیاز وضعیت و رابطه را توضیح دهید. این مقاله نمونه آموزشی کوچک دارد و گواهی انطباق کامل با استاندارد ارائه نمی‌کند. دسترس‌پذیری محصول واقعی نیازمند بررسی متناسب با محتوا، تعامل و کاربران آن است.

از عنصر بومی مناسب شروع کنید

برای اقدام از button و برای رفتن به نشانی از link استفاده کنید. یک div با onClick همه رفتارهای کیبورد، نام و نقش دکمه را خودکار ندارد. بازسازی این قراردادها هزینه و احتمال خطا دارد. در فرم، label واقعی رابطه نام و ورودی را ایجاد می‌کند. Placeholder جای آن را نمی‌گیرد؛ با ورود متن ناپدید می‌شود و همیشه نام مناسبی برای فناوری کمکی نیست.

ساختار عنوان و بخش نیز مهم است. عنوان اصلی، بخش‌ها و ترتیب محتوا باید معنی داشته باشند. انتخاب h3 فقط به دلیل اندازه فونت، ساختار را از معنا جدا می‌کند. CSS می‌تواند ظاهر را تنظیم کند. راهنمای WAI درباره Label فرم مرجع رابطه نام و کنترل است. از چند نام متناقض برای یک ورودی خودداری کنید؛ کاربر باید همان نام روشن را در رابط و فناوری کمکی دریافت کند.

کیبورد و Focus بخشی از طراحی‌اند

کنترل‌ها باید با کیبورد قابل دسترسی و فعال‌سازی باشند. ترتیب DOM معمولاً پایه ترتیب Tab است؛ جابه‌جایی بصری گسترده می‌تواند آن را گیج‌کننده کند. Outline را بدون جایگزین مناسب حذف نکنید. Focus-visible کمک می‌کند نشانگر واضح برای تعامل کیبورد داشته باشید. استفاده از tabindex مثبت برای اصلاح ترتیب اغلب قرارداد پیچیده‌ای می‌سازد؛ ابتدا ساختار صفحه را درست کنید و از عنصر بومی کمک بگیرید.

وقتی بخش تعاملی حذف یا عوض می‌شود، محل Focus را در نظر بگیرید. Dialog و منو قراردادهای متفاوتی دارند و یک پنل معمولی جایگزین آن‌ها نیست. در فرم نمونه، پس از خطا تمرکز روی اولین ورودی مسئله‌دار قرار می‌گیرد. این رفتار به کاربر فرصت اصلاح می‌دهد، اما ادعای پوشش همه سناریوهای فرم پیچیده نیست. برای جریان واقعی، بازگشت و خروج از کنترل‌ها نیز باید روشن باشند.

شناسه‌های پایدار در React

Label و توضیح خطا به شناسه نیاز دارند. اگر یک کامپوننت چند بار نمایش داده شود، شناسه ثابت تکراری می‌تواند رابطه‌ها را خراب کند. Hook به نام useId برای تولید شناسه مرتبط با دسترس‌پذیری کاربرد دارد. مستندات رسمی useId توضیح می‌دهد که این Hook برای Key فهرست ساخته نشده است. هویت داده فهرست باید از خود داده بیاید، نه از شناسه نمایشی فرم.

برای هر ورودی، نام، راهنما و خطا را با رابطه روشن نگه دارید. aria-describedby می‌تواند توضیح مرتبط را معرفی کند و aria-invalid وضعیت نامعتبر را نشان دهد. این ویژگی‌ها خودشان پیام خطا یا اعتبارسنجی ایجاد نمی‌کنند؛ وضعیت برنامه باید با آن‌ها هماهنگ باشد. استفاده از شناسه عنصر ناموجود در رابطه aria، توضیح مفید نمی‌سازد. متن و Markup نمونه باید کنار هم خوانده شوند.

نمونه کامل فرم محلی

سه فایل package.json، index.html و main.jsx زیر را در پوشه تازه قرار دهید. Node نسخه ۲۲.۱۲ به بالا و npm لازم است. npm install و سپس npm run dev را اجرا کنید و نشانی Vite را باز کنید. نمونه فقط اعتبارسنجی محلی نام و ایمیل را نشان می‌دهد و هیچ داده‌ای به سرور نمی‌فرستد. پیام موفقیت نیز همین محدودیت را می‌گوید؛ ارسال واقعی یا ذخیره دائمی در این کد وجود ندارد.

فایل package.json

{"type":"module","scripts":{"dev":"vite"},"dependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"devDependencies":{"vite":"^8.0.0"}}

فایل index.html

<!doctype html>
<html lang="fa" dir="rtl">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>نمونه React</title></head>
<body><div id="root"></div><script type="module" src="/main.jsx"></script></body>
</html>

فایل main.jsx

import React, { useId, useRef, useState } from 'react';
import { createRoot } from 'react-dom/client';
function App() {
  const prefix = useId();
  const nameRef = useRef(null);
  const emailRef = useRef(null);
  const [errors, setErrors] = useState({});
  const [message, setMessage] = useState('');
  function submit(event) {
    event.preventDefault();
    const next = {};
    if (!nameRef.current.value.trim()) next.name = 'نام را وارد کنید.';
    if (!emailRef.current.value || !emailRef.current.validity.valid) next.email = 'ایمیل معتبر وارد کنید.';
    setErrors(next);
    setMessage('');
    if (next.name) nameRef.current.focus();
    else if (next.email) emailRef.current.focus();
    else setMessage('ورودی‌ها در این نمونه محلی معتبرند؛ داده‌ای ارسال یا ذخیره نشد.');
  }
  return <main><h1>فرم آموزشی محلی</h1>
    <form noValidate onSubmit={submit}>
      <p><label htmlFor={`${prefix}-name`}>نام (الزامی)</label><br />
      <input id={`${prefix}-name`} ref={nameRef} autoComplete="name" required
        aria-invalid={Boolean(errors.name)} aria-describedby={errors.name ? `${prefix}-name-error` : undefined} />
      {errors.name && <span id={`${prefix}-name-error`}>{errors.name}</span>}</p>
      <p><label htmlFor={`${prefix}-email`}>ایمیل (الزامی)</label><br />
      <input id={`${prefix}-email`} ref={emailRef} type="email" autoComplete="email" required
        aria-invalid={Boolean(errors.email)} aria-describedby={errors.email ? `${prefix}-email-error` : undefined} />
      {errors.email && <span id={`${prefix}-email-error`}>{errors.email}</span>}</p>
      <button type="submit">بررسی محلی ورودی‌ها</button>
    </form>
    <p role="status">{message}</p>
  </main>;
}
createRoot(document.getElementById('root')).render(<App />);

فرم noValidate دارد تا پیام‌های همین مثال مسیر نمایشی باشند. اعتبار ایمیل از Constraint Validation مرورگر خوانده می‌شود و بررسی نام با trim انجام می‌شود. این‌ها قواعد آموزشی‌اند؛ اعتبارسنجی سمت سرور و قرارداد دامنه برای محصول واقعی لازم‌اند. خطا فقط با رنگ نشان داده نشده و متن مرتبط دارد. پیام نتیجه در ناحیه Status قرار دارد تا تغییر بدون جابه‌جایی اجباری Focus قابل اعلام باشد.

خطا باید مسیر اصلاح بدهد

پیام «ورودی نامعتبر» ممکن است کافی نباشد. نام فیلد و نوع اصلاح را روشن کنید، بدون افشای اطلاعات حساس. اگر رمز باید قاعده‌ای داشته باشد، آن را پیش از شکست توضیح دهید. داده واردشده را پس از یک خطا بی‌دلیل پاک نکنید. راهنمای WAI درباره اعلان فرم تفاوت بازخورد و رابطه با کنترل را توضیح می‌دهد. نوع پیام باید با رخداد واقعی هماهنگ باشد.

برای فرم بلند، خلاصه خطا با لینک به فیلدها می‌تواند مطرح شود، ولی نمونه کوچک بالا آن را پیاده نمی‌کند. نباید متن آموزش ادعای قابلیت ناموجود داشته باشد. خطای شبکه با خطای فیلد متفاوت است؛ شاید کاربر چیزی برای اصلاح ندارد و باید امکان تلاش یا پیگیری ببیند. راهنمای طراحی فرم به جریان و پیام کمک می‌کند. دسترس‌پذیری و فهم تجربه به هم وابسته‌اند.

Live Region را هدفمند استفاده کنید

هر تغییر کوچک را با role alert اعلام نکنید. اعلان‌های زیاد می‌توانند مزاحم و نامفهوم شوند. Status برای نتیجه غیراضطراری و Alert برای پیام فوری‌تر کاربردهای متفاوتی دارند. انتخاب باید به رخداد و نیاز کاربر مربوط باشد. پیام موفقیت فقط وقتی درست است که عملیات واقعاً انجام شده باشد. در نمونه، تأیید محلی گفته می‌شود و واژه «ذخیره شد» استفاده نشده، چون ذخیره‌ای وجود ندارد.

اگر در دریافت داده کل بخش دوباره Render می‌شود، اعلان و Focus را با دقت نگه دارید. جایگزینی دائمی محتوا با Spinner می‌تواند مسیر کار را قطع کند. راهنمای TanStack Query برای تفاوت دریافت اولیه و دریافت دوباره مفید است. ابزار داده تضمین نمی‌کند پیام و تعامل قابل دسترس باشند؛ نمایش وضعیت همچنان مسئولیت رابط است.

کنتراست، بزرگ‌نمایی و حرکت

خوانایی فقط رنگ متن نیست. اندازه، فاصله، بزرگ‌نمایی و نمایش در عرض کم باید محتوا و کنترل را قابل استفاده نگه دارند. اطلاعات ضروری را تنها با رنگ منتقل نکنید. نشانگر خطا می‌تواند رنگ داشته باشد، ولی متن و رابطه هم لازم‌اند. مرجع سریع WCAG 2.2 معیارهای مرتبط را کنار روش‌ها ارائه می‌کند. یک امتیاز ابزار یا چک‌لیست کوتاه به تنهایی انطباق کامل را ثابت نمی‌کند.

برای حرکت، ترجیح Reduced Motion را در نظر بگیرید و کارکرد را بدون آن حفظ کنید. راهنمای حرکت CSS نمونه کامل مرتبط دارد. در فرم مثال، حرکت لازم نیست و اضافه نشده است. طراحی مناسب به معنی استفاده از همه قابلیت‌ها نیست؛ هر رفتار باید نقش روشن داشته باشد. برای لمس نیز اندازه و فاصله کنترل و نبود وابستگی به Hover اهمیت دارند.

دسترس‌پذیری را در قرارداد تیم نگه دارید

برای کامپوننت مشترک، نام، ورودی، حالت غیرفعال، خطا و رفتار Focus را مستند کنید. یک ظاهر مشترک بدون قرارداد تعامل می‌تواند در هر صفحه متفاوت استفاده شود. اگر کنترل آماده می‌گیرید، فرض نکنید تمام ترکیب محصول شما خودکار درست است. Label، محتوا و ترتیب همچنان به استفاده‌کننده وابسته‌اند. قابلیت ابزار را با نتیجه واقعی صفحه یکی نگیرید و محدودیت شناخته‌شده را ثبت کنید.

در تغییر واقعی، بررسی کیبورد و فناوری کمکی متناسب اهمیت دارد؛ این مقاله ادعای انجام چنین بررسی روی سایت شما ندارد. هدف نمونه نشان‌دادن رابطه‌های قابل خواندن در کد است. از HTML مناسب شروع کنید، وضعیت را صادقانه اعلام کنید و راه اصلاح را نگه دارید. دسترس‌پذیری بخشی از کارکرد رابط است و باید همراه محتوا، داده و تعامل طراحی شود، نه به صورت تزئین نهایی.

واکنش به این مقاله

اشتراک‌گذاری این مقاله:
دیدگاه‌ها 0
۰ / ۲۰۰۰

هنوز دیدگاهی ثبت نشده

اولین نفری باشید که نظر می‌دهد!