Skip to content

دسترسی پذیری | Accessibility

دسترسی پذیری وب (که به آن a11y هم گفته می شود) به عمل ایجاد وب سایت هایی گفته می شود که توسط هر کسی - اعم از شخصی با معلولیت، اتصال ضعیف، سخت افزار منسوخ یا خراب و یا صرفا کسی در محیط نامساعد - قابل استفاده باشد. به عنوان مثال، اضافه کردن زیرنویس به ویدیو هم به کاربران ناشنوا و کم شنوای شما کمک می کند و هم به کاربرانی که در محیط پرسروصدا هستند و نمی توانند صدای تلفن خود را بشنوند. به همین ترتیب، مطمئن شدن از اینکه متن شما کنتراست کمی ندارد، هم به کاربران کم بینای شما کمک می کند و هم به کاربرانی که در حال تلاش برای استفاده از تلفن خود در نور خورشید زیاد هستند.

برای شروع آماده هستید اما مطمئن نیستید از کجا شروع کنید؟

راهنمای برنامه ریزی و مدیریت دسترسی پذیری وب را که توسط کنسرسیوم جهانی وب (W3C) ارائه شده است، بررسی کنید.

شما می‌توانید در بالای هر صفحه لینکی اضافه کنید که مستقیماً به بخش اصلی محتوا برود تا کاربران بتوانند بخش‌هایی را که در صفحات متعدد وب تکرار می شود را اسکیپ کنند. لینک اسکیپ به کاربران کمک می‌کنند تا به سرعت به بخش‌های خاص یک صفحه وب بروند، به جای اینکه به صورت ترتیبی از ابتدا تا انتها صفحه را بخوانند.

معمولاً این کار در بالای App.vue انجام می شود زیرا اولین عنصر قابل تمرکز بر روی تمام صفحات شما خواهد بود:

template
<ul class="skip-links">
  <li>
    <a href="#main" ref="skipLink" class="skip-link">Skip to main content</a>
  </li>
</ul>

همچنین برای مخفی سازی لینک تا هنگامی که بر روی آن فوکوس شود می‌توانید از استایل زیر استفاده کنید:

css
.skip-link {
  white-space: nowrap;
  margin: 1em auto;
  top: 0;
  position: fixed;
  left: 50%;
  margin-left: -72px;
  opacity: 0;
}
.skip-link:focus {
  opacity: 1;
  background-color: white;
  padding: 0.5em;
  border: 1px solid black;
}

هنگامی که کاربر route را تغییر می دهد، focus را به لینک اسکیپ بازگردانید. این کار با صدا زدن تابع focus روی template ref پیوند اسکیپ (با فرض استفاده از vue-router) امکان پذیر است: (مترجم: به ref="skipLink"‎ در بالا توجه کنید.)

vue
<script>
export default {
  watch: {
    $route() {
      this.$refs.skipLink.focus()
    }
  }
}
</script>
vue
<script setup>
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()
const skipLink = ref()

watch(
  () => route.path,
  () => {
    skipLink.value.focus()
  }
)
</script>

اسناد اتصال لینک اسکیپ به محتوای اصلی را بخوانید

ساختار محتوا

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

عناوین | Headings

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

  • عناوین را بر اساس رتبه‌بندی آن‌ها درون تگ‌های heading قرار دهید: ‎<h1>‎ - ‎<h6>‎
  • در هر section از استفاده از heading صرف‌نظر نکنید
  • از تگ‌های واقعی heading به جای استایل دادن متن برای گرفتن ظاهر heading استفاده کنید

بیشتر در مورد heading بخوانید

template
<main role="main" aria-labelledby="main-title">
  <h1 id="main-title">عنوان اصلی</h1>
  <section aria-labelledby="section-title-1">
    <h2 id="section-title-1"> عنوان بخش </h2>
    <h3> زیرعنوان بخش </h3>
    <!-- محتوا -->
  </section>
  <section aria-labelledby="section-title-2">
    <h2 id="section-title-2"> عنوان بخش </h2>
    <h3> زیرعنوان بخش </h3>
    <!-- محتوا  -->
    <h3> زیرعنوان بخش </h3>
    <!-- محتوا -->
  </section>
</main>

Landmarks

landmark ها دسترسی برنامه‌ای به بخش‌های درون یک برنامه را فراهم می‌کنند. کاربرانی که بر فناوری کمکی تکیه دارند می‌توانند به هر بخشی از برنامه مراجعه کرده و محتوا را اسکیپ کنند. شما می‌توانید از role های ARIA برای دستیابی به این هدف استفاده کنید.

HTMLARIA RoleLandmark هدف
headerrole="banner"عنوان اصلی: عنوان صفحه
navrole="navigation"مجموعه‌ای از پیوندهای مناسب برای استفاده هنگام مرور سند یا اسناد مرتبط
mainrole="main"محتوای اصلی یا مرکزی سند
footerrole="contentinfo"اطلاعات درباره سند اصلی: پانویس/کپی رایت/لینک به بیانیه حریم خصوصی
asiderole="complementary"از محتوای اصلی پشتیبانی می‌کند، اما به تنهایی بامعناست
searchrole="search"این بخش شامل قابلیت جستجو برای برنامه است
formrole="form"مجموعه‌ای از عناصر مرتبط با فرم
sectionrole="region"محتوایی که مرتبط با خواست کاربر است و احتمالا کاربران می خواهند به آن مراجعه کنند. لیبل باید برای این عنصر فراهم شود

نکته

توصیه می‌شود از landmark HTML به همراه landmark مازاد برای بیشینه کردن سازگاری با مرورگرهای قدیمی که از عناصر معنایی HTML5 پشتیبانی نمی‌کنند استفاده کنید.

بیشتر در مورد landmark ها بخوانید

فرم‌های معنایی | Semantic Forms

هنگام ایجاد یک فرم، می‌توانید از این عناصر استفاده کنید: ‎<form>, <label>, <input>, <textarea>‎ و ‎<button>‎

لیبل‌ها معمولا در بالا یا در کنار فیلدهای فرم قرار می‌گیرند:

template
<form action="/dataCollectionLocation" method="post" autocomplete="on">
  <div v-for="item in formItems" :key="item.id" class="form-item">
    <label :for="item.id">{{ item.label }}: </label>
    <input
      :type="item.type"
      :id="item.id"
      :name="item.id"
      v-model="item.value"
    />
  </div>
  <button type="submit">Submit</button>
</form>

توجه کنید که می‌توانید autocomplete='on'‎ را روی عنصر form قرار دهید و این ویژگی برای تمام inputهای فرم اعمال می‌شود. همچنین می‌توانید برای هر input مقدار متفاوتی برای ویژگی autocomplete تعیین کنید.

Labels

برای هر یک از فیلدها، یک لیبل (label) تعریف کنید تا مشخص شود آن فیلد برای چه منظوری استفاده می‌شود. سپس، ویژگی id را برای فیلد و ویژگی for را برای لیبل تعریف کنید و مقادیر آن‌ها را برابر هم قرار دهید تا بین لیبل و فیلد ارتباط برقرار شود.

template
<label for="name">Name: </label>
<input type="text" name="name" id="name" v-model="name" />

اگر این عنصر را در DevTools کروم خود بررسی کنید و تب Accessibility را درون تب Elements باز کنید، خواهید دید که چگونه input نام خود را از لیبل دریافت می کند:

Chrome Developer Tools showing input accessible name from label

هشدار

اگرچه ممکن است label هایی را دیده باشید که فیلدهای ورودی را به این صورت دربر گرفته‌باشند:

template
<label>
  Name:
  <input type="text" name="name" id="name" v-model="name" />
</label>

اما تنظیم صریح لیبل‌ها با یک id مطابق توسط فناوری‌های کمکی بهتر پشتیبانی می‌شود.

aria-label

همچنین می‌توانید با استفاده از aria-label به input نام دسترس‌پذیر بدهید.

template
<label for="name">Name: </label>
<input
  type="text"
  name="name"
  id="name"
  v-model="name"
  :aria-label="nameLabel"
/>

این عنصر را در ابزارهای توسعه‌دهنده کروم بررسی کنید تا ببینید چگونه نام تغییر کرده است:

Chrome Developer Tools showing input accessible name from aria-label

aria-labelledby

استفاده از aria-labelledby شبیه aria-label است با این تفاوت که زمانی استفاده می‌شود که متن لیبل روی صفحه قابل مشاهده باشد. آن را با سایر عناصر از طریق id آن‌ها جفت می‌کنند و می‌توانید چندین id را متصل کنید: (مترجم: billing به h1 و name به input برمی‌گرده. input هم از label نام می‌گیره)

template
<form
  class="demo"
  action="/dataCollectionLocation"
  method="post"
  autocomplete="on"
>
  <h1 id="billing">Billing</h1>
  <div class="form-item">
    <label for="name">Name: </label>
    <input
      type="text"
      name="name"
      id="name"
      v-model="name"
      aria-labelledby="billing name"
    />
  </div>
  <button type="submit">Submit</button>
</form>

Chrome Developer Tools showing input accessible name from aria-labelledby

aria-describedby

aria-describedby به همان شیوه‌ی aria-labelledby استفاده می‌شود با این تفاوت که توضیحاتی با اطلاعات اضافی که کاربر ممکن است نیاز داشته باشد را فراهم می‌کند. این می‌تواند برای توضیح معیارهای هر ورودی استفاده شود:

template
<form
  class="demo"
  action="/dataCollectionLocation"
  method="post"
  autocomplete="on"
>
  <h1 id="billing">Billing</h1>
  <div class="form-item">
    <label for="name">Full Name: </label>
    <input
      type="text"
      name="name"
      id="name"
      v-model="name"
      aria-labelledby="billing name"
      aria-describedby="nameDescription"
    />
    <p id="nameDescription">Please provide first and last name.</p>
  </div>
  <button type="submit">Submit</button>
</form>

شما می‌توانید description را با بررسی Chrome DevTools ببینید:

Chrome Developer Tools showing input accessible name from aria-labelledby and description with aria-describedby

نمونه متن | Placeholder

از Placeholder ها اجتناب کنید زیرا می‌توانند بسیاری از کاربران را گیج کنند.

یکی از مشکلات Placeholder ها این است که به طور پیش‌فرض معیارهای کنتراست رنگ را برآورده نمی‌کنند؛ تصحیح کنتراست رنگ باعث می‌شود Placeholder شبیه داده‌های از پیش‌تکمیل‌شده در فیلدهای ورودی به نظر برسد. با نگاه به مثال زیر، می‌توانید ببینید که Placeholder نام خانوادگی که معیارهای کنتراست رنگ را برآورده می‌کند، شبیه داده‌های پیش‌تکمیل‌شده می‌رسد:

Accessible placeholder

template
<form
  class="demo"
  action="/dataCollectionLocation"
  method="post"
  autocomplete="on"
>
  <div v-for="item in formItems" :key="item.id" class="form-item">
    <label :for="item.id">{{ item.label }}: </label>
    <input
      type="text"
      :id="item.id"
      :name="item.id"
      v-model="item.value"
      :placeholder="item.placeholder"
    />
  </div>
  <button type="submit">Submit</button>
</form>
css
/* https://www.w3schools.com/howto/howto_css_placeholder.asp */

#lastName::placeholder {
  /* Chrome, Firefox, Opera, Safari 10.1+ */
  color: black;
  opacity: 1; /* Firefox */
}

#lastName:-ms-input-placeholder {
  /* Internet Explorer 10-11 */
  color: black;
}

#lastName::-ms-input-placeholder {
  /* Microsoft Edge */
  color: black;
}

بهتر است تمام اطلاعاتی که کاربر برای پر کردن فرم‌ها نیاز دارد خارج از input ها فراهم شود.

دستورالعمل‌ها | Instructions

هنگام اضافه کردن دستورالعمل برای فیلدهای ورودی، مطمئن شوید آن را به درستی به ورودی متصل کرده‌اید. می‌توانید دستورالعمل‌های اضافی ارائه دهید و چندین id را درون aria-labelledby متصل کنید. این امکان طراحی انعطاف‌پذیرتری را فراهم می‌کند.

template
<fieldset>
  <legend>Using aria-labelledby</legend>
  <label id="date-label" for="date">Current Date: </label>
  <input
    type="date"
    name="date"
    id="date"
    aria-labelledby="date-label date-instructions"
  />
  <p id="date-instructions">MM/DD/YYYY</p>
</fieldset>

به علاوه، می‌توانید دستورالعمل‌ها را با استفاده از aria-describedby به ورودی متصل کنید:

template
<fieldset>
  <legend>Using aria-describedby</legend>
  <label id="dob" for="dob">Date of Birth: </label>
  <input type="date" name="dob" id="dob" aria-describedby="dob-instructions" />
  <p id="dob-instructions">MM/DD/YYYY</p>
</fieldset>

پنهان کردن محتوا

معمولاً توصیه نمی‌شود label ها را پنهان کرد، حتی اگر input مقدار accessible name را داشته باشد. با این حال، اگر عملکرد ورودی با محتوای اطراف آن قابل درک باشد، می‌توانیم label را بطور بصری پنهان کنیم.

این فیلد سرچ را ببینید:

template
<form role="search">
  <label for="search" class="hidden-visually">Search: </label>
  <input type="text" name="search" id="search" v-model="search" />
  <button type="submit">Search</button>
</form>

می‌توانیم این کار را انجام دهیم زیرا دکمه جستجو به کاربران کمک می‌کند تا هدف فیلد ورودی را شناسایی کنند.

می‌توانیم از CSS برای پنهان کردن بصری عناصر اما نگه داشتن آن‌ها در دسترس فناوری کمکی استفاده کنیم:

css
.hidden-visually {
  position: absolute;
  overflow: hidden;
  white-space: nowrap;
  margin: 0;
  padding: 0;
  height: 1px;
  width: 1px;
  clip: rect(0 0 0 0);
  clip-path: inset(100%);
}

aria-hidden="true"‎

اضافه کردن aria-hidden="true"‎ عنصر را از دید فناوری کمکی پنهان می‌کند اما آن را به صورت بصری برای سایر کاربران در دسترس نگه می‌دارد. از آن روی عناصر قابل focus استفاده نکنید، صرفاً روی محتوای تزئینی، تکراری یا خارج از صفحه استفاده کنید.

template
<p> این متن از صفحه خوان پنهان نشده است </p>
<p aria-hidden="true"> این متن از صفحه خوان پنهان شده است <</p>

دکمه‌ها |‌ Buttons

هنگام استفاده از دکمه‌ها درون یک فرم، باید نوع آن‌ها را تنظیم کنید تا از ارسال اشتباهی فرم جلوگیری شود. همچنین می‌توانید از یک input برای ایجاد دکمه استفاده کنید:

template
<form action="/dataCollectionLocation" method="post" autocomplete="on">
  <!-- Buttons -->
  <button type="button">Cancel</button>
  <button type="submit">Submit</button>

  <!-- Input buttons -->
  <input type="button" value="Cancel" />
  <input type="submit" value="Submit" />
</form>

Functional Images

می‌توانید از این تکنیک برای ایجاد تصاویر عملکردی استفاده کنید.

  • فیلدهای ورودی

    • این تصاویر مانند دکمه‌ای با نوع submit در فرم‌ها عمل می‌کنند
    template
    ‎<form role="search"‎>‎
      ‎<label for="search" class="hidden-visually">Search: </label>‎
      ‎<input type="text" name="search" id="search" v-model="search"‎ />‎
      ‎<input
        type="image"
        class="btnImg"
        src="https://img.icons8.com/search"
        alt="Search"
      ‎/>‎
    ‎</form>‎
  • آیکن‌ها

template
<form role="search">
  <label for="searchIcon" class="hidden-visually">Search: </label>
  <input type="text" name="searchIcon" id="searchIcon" v-model="searchIcon" />
  <button type="submit">
    <i class="fas fa-search" aria-hidden="true"></i>
    <span class="hidden-visually">Search</span>
  </button>
</form>

استانداردها

کنسرسیوم جهانی وب (W3C) و کارگروه دسترس‌پذیری وب (WAI) استانداردهای دسترس‌پذیری وب را برای قسمت‌های مختلف توسعه می‌دهد:

رهنمودهای دسترسی‌پذیری محتوای وب | Web Content Accessibility Guidelines (WCAG)

WCAG 2.1 بر اساس WCAG 2.0 توسعه یافته و اجرای فناوری‌های جدید را با رسیدگی به تغییرات وب ممکن می‌سازد. W3C توصیه می‌کند هنگام توسعه یا به‌روزرسانی خط‌مشی‌های دسترس‌پذیری وب، از جدیدترین نسخه WCAG استفاده شود.

چهار اصل راهنمای اصلی WCAG 2.1 (به اختصار POUR):

  • قابل ادراک (Perceivable)
    • کاربران باید بتوانند اطلاعات ارائه شده را درک کنند
  • قابل استفاده (Operable)
    • اجزای رابط کاربری مانند دکمه‌ها، فیلدهای ورود اطلاعات، لینک‌ها و منوها باید برای کاربران قابل دسترسی و استفاده باشد
  • قابل فهم (Understandable)
    • اطلاعات و عملکرد رابط کاربری باید برای همه کاربران قابل فهم باشد
  • انعطاف‌پذیر (Robust)
    • محتوای وبسایت باید به گونه‌ای طراحی و پیاده‌سازی شود که با گذشت زمان و ظهور فناوری‌ها و ابزارهای جدید (مثل مرورگرهای جدید، سیستم‌عامل‌های جدید و غیره)، همچنان قابل دسترس و استفاده برای کاربران باقی بماند

کارگروه دسترسی‌پذیری وب - راهنماهایی برای برنامه‌های اینترنتی غنی و قابل دسترس (WAI-ARIA)

کنسرسیوم جهانی وب راهنمایی‌هایی در مورد چگونگی ساخت محتوای تعاملی و رابط کاربری پیشرفته ارائه می‌دهد.

منابع

مستندات

فناوری‌های کمکی

تست

کاربران

سازمان بهداشت جهانی تخمین می‌زند که ۱۵ درصد جمعیت جهان دارای نوعی ناتوانی هستند که ۲ تا ۴ درصد آن‌ها به شدت ناتوان می‌باشند. این برآورد حاکی از آن است که حدود یک میلیارد نفر در سراسر جهان دارای ناتوانی هستند؛ بنابراین افراد دارای ناتوانی بزرگ‌ترین گروه اقلیت در جهان را تشکیل می‌دهند.

انواع مختلفی از ناتوانی‌ها وجود دارد که به طور تقریبی می‌توان آن‌ها را به چهار دسته تقسیم کرد:

  • بینایی - این کاربران می‌توانند از صفحه خوان‌ها، بزرگ‌نمایی صفحه، کنترل کنتراست صفحه یا نمایشگر بریل بهره‌مند شوند.
  • شنوایی - این کاربران می‌توانند از زیرنویس‌ها، پیاده‌سازی متن یا ویدیوهای زبان اشاره بهره‌مند شوند.
  • حرکتی - این کاربران می‌توانند از مجموعه‌ای از فناوری‌های کمکی برای نقص حرکتی بهره‌مند شوند: نرم‌افزارهای تشخیص گفتار، ردیابی چشم، دسترسی تک‌سوئیچی، عصای سر، سوئیچ مکش و فوت، توپ غلتان بزرگ، صفحه‌کلید سازگار و سایر فناوری‌های کمکی.
  • شناختی - این کاربران می‌توانند از رسانه‌های تکمیلی، سازماندهی ساختاری محتوا و نوشتار ساده و روشن بهره‌مند شوند.

لینک‌های زیر از WebAim را برای درک بهتر نیاز کاربران بررسی کنید:

دسترسی پذیری | Accessibility has loaded