الفرق بين المراجعتين لصفحة: «React/accessibility»

من موسوعة حسوب
لا ملخص تعديل
تحديث
 
(9 مراجعات متوسطة بواسطة 3 مستخدمين غير معروضة)
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE:سهولة الوصول}}</noinclude>
<noinclude>{{DISPLAYTITLE:سهولة الوصول في React}}</noinclude>


== الفائدة من سهولة الوصول ==
== الفائدة من سهولة الوصول ==
سهولة الوصول للويب (Web accessibility) والتي يشار إليها أيضًا بالرمز <code>a11y</code>، هي تصميم وإنشاء مواقع يُمكِن استخدامها من قبل أي شخص. يكون دعم سهولة الوصول ضروريًّا للسماح للتقنيات المساعدة بالتعامل مع صفحات الويب.
سهولة الوصول للويب (Web accessibility) والتي يشار إليها أيضًا بالرمز <code>[[wikt:a11y|a11y]]</code>، هي تصميم وإنشاء مواقع يُمكِن استخدامها من قبل أي شخص. يكون دعم سهولة الوصول ضروريًّا للسماح للتقنيات المساعدة بالتعامل مع صفحات الويب.


تدعم React بشكلٍ كامل بناء مواقع سهلة الوصول، وذلك عن طريق استخدام تقنيات HTML المعياريّة عادةً.
تدعم React بشكلٍ كامل بناء مواقع سهلة الوصول، وذلك عن طريق استخدام تقنيات HTML المعياريّة عادةً.
سطر 9: سطر 9:


=== WCAG ===
=== WCAG ===
تزوّدنا توجيهات سهولة الوصول لمحتوى الويب (Web Content Accessibility Guidelines) بتوجيهات لإنشاء مواقع سهلة الوصول.
تزوّدنا [https://www.w3.org/WAI/intro/wcag توجيهات سهولة الوصول لمحتوى الويب (Web Content Accessibility Guidelines)] بتوجيهات لإنشاء مواقع سهلة الوصول.


تعطينا القوائم التالية فكرة عامة حول ذلك:
تعطينا القوائم التالية فكرة عامة حول ذلك:
* قائمة التوجيهات المُقدَّمة من Wuhcag.
* [https://www.wuhcag.com/wcag-checklist/ قائمة التوجيهات المُقدَّمة من Wuhcag].
* قائمة التوجيهات المُقدَّمة من WebAIM.
* [http://webaim.org/standards/wcag/checklist قائمة التوجيهات المُقدَّمة من WebAIM].
* قائمة التوجيهات من مشروع A11Y.
* [http://a11yproject.com/checklist.html قائمة التوجيهات من مشروع A11Y].


=== WAI-ARIA ===
=== WAI-ARIA ===
يحتوي مستند دليل سهولة الوصول - تطبيقات الإنترنت سهلة الوصول (Web Accessibility Initiative - Accessible Rich Internet Applications ) على تقنيات لبناء أدوات ذكية في JavaScript سهلة الوصول بشكلٍ كامل.
يحتوي مستند [https://www.w3.org/WAI/intro/aria دليل سهولة الوصول - تطبيقات الإنترنت سهلة الوصول (Web Accessibility Initiative - Accessible Rich Internet Applications )] على تقنيات لبناء أدوات ذكية في JavaScript سهلة الوصول بشكلٍ كامل.  


انتبه إلى أنّ خاصيّات <code>aria-*</code>‎ في HTML ليست كلّها مدعومة بشكلٍ كامل في JSX. وفي حين أنّ معظم خاصيّات DOM تُكتَب في React بشكل camelCase، ينبغي كتابة خاصيّات <code>aria-*</code>‎ بحالة hyphen-cased (والتي تُعرَف أيضًا بحالة kebab-case، أو lisp-case، إلخ..) كما هي حالتها في HTML:<syntaxhighlight lang="javascript">
انتبه إلى أنّ خاصيّات <code>aria-*</code>‎ في HTML ليست كلّها مدعومة بشكلٍ كامل في JSX. وفي حين أنّ معظم خاصيّات DOM تُكتَب في React بشكل camelCase، ينبغي كتابة خاصيّات <code>aria-*</code>‎ بحالة hyphen-cased (والتي تُعرَف أيضًا بحالة kebab-case، أو lisp-case، إلخ..) كما هي حالتها في HTML:<syntaxhighlight lang="javascript">
سطر 33: سطر 33:
== HTML الخاصة بدلالات الألفاظ (Semantic HTML) ==
== HTML الخاصة بدلالات الألفاظ (Semantic HTML) ==
وهي تهتم بتقديم المعنى الدلالي لكل عنصر من عناصر HTML بدلًا من الاهتمام فقط بما يُمثِّله هذا العنصر. وهي أساس سهولة الوصول في تطبيقات الويب. حيث يُعطينا استخدام عناصر HTML المتنوعة لتعزيز المعنى الدلالي للمعلومات في مواقعنا سهولة للوصول بشكلٍ مجاني.
وهي تهتم بتقديم المعنى الدلالي لكل عنصر من عناصر HTML بدلًا من الاهتمام فقط بما يُمثِّله هذا العنصر. وهي أساس سهولة الوصول في تطبيقات الويب. حيث يُعطينا استخدام عناصر HTML المتنوعة لتعزيز المعنى الدلالي للمعلومات في مواقعنا سهولة للوصول بشكلٍ مجاني.
* مرجع عناصر HTML.
* [https://developer.mozilla.org/en-US/docs/Web/HTML/Element مرجع عناصر HTML].
أحيانًا نخرق دلالات HTML عندما نُضيف عناصر <code>‎<nowiki><div></nowiki></code>‎ إلى JSX لجعل شيفرة React تعمل، خاصّة عند التعامل مع القوائم (‎<code><nowiki><ol></nowiki></code>‎، و <code>‎<nowiki><ul></nowiki></code>‎، و <code>‎<nowiki><dl></nowiki></code>‎) والجدول ‎<code><nowiki><table></nowiki></code>‎. في هذه الحالات يجب أن نستخدم الأجزاء (Fragments) في React لتجميع عناصر متعددة معًا.
أحيانًا نخرق دلالات HTML عندما نُضيف عناصر <code>‎<nowiki><div></nowiki></code>‎ إلى JSX لجعل شيفرة React تعمل، خاصّة عند التعامل مع القوائم (‎<code><nowiki><ol></nowiki></code>‎، و <code>‎<nowiki><ul></nowiki></code>‎، و <code>‎<nowiki><dl></nowiki></code>‎) والجدول ‎<code><nowiki><table></nowiki></code>‎. في هذه الحالات يجب أن نستخدم [[React/fragments|الأجزاء (Fragments)]] في React لتجميع عناصر متعددة معًا.


على سبيل المثال:<syntaxhighlight lang="javascript">
على سبيل المثال:<syntaxhighlight lang="javascript">
سطر 48: سطر 48:
}
}


function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        <ListItem item={item} key={item.id} />
      ))}
    </dl>
  );
}
</syntaxhighlight>تستطيع تعيين مجموعة من العناصر إلى مصفوفة من الأجزاء (fragments) كما ستفعل مع أي نوع آخر من العناصر:<syntaxhighlight>
function Glossary(props) {
function Glossary(props) {
   return (
   return (
سطر 62: سطر 72:
}
}


</syntaxhighlight>عندما لا تحتاج أي خاصيّات ضمن الوسم <code>Fragment</code> تستطيع أيضًا استخدام الصياغة المختصرة إن كانت أدواتك تدعمها:<syntaxhighlight lang="javascript">
</syntaxhighlight>عندما لا تحتاج أي خاصيّات ضمن الوسم <code>Fragment</code> تستطيع أيضًا استخدام [[React/fragments#.D8.B5.D9.8A.D8.A7.D8.BA.D8.A9 .D9.85.D8.AE.D8.AA.D8.B5.D8.B1.D8.A9|الصياغة المختصرة]] إن كانت أدواتك تدعمها:<syntaxhighlight lang="javascript">
function ListItem({ item }) {
function ListItem({ item }) {
   return (
   return (
سطر 72: سطر 82:
}
}


</syntaxhighlight>للمزيد من المعلومات انظر إلى توثيق الأجزاء في React.
</syntaxhighlight>للمزيد من المعلومات انظر إلى [[React/fragments|توثيق الأجزاء في React]].


== الحقول (Forms) سهلة الوصول ==
== الحقول (Forms) سهلة الوصول ==
سطر 80: سطر 90:


تُرينا المصادر التالية كيفية فعل ذلك:
تُرينا المصادر التالية كيفية فعل ذلك:
* شرح كيفيّة تسمية العناصر المُقدَّم من قبل W3C.
* [https://www.w3.org/WAI/tutorials/forms/labels/ شرح كيفيّة تسمية العناصر المُقدَّم من قبل W3C].
* شرح كيفيّة تسمية العناصر المُقدَّم من قبل WebAIM.
* [http://webaim.org/techniques/forms/controls شرح كيفيّة تسمية العناصر المُقدَّم من قبل WebAIM].
* شرح الأسماء سهلة الوصول المُقدَّم من قبل مجموعة Paciello.
* [https://www.paciellogroup.com/blog/2017/04/what-is-an-accessible-name/ شرح الأسماء سهلة الوصول المُقدَّم من قبل مجموعة Paciello].
على الرغم من أنّه يُمكِن استخدام ممارسات HTML المعيارية هذه بشكلٍ مباشر في React، لاحظ أنّ الخاصيّة <code>for</code> تُكتَب بالشكل <code>htmlFor</code> في JSX:
على الرغم من أنّه يُمكِن استخدام ممارسات HTML المعيارية هذه بشكلٍ مباشر في React، لاحظ أنّ الخاصيّة <code>for</code> تُكتَب بالشكل <code>htmlFor</code> في JSX:<syntaxhighlight lang="javascript">
<label htmlFor="namedInput">الاسم:</label>
<input id="namedInput" type="text" name="name"/>
 
</syntaxhighlight>
 
=== إخبار المستخدمين عن الأخطاء ===
يجب أن تكون جميع حالات الأخطاء مفهومة من قبل جميع المستخدمين. يُرينا الرابط التالي كيفيّة إظهار نصوص الأخطاء إلى القارئين أيضًا:
* [https://www.w3.org/WAI/tutorials/forms/notifications/ شرح إشعارات المستخدمين المُقدَّم من قبل W3C].
* [http://webaim.org/techniques/formvalidation/ شرح التحقّق من الحقول المُقدَّم من قبل WebAIM].
 
== التحكم من خلال تركيز الحقول ==
احرص على أن يكون تطبيق الويب لديك سهل الوصول بشكلٍ كامل من خلال لوحة المفاتيح فقط:
* [http://webaim.org/techniques/keyboard/ شرح سهولة الوصول من لوحة المفاتيح المُقدَّم من قبل WebAIM].
 
=== تركيز لوحة المفاتيح وحدود التركيز ===
يُشير تركيز لوحة المفاتيح إلى العنصر الحالي في DOM المُختار ليقبل الدّخل من لوحة المفاتيح. نشاهده كحد خارجي للتركيز مرسوم بشكل مشابه للحد في الصورة التالية:
[[ملف:keyboard-focus-dec0e6bcc1f882baf76ebc860d4f04e5-9d63d.png|مركز]]
 
لا تستخدم CSS لإزالة هذا الحد الخارجي (مثلًا عن طريق تعيين <code>outline: 0</code>) إلّا إن كنتَ تضع بدلًا منه طريقة أخرى لحدود التركيز.
 
=== آليات التخطي إلى المحتوى المطلوب ===
يجب تزويد آليات للسماح للمستخدمين بتخطي مقاطع التصفّح (navigation) في تطبيقك لأنّ هذا يُساعد ويُسرِّح التصفح من لوحة المفاتيح.
 
تكون روابط تخطي التصفّح أو روابط التخطي عبارة عن روابط تصفّح مخفيّة والتي تُصبِح ظاهرة فقط عندما يتفاعل مستخدمو لوحة المفاتيح مع الصفحة. من السهل تطبيقها باستخدام الروابط الداخلية للصفحة وبعض التنسيق:
* [http://webaim.org/techniques/skipnav/ شرح روابط تخطي التصفّح من WebAIM].
استخدم أيضًا عناصر الأعلام والأدوار مثل العنصرين <code>‎<main></code>‎ و ‎<code><aside></code>‎ للإعلان عن مناطق من الصفحة كمناطق مفيدة مما يسمح للمستخدم بالانتقال بسرعة إلى هذه الأقسام.
 
اقرأ المزيد حول استخدام هذه العناصر لتعزيز سهولة الوصول من هنا:
* [http://www.scottohara.me/blog/2018/03/03/landmarks.html نقاط علام سهلة الوصول].
 
=== إدارة التركيز برمجيًّا ===
تُعدِّل تطبيقات React بشكلٍ مستمر HTML DOM خلال زمن التنفيذ، مما يؤدي أحيانًا إلى فقدان تركيز لوحة المفاتيح أو تعيينها إلى عنصر غير متوقّع. نحتاج لإصلاح هذا إلى توجيه تركيز لوحة المفاتيح برمجيًّا بالاتجاه الصحيح. مثلًا عن طريق إعادة تعيين تركيز لوحة المفايتح إلى الزر الذي فتح النافذة بعد إغلاق تلك النافذة.
 
تشرح توثيقات الويب الخاصّة بشبكة مطوري Mozilla هذا الأمر وتصف كيف يمكننا بناء [https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets أدوات مصغرة في JavaScript قابلة للتصفّح باستخدام لوحة المفاتيح].
 
لتعيين التركيز في React نستطيع استخدام [[React/refs and the dom|مراجع إلى عناصر DOM]].
 
نُنشِئ في البداية مرجعًا إلى عنصر في JSX الموجودة ضمن مكوّن React من نوع صنف:<syntaxhighlight lang="javascript">
class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
// إنشاء مرجع لتخزين عنصر textInput
    this.textInput = React.createRef();
  }
  render() {
  // استخدم رد النداء ref لتخزين مرجع إلى عنصر إدخال النص ضمن نسخة الحقل
  // مثلًا this.textInput
    return (
      <input
        type="text"
        ref={this.textInput}
      />
    );
  }
}
 
</syntaxhighlight>نستطيع بعدها التركيز في مكان آخر في مكوّننا عند الحاجة لذلك:<syntaxhighlight lang="javascript">
focus() {
  // التركيز على حقل الإدخال النصي باستخدام DOM API
  // ملاحظة: نصل إلى current للحصول على عقدة DOM الحالية
  this.textInput.current.focus();
}
 
</syntaxhighlight>يحتاج المكوّن الأب أحيانًا إلى تعيين التركيز إلى مكوّن ابن. نستطيع فعل ذلك عن طريق [[React/refs and the dom#.D8.AA.D8.B9.D8.B1.D9.8A.D8.B6 .D9.85.D8.B1.D8.A7.D8.AC.D8.B9 DOM .D9.84.D9.84.D9.85.D9.83.D9.88.D9.86 .D8.A7.D9.84.D8.A3.D8.A8|تعريض مراجع DOM للمكوّن الأب]] عبر خاصية مميزة في المكوّن الابن والتي تُمرِّر مرجع الأب إلى عقدة DOM للمكوّن الابن:<syntaxhighlight lang="javascript">
function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}
 
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.inputElement = React.createRef();
  }
  render() {
    return (
      <CustomTextInput inputRef={this.inputElement} />
    );
  }
}
 
// تستطيع الآن تعيين التركيز عند الحاجة إليه
this.inputElement.current.focus();
 
</syntaxhighlight>عند استخدام المكوّنات ذات الترتيب الأعلى لتمديد المكوّنات، فمن المفضّل [[React/forwarding refs|تمرير المرجع]] إلى المكوّن المغلّف باستخدام الدالة <code>forwardRef</code> في React. إن كان لا يعتمد المكوّن ذو الترتيب الأعلى المُقدَّم من طرف ثالث تمرير المراجع، فيُمكِن استخدام الطريقة السابقة كطريقة احتياطية.
 
من الأمثلة الرائعة حول إدارة التركيز مثال <code>[https://github.com/davidtheclark/react-aria-modal react-aria-modal]</code>، وهو مثال نادر نسبيًّا عن نافذة سهلة الوصول بشكل كامل، فهي لا تُعيِّن فقط التركيز المبدئي على زر الإلغاء <code>cancel</code> (ممّا يمنع مستخدم لوحة المفاتيح من تفعيل الحدث <code>success</code> عن طريق الخطأ) وتحصر تركيز لوحة المفاتيح بداخل النافذة، بل تُعيد تعيين التركيز أيضًا إلى العنصر الذي أطلق هذه النافذة.
 
ملاحظة: على الرغم من أنّ ميزة تركيز لوحة المفاتيح هي ميزة هامة لسهولة الوصول ولكن في نفس الوقت هي تقنية يجب استخدامها بحذر. استخدمها لإصلاح تركيز لوحة المفاتيح عند حدوث خطأ ما، ولكن لا تستخدمها لتتوقع كيف يريد المستخدم أن يتعامل مع التطبيق.
 
== أحداث المؤشر والفأرة ==
احرص على أن تكون جميع الوظائف المتوفرة عبر أحداث الفأرة أو المؤشر سهلة الوصول باستخدام لوحة المفاتيح لوحدها. يقود الاعتماد على المؤشر فقط إلى حالات لا يتمكّن فيها مستخدمو لوحة المفاتيح من استخدام تطبيقك.
 
لتوضيح ذلك فلننظر إلى مثال حول حصول خلل في سهولة الوصول بسبب أحداث الضغط <code>click</code>. يحتوي هذا المثال على نمط الضغط خارج النافذة حيث يستطيع المستخدم تعطيل النافذة المنبثقة المفتوحة عن طريق الضغط خارج العنصر:
[[ملف:outerclick-with-mouse-5523b05b22210c5a2fa0bd1f01339cb3.gif|مركز]]
 
يُنفَّذ هذا عن طريق إرفاق الحدث <code>click</code> بكائن النافذة <code>windows</code> الذي يُغلِق النافذة المنبثقة:<syntaxhighlight lang="javascript">
class OuterClickExample extends React.Component {
  constructor(props) {
    super(props);
 
    this.state = { isOpen: false };
    this.toggleContainer = React.createRef();
 
    this.onClickHandler = this.onClickHandler.bind(this);
    this.onClickOutsideHandler = this.onClickOutsideHandler.bind(this);
  }
 
  componentDidMount() {
    window.addEventListener('click', this.onClickOutsideHandler);
  }
 
  componentWillUnmount() {
    window.removeEventListener('click', this.onClickOutsideHandler);
  }
 
  onClickHandler() {
    this.setState(currentState => ({
      isOpen: !currentState.isOpen
    }));
  }
 
  onClickOutsideHandler(event) {
    if (this.state.isOpen && !this.toggleContainer.current.contains(event.target)) {
      this.setState({ isOpen: false });
    }
  }
 
  render() {
    return (
      <div ref={this.toggleContainer}>
        <button onClick={this.onClickHandler}>Select an option</button>
        {this.state.isOpen && (
          <ul>
            <li>الخيار 1</li>
            <li>الخيار 2</li>
            <li>الخيار 3</li>
          </ul>
        )}
      </div>
    );
  }
}
</syntaxhighlight>يعمل هذا بشكل جيّد للمستخدمين الذي يمتلكون أجهزة تأشير كالفأرة مثلًا، ولكن تقود تجربة هذا المثال من لوحة المفاتيح وحدها إلى وظيفة معطوبة عند الانتقال للعنصر التالي بسبب عدم استقبال الكائن <code>windows</code> للحدث <code>click</code>. قد يؤدي هذا إلى منع المستخدمين من استخدام تطبيقك:
[[ملف:outerclick-with-keyboard-eca0ca825c8c5e2aa609cee72ef47e27.gif|مركز]]
 
يُمكِن تحقيق نفس الوظيفة عن طريق استخدام مُعالِجات الأحداث المناسبة، مثل <code>onBlur</code> و <code>onFocus</code>:<syntaxhighlight lang="javascript">
class BlurExample extends React.Component {
  constructor(props) {
    super(props);
 
    this.state = { isOpen: false };
    this.timeOutId = null;
 
    this.onClickHandler = this.onClickHandler.bind(this);
    this.onBlurHandler = this.onBlurHandler.bind(this);
    this.onFocusHandler = this.onFocusHandler.bind(this);
  }
 
  onClickHandler() {
    this.setState(currentState => ({
      isOpen: !currentState.isOpen
    }));
  }
 
  // نغلق النافذة المنبثقة بالنقرة التالية عن طريق استخدام التابع setTimeout
  // هذا ضروري لأننا نحتاج أولا من التحقق
  // ما إذا كان ابن آخر للعنصر قد استقبل التركيز
  // بسبب إطلاق الحدث blur قبل حدث التركيز الجديد
 
  onBlurHandler() {
    this.timeOutId = setTimeout(() => {
      this.setState({
        isOpen: false
      });
    });
  }
 
  // إن استقبل أي عنصر ابن التركيز فلا تغلق النافذة المنبثقة
  onFocusHandler() {
    clearTimeout(this.timeOutId);
  }
 
  render() {
// تساعدنا React عن طريق مضاعفة أحداث blur و focus للمكون الأب
    return (
      <div onBlur={this.onBlurHandler}
          onFocus={this.onFocusHandler}>
        <button onClick={this.onClickHandler}
                aria-haspopup="true"
                aria-expanded={this.state.isOpen}>
          Select an option
        </button>
        {this.state.isOpen && (
          <ul>
            <li>خيار 1</li>
            <li>خيار 2</li>
            <li>خيار 3</li>
          </ul>
        )}
      </div>
    );
  }
}
 
</syntaxhighlight>تُوفِّر هذه الشيفرة الوظيفة المطلوبة إلى مستخدمي المؤشر ولوحة المفاتيح بنفس الوقت. لاحظ أيضًا أنّنا أضفنا خاصيّات ‎<code>aria-*</code>‎ لدعم المستخدمين الذين يقرؤون الشاشة. ولغرض البساطة لم ننفذ أحداث لوحة المفاتيح لتمكين التفاعل بمفاتيح الأسهم <code>arrow key</code> مع خيارات النافذة المنبثقة:
[[ملف:blur-popover-close-28ce2067489843caf05fe7ce22494542.gif|مركز]]
 
هذا فقط مثال واحد من حالات متعدّدة التي يؤدي فيها الاعتماد فقط على أحداث المؤشر والفأرة إلى خلل بالوظيفة بالنسبة لمستخدمي لوحة المفاتيح. يكشف اختبار لوحة المفاتيح مباشرة المناطق التي فيها مشاكل والتي يمكن بعد ذلك إصلاحها باستخدام معالجات أحداث لوحة المفاتيح.
 
== أدوات مصغرة أكثر تعقيدًا ==
لا يجب أن تعني تجربة المستخدم الأكثر تعقيدًا أن تصبح سهولة الوصول أقل. تُحقَّق سهولة الوصول ببساطة عن طريق كتابة شيفرة قريبة من HTML قدر الإمكان. يُمكِن كتابة أكثر الأدوات المُصغَّرة تعقيدًا بطريقة سهلة الوصول.
 
نحتاج هنا إلى معرفة [https://www.w3.org/TR/wai-aria/#roles بأدوار ARIA] و[https://www.w3.org/TR/wai-aria/#states_and_properties حالات وخاصيّات ARIA] أيضًا. وهي عبارة عن جداول تحتوي على خاصيّات HTML مدعومة بشكل كامل في JSX وتُمكِّننا من بناء مكوّنات React سهلة الوصول وذات وظيفة عالية الكفاءة.
 
يمتلك كل نوع من الأدوات المصغرة نمط تصميم خاص ومن المتوقع أن يعمل بطريقة معينة من قبل المستخدمين والعملاء مثل:
* [https://www.w3.org/TR/wai-aria-practices/#aria_ex أساليب WAI-ARIA – أنماط التصميم والأدوات المصغرة].
* [http://heydonworks.com/practical_aria_examples/ أمثلة Heydon Pickering – ARIA].
* [https://inclusive-components.design/ المكوّنات الداخلية].
 
== نقاط أخرى يجب أخذها بعين الاعتبار ==
 
=== تعيين اللغة ===
يجب أن تشير إلى لغة نصوص الصفحة لأنّ برامج قراءة الشاشة تستخدم هذا لتحديد إعدادات الصوت الصحيحة:
* [http://webaim.org/techniques/screenreader/#language توثيقات اللغة – WebAIM].
 
=== تعيين عنوان المستند ===
عيّن عنوان المستند عن طريق العنصر ‎<code><title></code>‎ بشكل صحيح ليصف محتوى الصفحة الحالية حيث يضمن ذلك أن يبقى المستخدم على دراية بمحتوى الصفحة الحالي:
* [https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-title.html فهم متطلبات عنوان المستند – WCAG].
نستطيع تعيين العنوان في React باستخدام [https://github.com/gaearon/react-document-title مكوّن عنوان المستند].
 
=== تباين اللون ===
احرص على امتلاك النص القابل للقراءة تباين ألوان كافٍ ليبقى مقروءًا من قبل المستخدمين ضعيفي البصر:
* [https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html فهم متطلبات تباين اللون – WCAG].
* [https://www.smashingmagazine.com/2014/10/color-contrast-tips-and-tools-for-accessibility/ كل شيء حول تباين اللون ولماذا يجب أن تعيد النظر فيه].
* [http://a11yproject.com/posts/what-is-color-contrast/ ما هو التباين اللوني – مشروع A11y].
قد يكون من الممل حساب مجموعات الألوان المناسبة يدويًّا لجميع الحالات في موقعك، لذا تستطيع [http://jxnblk.com/colorable/ حساب جميع الألوان باستخدام Colorable].
 
تتضمّن أدوات aXe و WAVE التي سنشير إليها اختبارات لتباين الألوان وستُبلِّغ عن أخطاء التباين.
 
إن أردت تمديد قدرات اختبار التباين فبإمكانك استخدام هذه الأدوات:
* [http://webaim.org/resources/contrastchecker/ التحقق من تباين الألوان – WebAIM].
* [https://www.paciellogroup.com/resources/contrastanalyser/ محلل تباين الألوان – مجموعة Paciello].
 
== أدوات الاختبار والتطوير ==
هنالك عدد من الأدوات التي نستطيع استخدامها لمساعدتنا على إنشاء تطبيقات ويب سهلة الوصول.
 
=== لوحة المفاتيح ===
من أسهل وأهم الاختبارات التي يجب عليك القيام بها هي التحقق ما إذا كان كامل موقعك قابلًا للوصول والاستخدام عن طريق لوحة المفاتيح لوحدها. افعل ذلك عن طريق:
* إزالة الفأرة.
* استخدام زر <code>Tab</code> و <code>Shift+Tab</code> للتصفح.
* استخدام زر <code>Enter</code> لتفعيل العناصر.
* استخدام الأسهم للتفاعل مع بعض العناصر، مثل القوائم والقوائم المنسدلة.
 
=== مساعد التطوير ===
نستطيع التحقق من بعض ميزات سهولة الوصول بشكل مباشر في شيفرة JSX. عادة تكون هذه التحققات متوفرة مسبقًا في أي مُحرِّر يحتوي على إضافات JSX من أجل أدوار ARIA، والحالات والخاصيّات. لدينا أيضًا إمكانية الوصول للأدوات التالية:
 
==== [https://github.com/evcohen/eslint-plugin-jsx-a11y eslint-plugin-jsx-a11y] ====
تزوّدنا هذه الإضافة من أجل ESLint بالتحقق من الأخطاء خاص بمشاكل سهولة الوصول في JSX. تسمح لك العديد من المُحرِّرات بتضمين هذه الموجودات بشكل مباشر في تحليل الشيفرة ونوافذ الشيفرة المصدرية.
 
يمتلك <code>[https://github.com/facebookincubator/create-react-app create-react-app]</code> هذه الإضافة مع مجموعة قواعد فرعية مُفعلة. إن أردت تمكين المزيد من قواعد سهولة الوصول فبإمكانك إنشاء الملف <code>‎.eslintrc</code> في المجلد الجذري للمشروع مع وضع هذا المحتوى بداخله:<syntaxhighlight lang="javascript">
{
  "extends": ["react-app", "plugin:jsx-a11y/recommended"],
  "plugins": ["jsx-a11y"]
}
 
</syntaxhighlight>
 
=== اختبار سهولة الوصول في المتصفح ===
العديد من الأدوات الموجودة تنفذ اختبارات أداء لسهولة الوصول في صفحات الويب ضمن متصفحك. استخدمها مع أدوات التحقق من سهولة الوصول التي سنشير إليها الآن لأنّها فقط تختبر سهولة الوصول من الناحية التقنية في HTML:
 
==== aXe, aXe-core and react-axe ====
توفّر لنا شركة Deque تقنية تُدعى [https://github.com/dequelabs/axe-core aXe-core] من أجل اختبارات سهولة الوصول التلقائيّة لتطبيقاتنا. تتضمّن هذه الوحدة تكاملًا من أجل Selenium.
 
إنّ [https://www.deque.com/products/axe/ مُحرِّك سهولة الوصول] أو aXe هو عبارة عن إضافة للمتصفح لكشف سهولة الوصول مبنية على تقنية aXe-core.
 
بإمكانك أيضًا استخدام الوحدة [https://github.com/dylanb/react-axe react-axe] للتبليغ عن موجودات سهولة الوصول بشكل مباشر إلى الكونسول أثناء التطوير وتنقيح الأخطاء.
 
==== WebAIM WAVE ====
[http://wave.webaim.org/extension/ أداة تقييم سهولة الوصول للويب]، وهي عبارة عن إضافة أخرى للمتصفح.
 
==== مستكشفات سهولة الوصول وشجرة سهولة الوصول ====
[https://www.paciellogroup.com/blog/2015/01/the-browser-accessibility-tree/ شجرة سهولة الوصول] هي عبارة عن مجموعة فرعية من شجرة DOM والتي تحتوي على كائنات سهلة الوصول لكل عنصر DOM والتي ينبغي تعريضها إلى تقنية مُساعِدة مثل قارئات الشاشة.
 
نستطيع بسهولة في بعض المتصفحات مشاهدة معلومات سهولة الوصول لكل عنصر في شجرة سهولة الوصول:
* [https://developer.mozilla.org/en-US/docs/Tools/Accessibility_inspector تفعيل مستكشف سهولة الوصول في متصفح Firefox].
* [https://gist.github.com/marcysutton/0a42f815878c159517a55e6652e3b23a تفعيل مستكشف سهولة الوصول في متصفح Chrome].
* [https://developer.apple.com/library/content/documentation/Accessibility/Conceptual/AccessibilityMacOSX/OSXAXTestingApps.html استخدام مستكشف سهولة الوصول في متصفح OS X Safari].
 
=== قارئات الشاشة ===
يجب أن يكون اختبار قارئات الشاشة جزءًا من اختبارات سهولة الوصول لديك.
 
يرجى الانتباه إلى وجود اختلافات عند الجمع بين قارئات شاشة مختلفة مع متصفحات مختلفة. لذا من الأفضل أن تختبر تطبيقك مع المتصفح الذي يُلائِم قارئات الشاشة التي تختارها.
 
=== قارئات الشاشة الأشيع استخدامًا ===
 
==== NVDA في متصفح Firefox ====
[https://www.nvaccess.org/ الوصول غير المرئي لسطح المكتب] (NonVisual Desktop Access أو اختصارًا NVDA) هو عبارة عن قارئ شاشة مُستخدَم بشكلٍ كبير.
 
ارجع إلى المقالات التالية لمعرفة أفضل طريقة لاستخدام NVDA:
* [http://webaim.org/articles/nvda/ استخدام NVDA لتقييم سهولة الوصول للويب – شرح من موقع WebAIM].
* [https://dequeuniversity.com/screenreaders/nvda-keyboard-shortcuts اختصارات لوحة المفاتيح في NVDA – شرح من موقع Deque].
 
==== VoiceOver في متصفح Safari ====
وهو عبارة عن قارئ شاشة مُدمَج في أجهزة Apple.
 
ارجع إلى المقالات التالية لمعرفة كيفيّة تفعيل واستخدام VoiceOver:
* [http://webaim.org/articles/voiceover/ استخدام VoiceOver لتقييم سهولة الوصول للويب – شرح من موقع WebAIM].
* [https://dequeuniversity.com/screenreaders/voiceover-keyboard-shortcuts اختصارات لوحة مفاتيح نظام OS X في VoiceOver – شرح من موقع Deque].
* [https://dequeuniversity.com/screenreaders/voiceover-ios-shortcuts اختصارات نظام iOS في VoiceOver – شرح من موقع Deque].
 
==== JAWS في متصفح Internet Explorer ====
[http://www.freedomscientific.com/Products/Blindness/JAWS الوصول للوظائف عن طريق الكلام] (Job Access With Speech أو اختصارًا JAWS)، وهو قارئ شاشة مُستخدَم على نظام ويندوز.
 
ارجع إلى هذه الإرشادات حول كيفيّة استخدام JAWS:
* [http://webaim.org/articles/jaws/ استخدام JAWS لتقييم سهولة الوصول للويب – شرح من موقع WebAIM].
* [https://dequeuniversity.com/screenreaders/jaws-keyboard-shortcuts اختصارات لوحة المفاتيح في JAWS – شرح من موقع Deque].
 
=== قارئات شاشة أخرى ===
 
==== ChromeVox في متصفح Chrome ====
[http://www.chromevox.com/ ChromeVox] هو قارئ شاشة مُدمَج على أجهزة Chromebooks ومُتوفِّر [https://chrome.google.com/webstore/detail/chromevox/kgejglhpjiefppelpmljglcjbhoiplfn?hl=en كإضافة] لمتصفّح Google Chrome.
 
ارجع إلى الإرشادات التالية حول كيفيّة استخدام ChromeVox:
* [https://support.google.com/chromebook/answer/7031755?hl=en استخدام قارئ الشاشة المُدمَج – دليل Chromebook من Google].
* [http://www.chromevox.com/keyboard_shortcuts.html مرجع اختصارات لوحة المفاتيح التقليدية في ChromeVox].
== انظر أيضًا ==
* [[React/jsx in depth|شرح JSX بالتفصيل]]
* [[React/static type checking|التحقق من الأنواع الثابتة]]
* [[React/typechecking with proptypes|التحقق من الأنواع باستخدام PropTypes]]
* [[React/refs and the dom|استخدام المراجع مع DOM]]
* [[React/uncontrolled components|المكونات غير المضبوطة]]
* [[React/optimizing performance|تحسين الأداء]]
* [[React/react without es6|React بدون ES6]]
* [[React/react without jsx|React بدون JSX]]
* [[React/reconciliation|المطابقة (Reconciliation)]]
* [[React/context|استخدام السياق (Context) في React]]
* [[React/fragments|استخدام الأجزاء (Fragments) في React]]
* [[React/portals|المداخل (Portals) في React]]
* [[React/error boundaries|حدود الأخطاء]]
* [[React/web components|مكونات الويب]]
* [[React/higher order components|المكونات ذات الترتيب الأعلى]]
* [[React/forwarding refs|تمرير المراجع]]
* [[React/render props|خاصيات التصيير]]
* [[React/integrating with other libraries|تكامل React مع المكتبات الأخرى]]
* [[React/code splitting|تقسيم الشيفرة]]
* [[React/strict mode|الوضع الصارم (Strict Mode)]]
== مصادر==
*[https://reactjs.org/docs/accessibility.html صفحة سهولة الوصول في توثيق React الرسمي].
[[تصنيف:React]]
[[تصنيف:React Advanced Guides]]

المراجعة الحالية بتاريخ 09:01، 3 نوفمبر 2020


الفائدة من سهولة الوصول

سهولة الوصول للويب (Web accessibility) والتي يشار إليها أيضًا بالرمز a11y، هي تصميم وإنشاء مواقع يُمكِن استخدامها من قبل أي شخص. يكون دعم سهولة الوصول ضروريًّا للسماح للتقنيات المساعدة بالتعامل مع صفحات الويب.

تدعم React بشكلٍ كامل بناء مواقع سهلة الوصول، وذلك عن طريق استخدام تقنيات HTML المعياريّة عادةً.

المعايير والتوجيهات

WCAG

تزوّدنا توجيهات سهولة الوصول لمحتوى الويب (Web Content Accessibility Guidelines) بتوجيهات لإنشاء مواقع سهلة الوصول.

تعطينا القوائم التالية فكرة عامة حول ذلك:

WAI-ARIA

يحتوي مستند دليل سهولة الوصول - تطبيقات الإنترنت سهلة الوصول (Web Accessibility Initiative - Accessible Rich Internet Applications ) على تقنيات لبناء أدوات ذكية في JavaScript سهلة الوصول بشكلٍ كامل.

انتبه إلى أنّ خاصيّات aria-*‎ في HTML ليست كلّها مدعومة بشكلٍ كامل في JSX. وفي حين أنّ معظم خاصيّات DOM تُكتَب في React بشكل camelCase، ينبغي كتابة خاصيّات aria-*‎ بحالة hyphen-cased (والتي تُعرَف أيضًا بحالة kebab-case، أو lisp-case، إلخ..) كما هي حالتها في HTML:

<input
  type="text"
  aria-label={labelText}
  aria-required="true"
  onChange={onchangeHandler}
  value={inputValue}
  name="name"
/>

HTML الخاصة بدلالات الألفاظ (Semantic HTML)

وهي تهتم بتقديم المعنى الدلالي لكل عنصر من عناصر HTML بدلًا من الاهتمام فقط بما يُمثِّله هذا العنصر. وهي أساس سهولة الوصول في تطبيقات الويب. حيث يُعطينا استخدام عناصر HTML المتنوعة لتعزيز المعنى الدلالي للمعلومات في مواقعنا سهولة للوصول بشكلٍ مجاني.

أحيانًا نخرق دلالات HTML عندما نُضيف عناصر ‎<div>‎ إلى JSX لجعل شيفرة React تعمل، خاصّة عند التعامل مع القوائم (‎<ol>‎، و ‎<ul>‎، و ‎<dl>‎) والجدول ‎<table>‎. في هذه الحالات يجب أن نستخدم الأجزاء (Fragments) في React لتجميع عناصر متعددة معًا.

على سبيل المثال:

import React, { Fragment } from 'react';

function ListItem({ item }) {
  return (
    <Fragment>
      <dt>{item.term}</dt>
      <dd>{item.description}</dd>
    </Fragment>
  );
}

function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        <ListItem item={item} key={item.id} />
      ))}
    </dl>
  );
}

تستطيع تعيين مجموعة من العناصر إلى مصفوفة من الأجزاء (fragments) كما ستفعل مع أي نوع آخر من العناصر:

function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
		// يجب أن تمتلك الأجزاء أيضًا خاصية مفتاح عند تعيين المجموعات
        <Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </Fragment>
      ))}
    </dl>
  );
}

عندما لا تحتاج أي خاصيّات ضمن الوسم Fragment تستطيع أيضًا استخدام الصياغة المختصرة إن كانت أدواتك تدعمها:

function ListItem({ item }) {
  return (
    <>
      <dt>{item.term}</dt>
      <dd>{item.description}</dd>
    </>
  );
}

للمزيد من المعلومات انظر إلى توثيق الأجزاء في React.

الحقول (Forms) سهلة الوصول

التسمية (Labeling)

يجب تسمية كل حقل في HTML، مثل ‎<input>‎ و ‎<textarea>‎ بطريقة سهلة الوصول. يجب علينا تزويد تسميات وصفية تكون ظاهرة أيضًا للقارئين.

تُرينا المصادر التالية كيفية فعل ذلك:

على الرغم من أنّه يُمكِن استخدام ممارسات HTML المعيارية هذه بشكلٍ مباشر في React، لاحظ أنّ الخاصيّة for تُكتَب بالشكل htmlFor في JSX:

<label htmlFor="namedInput">الاسم:</label>
<input id="namedInput" type="text" name="name"/>

إخبار المستخدمين عن الأخطاء

يجب أن تكون جميع حالات الأخطاء مفهومة من قبل جميع المستخدمين. يُرينا الرابط التالي كيفيّة إظهار نصوص الأخطاء إلى القارئين أيضًا:

التحكم من خلال تركيز الحقول

احرص على أن يكون تطبيق الويب لديك سهل الوصول بشكلٍ كامل من خلال لوحة المفاتيح فقط:

تركيز لوحة المفاتيح وحدود التركيز

يُشير تركيز لوحة المفاتيح إلى العنصر الحالي في DOM المُختار ليقبل الدّخل من لوحة المفاتيح. نشاهده كحد خارجي للتركيز مرسوم بشكل مشابه للحد في الصورة التالية:

لا تستخدم CSS لإزالة هذا الحد الخارجي (مثلًا عن طريق تعيين outline: 0) إلّا إن كنتَ تضع بدلًا منه طريقة أخرى لحدود التركيز.

آليات التخطي إلى المحتوى المطلوب

يجب تزويد آليات للسماح للمستخدمين بتخطي مقاطع التصفّح (navigation) في تطبيقك لأنّ هذا يُساعد ويُسرِّح التصفح من لوحة المفاتيح.

تكون روابط تخطي التصفّح أو روابط التخطي عبارة عن روابط تصفّح مخفيّة والتي تُصبِح ظاهرة فقط عندما يتفاعل مستخدمو لوحة المفاتيح مع الصفحة. من السهل تطبيقها باستخدام الروابط الداخلية للصفحة وبعض التنسيق:

استخدم أيضًا عناصر الأعلام والأدوار مثل العنصرين ‎<main>‎ و ‎<aside>‎ للإعلان عن مناطق من الصفحة كمناطق مفيدة مما يسمح للمستخدم بالانتقال بسرعة إلى هذه الأقسام.

اقرأ المزيد حول استخدام هذه العناصر لتعزيز سهولة الوصول من هنا:

إدارة التركيز برمجيًّا

تُعدِّل تطبيقات React بشكلٍ مستمر HTML DOM خلال زمن التنفيذ، مما يؤدي أحيانًا إلى فقدان تركيز لوحة المفاتيح أو تعيينها إلى عنصر غير متوقّع. نحتاج لإصلاح هذا إلى توجيه تركيز لوحة المفاتيح برمجيًّا بالاتجاه الصحيح. مثلًا عن طريق إعادة تعيين تركيز لوحة المفايتح إلى الزر الذي فتح النافذة بعد إغلاق تلك النافذة.

تشرح توثيقات الويب الخاصّة بشبكة مطوري Mozilla هذا الأمر وتصف كيف يمكننا بناء أدوات مصغرة في JavaScript قابلة للتصفّح باستخدام لوحة المفاتيح.

لتعيين التركيز في React نستطيع استخدام مراجع إلى عناصر DOM.

نُنشِئ في البداية مرجعًا إلى عنصر في JSX الموجودة ضمن مكوّن React من نوع صنف:

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
	// إنشاء مرجع لتخزين عنصر textInput
    this.textInput = React.createRef();
  }
  render() {
  // استخدم رد النداء ref لتخزين مرجع إلى عنصر إدخال النص ضمن نسخة الحقل
  // مثلًا this.textInput
    return (
      <input
        type="text"
        ref={this.textInput}
      />
    );
  }
}

نستطيع بعدها التركيز في مكان آخر في مكوّننا عند الحاجة لذلك:

focus() {
  // التركيز على حقل الإدخال النصي باستخدام DOM API
  // ملاحظة: نصل إلى current للحصول على عقدة DOM الحالية
  this.textInput.current.focus();
}

يحتاج المكوّن الأب أحيانًا إلى تعيين التركيز إلى مكوّن ابن. نستطيع فعل ذلك عن طريق تعريض مراجع DOM للمكوّن الأب عبر خاصية مميزة في المكوّن الابن والتي تُمرِّر مرجع الأب إلى عقدة DOM للمكوّن الابن:

function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.inputElement = React.createRef();
  }
  render() {
    return (
      <CustomTextInput inputRef={this.inputElement} />
    );
  }
}

// تستطيع الآن تعيين التركيز عند الحاجة إليه
this.inputElement.current.focus();

عند استخدام المكوّنات ذات الترتيب الأعلى لتمديد المكوّنات، فمن المفضّل تمرير المرجع إلى المكوّن المغلّف باستخدام الدالة forwardRef في React. إن كان لا يعتمد المكوّن ذو الترتيب الأعلى المُقدَّم من طرف ثالث تمرير المراجع، فيُمكِن استخدام الطريقة السابقة كطريقة احتياطية.

من الأمثلة الرائعة حول إدارة التركيز مثال react-aria-modal، وهو مثال نادر نسبيًّا عن نافذة سهلة الوصول بشكل كامل، فهي لا تُعيِّن فقط التركيز المبدئي على زر الإلغاء cancel (ممّا يمنع مستخدم لوحة المفاتيح من تفعيل الحدث success عن طريق الخطأ) وتحصر تركيز لوحة المفاتيح بداخل النافذة، بل تُعيد تعيين التركيز أيضًا إلى العنصر الذي أطلق هذه النافذة.

ملاحظة: على الرغم من أنّ ميزة تركيز لوحة المفاتيح هي ميزة هامة لسهولة الوصول ولكن في نفس الوقت هي تقنية يجب استخدامها بحذر. استخدمها لإصلاح تركيز لوحة المفاتيح عند حدوث خطأ ما، ولكن لا تستخدمها لتتوقع كيف يريد المستخدم أن يتعامل مع التطبيق.

أحداث المؤشر والفأرة

احرص على أن تكون جميع الوظائف المتوفرة عبر أحداث الفأرة أو المؤشر سهلة الوصول باستخدام لوحة المفاتيح لوحدها. يقود الاعتماد على المؤشر فقط إلى حالات لا يتمكّن فيها مستخدمو لوحة المفاتيح من استخدام تطبيقك.

لتوضيح ذلك فلننظر إلى مثال حول حصول خلل في سهولة الوصول بسبب أحداث الضغط click. يحتوي هذا المثال على نمط الضغط خارج النافذة حيث يستطيع المستخدم تعطيل النافذة المنبثقة المفتوحة عن طريق الضغط خارج العنصر:

يُنفَّذ هذا عن طريق إرفاق الحدث click بكائن النافذة windows الذي يُغلِق النافذة المنبثقة:

class OuterClickExample extends React.Component {
  constructor(props) {
    super(props);

    this.state = { isOpen: false };
    this.toggleContainer = React.createRef();

    this.onClickHandler = this.onClickHandler.bind(this);
    this.onClickOutsideHandler = this.onClickOutsideHandler.bind(this);
  }

  componentDidMount() {
    window.addEventListener('click', this.onClickOutsideHandler);
  }

  componentWillUnmount() {
    window.removeEventListener('click', this.onClickOutsideHandler);
  }

  onClickHandler() {
    this.setState(currentState => ({
      isOpen: !currentState.isOpen
    }));
  }

  onClickOutsideHandler(event) {
    if (this.state.isOpen && !this.toggleContainer.current.contains(event.target)) {
      this.setState({ isOpen: false });
    }
  }

  render() {
    return (
      <div ref={this.toggleContainer}>
        <button onClick={this.onClickHandler}>Select an option</button>
        {this.state.isOpen && (
          <ul>
            <li>الخيار 1</li>
            <li>الخيار 2</li>
            <li>الخيار 3</li>
          </ul>
        )}
      </div>
    );
  }
}

يعمل هذا بشكل جيّد للمستخدمين الذي يمتلكون أجهزة تأشير كالفأرة مثلًا، ولكن تقود تجربة هذا المثال من لوحة المفاتيح وحدها إلى وظيفة معطوبة عند الانتقال للعنصر التالي بسبب عدم استقبال الكائن windows للحدث click. قد يؤدي هذا إلى منع المستخدمين من استخدام تطبيقك:

يُمكِن تحقيق نفس الوظيفة عن طريق استخدام مُعالِجات الأحداث المناسبة، مثل onBlur و onFocus:

class BlurExample extends React.Component {
  constructor(props) {
    super(props);

    this.state = { isOpen: false };
    this.timeOutId = null;

    this.onClickHandler = this.onClickHandler.bind(this);
    this.onBlurHandler = this.onBlurHandler.bind(this);
    this.onFocusHandler = this.onFocusHandler.bind(this);
  }

  onClickHandler() {
    this.setState(currentState => ({
      isOpen: !currentState.isOpen
    }));
  }

  // نغلق النافذة المنبثقة بالنقرة التالية عن طريق استخدام التابع setTimeout
  // هذا ضروري لأننا نحتاج أولا من التحقق
  // ما إذا كان ابن آخر للعنصر قد استقبل التركيز
  // بسبب إطلاق الحدث blur قبل حدث التركيز الجديد
  
  onBlurHandler() {
    this.timeOutId = setTimeout(() => {
      this.setState({
        isOpen: false
      });
    });
  }

  // إن استقبل أي عنصر ابن التركيز فلا تغلق النافذة المنبثقة
  onFocusHandler() {
    clearTimeout(this.timeOutId);
  }

  render() {
	// تساعدنا React عن طريق مضاعفة أحداث blur و focus للمكون الأب
	
    return (
      <div onBlur={this.onBlurHandler}
           onFocus={this.onFocusHandler}>
        <button onClick={this.onClickHandler}
                aria-haspopup="true"
                aria-expanded={this.state.isOpen}>
          Select an option
        </button>
        {this.state.isOpen && (
          <ul>
            <li>خيار 1</li>
            <li>خيار 2</li>
            <li>خيار 3</li>
          </ul>
        )}
      </div>
    );
  }
}

تُوفِّر هذه الشيفرة الوظيفة المطلوبة إلى مستخدمي المؤشر ولوحة المفاتيح بنفس الوقت. لاحظ أيضًا أنّنا أضفنا خاصيّات ‎aria-*‎ لدعم المستخدمين الذين يقرؤون الشاشة. ولغرض البساطة لم ننفذ أحداث لوحة المفاتيح لتمكين التفاعل بمفاتيح الأسهم arrow key مع خيارات النافذة المنبثقة:

هذا فقط مثال واحد من حالات متعدّدة التي يؤدي فيها الاعتماد فقط على أحداث المؤشر والفأرة إلى خلل بالوظيفة بالنسبة لمستخدمي لوحة المفاتيح. يكشف اختبار لوحة المفاتيح مباشرة المناطق التي فيها مشاكل والتي يمكن بعد ذلك إصلاحها باستخدام معالجات أحداث لوحة المفاتيح.

أدوات مصغرة أكثر تعقيدًا

لا يجب أن تعني تجربة المستخدم الأكثر تعقيدًا أن تصبح سهولة الوصول أقل. تُحقَّق سهولة الوصول ببساطة عن طريق كتابة شيفرة قريبة من HTML قدر الإمكان. يُمكِن كتابة أكثر الأدوات المُصغَّرة تعقيدًا بطريقة سهلة الوصول.

نحتاج هنا إلى معرفة بأدوار ARIA وحالات وخاصيّات ARIA أيضًا. وهي عبارة عن جداول تحتوي على خاصيّات HTML مدعومة بشكل كامل في JSX وتُمكِّننا من بناء مكوّنات React سهلة الوصول وذات وظيفة عالية الكفاءة.

يمتلك كل نوع من الأدوات المصغرة نمط تصميم خاص ومن المتوقع أن يعمل بطريقة معينة من قبل المستخدمين والعملاء مثل:

نقاط أخرى يجب أخذها بعين الاعتبار

تعيين اللغة

يجب أن تشير إلى لغة نصوص الصفحة لأنّ برامج قراءة الشاشة تستخدم هذا لتحديد إعدادات الصوت الصحيحة:

تعيين عنوان المستند

عيّن عنوان المستند عن طريق العنصر ‎<title>‎ بشكل صحيح ليصف محتوى الصفحة الحالية حيث يضمن ذلك أن يبقى المستخدم على دراية بمحتوى الصفحة الحالي:

نستطيع تعيين العنوان في React باستخدام مكوّن عنوان المستند.

تباين اللون

احرص على امتلاك النص القابل للقراءة تباين ألوان كافٍ ليبقى مقروءًا من قبل المستخدمين ضعيفي البصر:

قد يكون من الممل حساب مجموعات الألوان المناسبة يدويًّا لجميع الحالات في موقعك، لذا تستطيع حساب جميع الألوان باستخدام Colorable.

تتضمّن أدوات aXe و WAVE التي سنشير إليها اختبارات لتباين الألوان وستُبلِّغ عن أخطاء التباين.

إن أردت تمديد قدرات اختبار التباين فبإمكانك استخدام هذه الأدوات:

أدوات الاختبار والتطوير

هنالك عدد من الأدوات التي نستطيع استخدامها لمساعدتنا على إنشاء تطبيقات ويب سهلة الوصول.

لوحة المفاتيح

من أسهل وأهم الاختبارات التي يجب عليك القيام بها هي التحقق ما إذا كان كامل موقعك قابلًا للوصول والاستخدام عن طريق لوحة المفاتيح لوحدها. افعل ذلك عن طريق:

  • إزالة الفأرة.
  • استخدام زر Tab و Shift+Tab للتصفح.
  • استخدام زر Enter لتفعيل العناصر.
  • استخدام الأسهم للتفاعل مع بعض العناصر، مثل القوائم والقوائم المنسدلة.

مساعد التطوير

نستطيع التحقق من بعض ميزات سهولة الوصول بشكل مباشر في شيفرة JSX. عادة تكون هذه التحققات متوفرة مسبقًا في أي مُحرِّر يحتوي على إضافات JSX من أجل أدوار ARIA، والحالات والخاصيّات. لدينا أيضًا إمكانية الوصول للأدوات التالية:

eslint-plugin-jsx-a11y

تزوّدنا هذه الإضافة من أجل ESLint بالتحقق من الأخطاء خاص بمشاكل سهولة الوصول في JSX. تسمح لك العديد من المُحرِّرات بتضمين هذه الموجودات بشكل مباشر في تحليل الشيفرة ونوافذ الشيفرة المصدرية.

يمتلك create-react-app هذه الإضافة مع مجموعة قواعد فرعية مُفعلة. إن أردت تمكين المزيد من قواعد سهولة الوصول فبإمكانك إنشاء الملف ‎.eslintrc في المجلد الجذري للمشروع مع وضع هذا المحتوى بداخله:

{
  "extends": ["react-app", "plugin:jsx-a11y/recommended"],
  "plugins": ["jsx-a11y"]
}

اختبار سهولة الوصول في المتصفح

العديد من الأدوات الموجودة تنفذ اختبارات أداء لسهولة الوصول في صفحات الويب ضمن متصفحك. استخدمها مع أدوات التحقق من سهولة الوصول التي سنشير إليها الآن لأنّها فقط تختبر سهولة الوصول من الناحية التقنية في HTML:

aXe, aXe-core and react-axe

توفّر لنا شركة Deque تقنية تُدعى aXe-core من أجل اختبارات سهولة الوصول التلقائيّة لتطبيقاتنا. تتضمّن هذه الوحدة تكاملًا من أجل Selenium.

إنّ مُحرِّك سهولة الوصول أو aXe هو عبارة عن إضافة للمتصفح لكشف سهولة الوصول مبنية على تقنية aXe-core.

بإمكانك أيضًا استخدام الوحدة react-axe للتبليغ عن موجودات سهولة الوصول بشكل مباشر إلى الكونسول أثناء التطوير وتنقيح الأخطاء.

WebAIM WAVE

أداة تقييم سهولة الوصول للويب، وهي عبارة عن إضافة أخرى للمتصفح.

مستكشفات سهولة الوصول وشجرة سهولة الوصول

شجرة سهولة الوصول هي عبارة عن مجموعة فرعية من شجرة DOM والتي تحتوي على كائنات سهلة الوصول لكل عنصر DOM والتي ينبغي تعريضها إلى تقنية مُساعِدة مثل قارئات الشاشة.

نستطيع بسهولة في بعض المتصفحات مشاهدة معلومات سهولة الوصول لكل عنصر في شجرة سهولة الوصول:

قارئات الشاشة

يجب أن يكون اختبار قارئات الشاشة جزءًا من اختبارات سهولة الوصول لديك.

يرجى الانتباه إلى وجود اختلافات عند الجمع بين قارئات شاشة مختلفة مع متصفحات مختلفة. لذا من الأفضل أن تختبر تطبيقك مع المتصفح الذي يُلائِم قارئات الشاشة التي تختارها.

قارئات الشاشة الأشيع استخدامًا

NVDA في متصفح Firefox

الوصول غير المرئي لسطح المكتب (NonVisual Desktop Access أو اختصارًا NVDA) هو عبارة عن قارئ شاشة مُستخدَم بشكلٍ كبير.

ارجع إلى المقالات التالية لمعرفة أفضل طريقة لاستخدام NVDA:

VoiceOver في متصفح Safari

وهو عبارة عن قارئ شاشة مُدمَج في أجهزة Apple.

ارجع إلى المقالات التالية لمعرفة كيفيّة تفعيل واستخدام VoiceOver:

JAWS في متصفح Internet Explorer

الوصول للوظائف عن طريق الكلام (Job Access With Speech أو اختصارًا JAWS)، وهو قارئ شاشة مُستخدَم على نظام ويندوز.

ارجع إلى هذه الإرشادات حول كيفيّة استخدام JAWS:

قارئات شاشة أخرى

ChromeVox في متصفح Chrome

ChromeVox هو قارئ شاشة مُدمَج على أجهزة Chromebooks ومُتوفِّر كإضافة لمتصفّح Google Chrome.

ارجع إلى الإرشادات التالية حول كيفيّة استخدام ChromeVox:

انظر أيضًا

 مصادر