آنلاین

دسترس‌پذیری در Angular

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

برای آشنایی عمیق با مسائل و تکنیک‌های طراحی برنامه‌های دسترس‌پذیر، دوره Learn Accessibility از web.dev گوگل را ببینید.

در این صفحه، بهترین روش‌های طراحی برنامه‌های Angular را بررسی می‌کنیم تا برای همه کاربران، از جمله افرادی که به فناوری‌های کمکی متکی هستند، به‌خوبی کار کنند.

ویژگی‌های دسترس‌پذیری

ساخت تجربه‌های دسترس‌پذیر در وب اغلب مستلزم تنظیم ویژگی‌های Accessible Rich Internet Applications \(ARIA\) است تا در بخش‌هایی که معنای معنایی مشخصی وجود ندارد، این معنا فراهم شود. برای کنترل مقادیر ویژگی‌های مرتبط با دسترس‌پذیری، از syntax مربوط به attribute binding در template استفاده کنید.

ویژگی‌ها و propertyهای ARIA

هنگام binding به ویژگی‌های ARIA در Angular، می‌توانید مانند هر ویژگی HTML دیگری مستقیماً از آن‌ها استفاده کنید.

html
<button [aria-label]="myActionLabel">…</button>

ویژگی‌های ایستای ARIA مانند ویژگی‌های معمول HTML عمل می‌کنند.

html
<button aria-label="Save document">…</button>

برخی الگوهای ARIA، APIهای DOM یا ورودی‌های directive را در اختیار می‌گذارند که مقادیر ساختاریافته می‌پذیرند؛ برای مثال مجموعه‌ای از ارجاع‌های Element. در این موارد از property binding استاندارد استفاده کنید تا ارتباط زیرین همواره همگام باقی بماند.

ts
@Component({
  template: `
    <h2 #dialogTitle>Attention</h2>
    <p #dialogDescription>Please review your answers before continuing.</p>

    <section role="dialog" [ariaLabelledByElements]="[dialogTitle, dialogDescription]">
      <ng-content />
    </section>
  `,
})
export class ReviewDialog {}

در اینجا [ariaLabelledByElements] آرایه‌ای از elementها را می‌پذیرد؛ بنابراین property binding هر بار که داده‌های template تغییر می‌کنند، ارجاع‌های element را به‌روز نگه می‌دارد.

برای مشاهده خلاصه syntax ویژگی‌های ARIA، به راهنمای binding مراجعه کنید.

کامپوننت‌های رابط کاربری Angular

کتابخانه Angular Material که توسط تیم Angular نگهداری می‌شود، مجموعه‌ای از کامپوننت‌های رابط کاربری قابل استفاده مجدد است که هدف آن‌ها دسترس‌پذیری کامل است. Component Development Kit (CDK) شامل پکیج a11y است که ابزارهایی برای پشتیبانی از جنبه‌های مختلف دسترس‌پذیری فراهم می‌کند. برای مثال:

برای اطلاعات بیشتر درباره ناحیه‌های aria-live، مستندات W3C را ببینید.

  • از LiveAnnouncer برای اعلام پیام‌ها به کاربران screen reader از طریق یک ناحیه aria-live استفاده می‌شود.

از آن برای ایجاد تجربه‌ای دسترس‌پذیر در کامپوننت‌هایی مانند dialogهای modal استفاده کنید که فوکوس باید در محدوده مشخصی باقی بماند.

  • directive با نام cdkTrapFocus، فوکوس کلید Tab را درون یک element محدود می‌کند.

برای جزئیات کامل این ابزارها و سایر ابزارها، مرور کلی دسترس‌پذیری Angular CDK را ببینید.

برای کامپوننت‌هایی با استایل سفارشی که به الگوهای تعاملی قابل استفاده مجدد WAI-ARIA نیاز دارند، Angular Aria directiveهای headless را برای الگوهایی مانند accordion، combobox، listbox، menu، tabs و toolbar فراهم می‌کند. این directiveها ضمن اینکه ساختار HTML و استایل برنامه را در اختیار شما می‌گذارند، تعامل با صفحه‌کلید، ویژگی‌های ARIA، مدیریت فوکوس و پشتیبانی از screen reader را مدیریت می‌کنند.

تکمیل elementهای بومی

elementهای بومی HTML چندین الگوی تعاملی استاندارد و مهم برای دسترس‌پذیری را در خود دارند. هنگام ساخت کامپوننت‌های Angular، تا حد امکان همین elementهای بومی را مستقیماً استفاده کنید و رفتارهایی را که به‌خوبی پشتیبانی می‌شوند از نو پیاده‌سازی نکنید.

برای مثال، به‌جای ساخت یک custom element برای نوع جدیدی از دکمه، کامپوننتی ایجاد کنید که از attribute selector روی element بومی <button> استفاده می‌کند. این الگو بیشتر برای <button> و <a> کاربرد دارد، اما می‌توان آن را برای بسیاری از انواع دیگر element نیز به کار برد.

نمونه‌های این الگو را می‌توانید در Angular Material ببینید: MatButton، MatTabNav و MatTable.

استفاده از container برای elementهای بومی

گاهی استفاده از element بومی مناسب به یک element به‌عنوان container نیاز دارد. برای مثال، element بومی <input> نمی‌تواند فرزند داشته باشد؛ بنابراین هر کامپوننت سفارشی ورود متن باید یک <input> را همراه با elementهای اضافی در بر بگیرد. اگر فقط <input> را در template کامپوننت سفارشی خود قرار دهید، کاربران کامپوننت نمی‌توانند propertyها و ویژگی‌های دلخواه را روی element مربوط به <input> تنظیم کنند. در عوض، یک کامپوننت container بسازید که با استفاده از content projection، کنترل بومی را در API کامپوننت قرار دهد.

می‌توانید MatFormField را به‌عنوان نمونه‌ای از این الگو ببینید.

مطالعه موردی: ساخت progress bar سفارشی

مثال زیر نشان می‌دهد چگونه با استفاده از host binding برای کنترل ویژگی‌های مرتبط با دسترس‌پذیری، یک progress bar دسترس‌پذیر بسازید.

ویژگی ARIA با نام aria-valuenow به ورودی کاربر bind شده است.

  • کامپوننت یک element با قابلیت دسترس‌پذیری تعریف می‌کند که هم ویژگی استاندارد HTML یعنی role و هم ویژگی‌های ARIA را دارد.
  • در template، ویژگی aria-label دسترسی screen readerها به کنترل را تضمین می‌کند.
ts
/* eslint-disable @angular-eslint/no-host-metadata-property */
// #docregion progressbar-component
import {Component, input} from '@angular/core';

/**
 * Example progressbar component.
 */
@Component({
  selector: 'app-example-progressbar',
  template: '<div class="bar" [style.width.%]="value()"></div>',
  styleUrls: ['./progress-bar.component.css'],
  host: {
    // Sets the role for this component to "progressbar"
    role: 'progressbar',

    // Sets the minimum and maximum values for the progressbar role.
    'aria-valuemin': '0',
    'aria-valuemax': '100',

    // Binding that updates the current value of the progressbar.
    '[attr.aria-valuenow]': 'value',
  },
})
export class ExampleProgressbarComponent {
  /** Current value of the progressbar. */
  value = input(0);
}

// #enddocregion progressbar-component
html
<h1>Accessibility Example</h1>
<!-- #docregion template -->
<label for="progress-value">
  Enter an example progress value
  <input
    id="progress-value"
    type="number"
    min="0"
    max="100"
    [value]="progress"
    (input)="setProgress($event)"
  />
</label>

<!-- The user of the progressbar sets an aria-label to communicate what the progress means. -->
<app-example-progressbar [value]="progress" aria-label="Example of a progress bar" />
<!-- #enddocregion template -->

مسیریابی

مدیریت فوکوس پس از پیمایش

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

برای اینکه فقط به نشانه‌های بصری متکی نباشید، مطمئن شوید کد routing پس از پیمایش صفحه، فوکوس را به‌روزرسانی می‌کند. برای تشخیص زمان به‌روزرسانی فوکوس، از رویداد NavigationEnd در service با نام Router استفاده کنید.

مثال زیر نشان می‌دهد چگونه پس از پیمایش، عنوان محتوای اصلی را در DOM پیدا کرده و روی آن فوکوس کنید.

ts
router.events.pipe(filter((e) => e instanceof NavigationEnd)).subscribe(() => {
  const mainHeader = document.querySelector('#main-content-header');
  if (mainHeader) {
    mainHeader.focus();
  }
});

در یک برنامه واقعی، element دریافت‌کننده فوکوس به ساختار و layout مشخص برنامه شما بستگی دارد. element فوکوس‌شده باید کاربران را در موقعیتی قرار دهد که بلافاصله وارد محتوای اصلی تازه نمایش‌داده‌شده شوند. از موقعیت‌هایی که پس از تغییر route، فوکوس به element مربوط به body بازمی‌گردد اجتناب کنید.

شناسایی لینک‌های فعال

کلاس‌های CSS اعمال‌شده روی elementهای فعال RouterLink، مانند RouterLinkActive، یک نشانه بصری برای تشخیص لینک فعال فراهم می‌کنند. اما نشانه بصری برای کاربران نابینا یا کم‌بینا کمکی نمی‌کند. اعمال ویژگی aria-current روی element می‌تواند به شناسایی لینک فعال کمک کند. برای اطلاعات بیشتر، مستندات aria-current در Mozilla Developer Network \(MDN\) را ببینید.

directive با نام RouterLinkActive ورودی ariaCurrentWhenActive را فراهم می‌کند که هنگام فعال‌شدن لینک، مقدار aria-current را روی مقدار مشخص‌شده قرار می‌دهد.

مثال زیر نشان می‌دهد چگونه علاوه بر اعمال کلاس active-page به لینک‌های فعال، ویژگی aria-current آن‌ها را هنگام فعال‌بودن روی مقدار "page" تنظیم کنید:

html
<nav>
  <a routerLink="home" routerLinkActive="active-page" ariaCurrentWhenActive="page"> Home </a>
  <a routerLink="about" routerLinkActive="active-page" ariaCurrentWhenActive="page"> About </a>
  <a routerLink="shop" routerLinkActive="active-page" ariaCurrentWhenActive="page"> Shop </a>
</nav>

بارگذاری به‌تعویق‌افتاده

هنگام استفاده از بلوک‌های @defer در Angular برای lazy loading محتوا، پیامدهای دسترس‌پذیری آن را برای کاربران فناوری‌های کمکی در نظر بگیرید. ممکن است screen readerها هنگام بارگذاری کامپوننت‌های به‌تعویق‌افتاده، تغییر محتوا را به‌صورت خودکار اعلام نکنند و کاربران از محتوای جدید بی‌اطلاع بمانند.

برای اینکه تغییرات محتوای به‌تعویق‌افتاده به‌درستی اعلام شوند، بلوک‌های @defer را در elementهایی با ناحیه زنده ARIA مناسب قرار دهید. برای راهنمایی و مثال‌های کامل، بخش دسترس‌پذیری در راهنمای defer را ببینید.

اطلاعات بیشتر

کتاب‌ها

  • «A Web for Everyone: Designing Accessible User Experiences»، نوشته Sarah Horton و Whitney Quesenbery
  • «Inclusive Design Patterns»، نوشته Heydon Pickering