تخطَّ إلى المقال

القياس نُشِر زمن القراءة 9 د

لماذا يبلّغ axe عن أخطاء تباين في نصٍّ تقرؤه بوضوح

الفحوص الـ 144 نفسها، وبفارق ست دقائق، أعادت 707 عقد تباين خطيرة ثم 618 — والرقم الثاني هو الكذبة الأصغر. لا مفهوم للزمن عند axe: فهو يلاشي نصّك بالنيابة عنك، ويمرّر أي عنصر يجلس عند عتامة (opacity) صفر تمامًا. وكلا الخطأين موجود في الجولات المحفوظة في هذا المستودع، عقدةً عقدة.

باختصار

يقيس axe الإطار الذي يصادف التقاطه. فهو يضرب لون النص في عتامة كل سلف من أسلافه ثم يسطّح الناتج فوق ما خلفه، فيكون عنوانٌ قطع واحدًا بالمئة من تلاشيه هو فعلًا #eaf2f0 فوق #edf5f3 — أي 1.02:1 — بينما العنوان بعد استقراره يكاد يكون أسود ويُقرأ جيّدًا. جولة غير مخفَّضة الحركة على هذا الموقع، 144 فحصًا على 72 مستندًا بعرضين اثنين، أعادت 707 عقد تباين لوني خطيرة عبر 60 مسارًا؛ وبإعادتها بعد ست دقائق تحت prefers-reduced-motion: reduce هبطت خمس عائلات صفحات كاملة إلى صفر تمامًا. وتغيير الشرط نفسه كشف عيبًا حقيقيًّا كانت الجولة الأولى قد أخفته، لأن axe يعيد نتيجة نجاح لأي عنصر يجلس عند opacity: 0 تمامًا.

ما تخرج به

  1. شرط الفحص متغيّر من متغيّرات القياس: أعطت الفحوص الـ 144 نفسها 707 عقد تباين خطيرة عبر 60 مسارًا دون تخفيض الحركة، و618 عبر 36 مسارًا معه، بفارق ست دقائق.
  2. يضرب axe ألفا المقدّمة في عتامة كل سلف ثم يسطّح الناتج فوق الخلفية، فيقيس عنوانًا قطع واحدًا بالمئة من تلاشيه عند 1.02:1 — وهو ليس مخطئًا في البكسلات، لكنه لا يملك مفهومًا للزمن.
  3. العمى نفسه يعمل في الاتجاه المعاكس: العنصر عند عتامة صفر تمامًا يُعامَل كأنه مخفيّ ويُعاد بوصفه ناجحًا، وهذا أخفى 420 عقدة من أصل 612 عقدة لإخفاق حقيقي عند 4.36:1.
  4. قارن الشرطين بدل الجدال حول نتيجة واحدة — ما ينجو من الجولتين شأنه اللون، وما يظهر في واحدة فقط شأنه التوقيت.
  5. انشر رقمًا قابلًا للحركة: خمس مخالفات مذكورٌ بجانبها العنصر والنسبة والتاريخ وإصدار الأداة وشرط الفحص هي قياس، أما الصفر فادّعاء.

axe-core 4.11.0 · axe.js:24321-24345

لماذا يبلّغ axe عن أخطاء تباين في نصٍّ تستطيع قراءته؟

القاعدة تفعل بالضبط ما تقول إنها تفعله. يصعد axe-core من عقدة النص عبر كل سياق تكديس (stacking context) في سلسلة الأسلاف، ويضرب ألفا لون المقدّمة في عتامة كل واحد منها، ويسطّح الناتج فوق ما هو مرسوم خلفه، ثم يسطّح ذلك أخيرًا فوق الأبيض. فالعنوان الذي قطع واحدًا بالمئة من تلاشٍ مدّته ثمانمئة ميلي ثانية ليس حبرًا يكاد يكون أسود على الورق — إنه #eaf2f0 فوق #edf5f3، وهذا الزوج يقيس 1.02:1 في مواجهة اشتراط عند 4.5:1.

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

تفصيلان آخران في القاعدة يصيران مهمّين حين يهبط الرقم قرب الحدّ. يبتر axe النسبة بدل تقريبها — أرضيّة النسبة مضروبةً في مئة، مقسومةً على مئة — واختبار النجاح أكبر تمامًا من الاشتراط، فزوجٌ يُحسب إلى 4.50:1 بالضبط يُخفق. ويعود كلاهما في القسم 06، حيث جلس عيب حقيقي تحت الحدّ بأربعة عشر جزءًا من مئة.

الموضعان في axe-core 4.11.0 حيث تتحوّل لحظةٌ إلى قياس. قُرِئا من النسخة المثبَّتة في node_modules/axe-core/axe.js وقُوبِلا بالوسم v4.11.0 في المصدر.
// lib/commons/color/get-foreground-color.js — الإيجابي الكاذب
function calculateBlendedForegroundColor(fgColor, context, stacks) {
  while (context) {
    if (context.opacity === 1 && context.ancestor) {
      context = context.ancestor; continue;
    }
    fgColor.alpha *= context.opacity;            // الحبر يتلاشى
    fgColor = flattenColors(fgColor, bgColor);   // ثم يُسقَط فوق الخلفية
    context = context.ancestor;
  }
  return fgColor;
}
 
// lib/checks/color/color-contrast-evaluate.js — السلبي الكاذب
if (!isVisibleOnScreen(node)) {
  this.data({ messageKey: 'hidden' });
  return true;                                 // الظهور المُسلَّح يُعدّ نجاحًا
}
 
// lib/commons/dom/visibility-methods.js
function opacityHidden(vNode) {
  return vNode.getComputedStylePropertyValue('opacity') === '0';
}

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

two stored runs · 6 min 24 s apart

ما الذي غيّره تغييرُ شرط الفحص فعلًا؟

تجلس جولتان لهذا الموقع في tests/.golden-runs/، بفارق ست دقائق وأربع وعشرين ثانية في 22 أغسطس 2026. فحصت كلتاهما 144 صفحة: 72 مستندًا عند 1440x900 ثم مرّة أخرى عند 390x844. وحقنت كلتاهما axe-core 4.11.0 من node_modules بدل شبكة توزيع محتوى، محصورًا في وسوم wcag2a وwcag2aa وwcag21a وwcag21aa. والفرق الوحيد بينهما خيار سياق واحد في Playwright، هو reducedMotion مضبوطًا على reduce بدل no-preference.

أبلغت الجولة الأولى عن 707 عقد تباين لوني خطيرة عبر 60 مسارًا — 419 عند عرض سطح المكتب و288 على نافذة الهاتف — في 117 مجموعة نتائج، كلّها القاعدة نفسها عند الأثر نفسه. وأبلغت الثانية عن 618 عبر 36 مسارًا. تحسّنٌ بتسعين عقدة يبدو خطأ تقريب. لكنه، عائلةً عائلة، ليس شيئًا من هذا القبيل.

الفحوص الـ 144 نفسها، بفارق ست دقائق، ولم يتغيّر سوى شرط الفحص. أعداد العقد دقيقة ومأخوذة من الجولتين المحفوظتين؛ وهاتان الجولتان مستثناتان من git، فهي أدلّة محلّية مباشرة لا شيء يستطيع القارئ سحبه من المستودع العلني.
عائلة الصفحات المسارات دون تخفيض الحركة مع تخفيض الحركة
الرئيسية 3 6 0
فهرس المشاريع 3 60 0
فهرس التخصّصات 3 33 0
تفاصيل التخصّص 12 292 0
تواصل 3 118 0
دراسات الحالة 33 192 612
404 3 6 6

انتقلت خمس عائلات من مئات العقد الخطيرة إلى صفر تمامًا. أي 509 عقد ضجيج خالص — نصٌّ يقرؤه الإنسان قراءةً تامّة، التقطه ماسحٌ يمسك ساعة إيقاف في منتصف ظهوره. وذهبت عائلة واحدة في الاتجاه الآخر فارتفعت بمقدار 420. وواحدة لم تتحرّك إطلاقًا.

الضابط الذي تحتاجه الحجّة موجود داخل الجولة نفسها. فمن بين 62 مسارًا من مسارات الموقع نفسه في البيان حينها، وجدت الجولة غير المخفَّضة مخالفات على 60؛ والمساران اللذان لم يكن لديها ما تقوله عنهما هما صفحتا impressum وdatenschutz — المستندان الوحيدان في الموقع بلا نظام ظهور عند الدخول. أما صفحات العروض المُرحَّلة العشر، وبينها عشرون فحصًا، فلم تسهم بأي عقدة من العقد الـ 707 للسبب نفسه: لا شيء فيها يتحرّك.

وعدّت عائلة دراسات الحالة 33 مسارًا حينها بدل 30 التي تعدّها اليوم، لأنها كانت تضمّ عشر دراسات حالة بثلاث لغات إضافةً إلى صفحة شرح مستقلّة أُحيلت منذ ذلك الحين إلى التقاعد وإعادة التوجيه.

والسؤال نفسه — كم من فارقٍ مُبلَّغ عنه يعود إلى الصفحة وكم منه يعود إلى منصّة الاختبار — له جواب بالبكسل أيضًا: أرضيّة الضجيج في لوحة canvas تحت اختبار الانحدار البصري.

axe.js:26148 · 11317 · runs A and B

النصف الآخر: axe يعيد نتيجة نجاح لنصٍّ عند عتامة صفر

أبلغت عائلة دراسات الحالة عن 192 عقدة دون تخفيض الحركة و612 معه. هذا الاتجاه هو المفاجئ، وآليّته سطران من الأداة. يفتتح فحص التباين بالسؤال عمّا إذا كان العنصر مرئيًّا على الشاشة؛ ومُسنَد العتامة يجيب بالنفي عن أي عنصر عتامته المحسوبة صفر تمامًا؛ فيعيد الفحص القيمة true، وهي نجاح.

كل ظهور في هذا الموقع مُسلَّح بحالة بدء عتامتها صفر، تُكتب في التتالي (cascade) فقط ما دام مراقب يمسك العنصر أصلًا. تحت no-preference لم يكن معظم تلك العناصر في دراسة حالة قد دخل إطار العرض أثناء جولة الفحص، فجلست عند صفر تمامًا — مخفيّة، متجاوَزة، محسوبة نجاحات. أما تحت reduce فلا تُكتب حالة البدء أصلًا، فقُيّمت العقد الـ 612 كلّها، وأخفقت كلّها.

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

ولهذا فإن الصياغة الشائعة — أن axe يعطي إيجابيات كاذبة على الحركة — نصف حقيقة، والنصف الغائب هو المكلف. فقاعدةٌ بلا مفهوم للزمن مخطئة في الاتجاهين معًا: تخترع إخفاقات على نصٍّ في طريقه إلى الظهور، وتعذر إخفاقات على نصٍّ لم يصل بعد.

derived · linear fade · 800 ms reveal

كم من التلاشي إخفاقٌ مضمون؟

نقطة العبور قابلة للحساب لأي زوج، وتستحقّ أن تحسبها لزوجك أنت، لأنها تخبرك بأي جزء من كل انتقال في موقعك غير قابل للفحص. ادمج الحبر فوق الورق عند كل قيمة ألفا، وطبّق معادلة الإضاءة النسبية في WCAG، وابتر كما يبتر axe.

ولرموز هذا الموقع اللونية يُعبَر حدّ 4.5:1 عند عتامة 0.5521، وحدّ النص الكبير 3:1 عند 0.4271. تحت هاتين النقطتين كل إطار مخالفة خطيرة مُبلَّغ عنها للمعيار SC 1.4.3؛ وفوقهما ينجح العنصر نفسه، دون أن يتغيّر في الصفحة شيء سوى مدّة انتظار الماسح.

عتامة 0.0125 1.02:1
عتامة 0.30 2.05:1
عتامة 0.50 3.76:1
عتامة 0.5521 — نقطة العبور 4.50:1
عتامة 0.70 7.71:1
بعد الاستقرار، عتامة 1 20.36:1
التباين المُبلَّغ عنه لحبر الصفحة على ورق الصفحة، عبر تلاشٍ إلى الظهور.مُشتقّ لا مقيس: #040504 مدموجًا فوق #edf5f3 عند كل قيمة ألفا، مبتورًا كما يبتر axe. والأعمدة بمقياس نسبةً إلى 20.36:1 بعد الاستقرار.

على ظهور مدّته ثمانمئة ميلي ثانية، يقضي التلاشي الخطّي نحو 442 ms تحت حدّ النص العادي ونحو 342 ms تحت حدّ النص الكبير. عامِل هذه الميلي ثوانٍ رتبةَ مقدار لا أكثر — فكل ظهور هنا مُخفَّف بمنحنى، والزمن الحقيقي تحت الحدّ يختلف قسمًا عن قسم. نقاط عبور العتامة دقيقة، أما المُدد فتقريبية.

ثم تجعل منصّة الاختبار الضجيج حتميًّا بحكم بنائها. فهي تمرّر كل مستند بخطوات بارتفاع إطار العرض بفاصل 60 ms، ثم تعود إلى الأعلى، وتنتظر 120 ms، ثم تحقن axe. والعنصر الذي دخل الرؤية في الخطوة الأخيرة يكون قد قطع نحو 180 ms من تلاشٍ مدّته ثمانمئة ميلي ثانية حين يبدأ axe ببناء شجرته — أي أقلّ بكثير من عبور الخمسة والخمسين بالمئة، ويُبلَّغ عنه إخفاقًا خطيرًا لهذا السبب وحده.

وأنقى حالة في المجموعة هي عنوان مُحمِّل الصفحة. بعد استقراره هو #040504 فوق #21f1a8: أي 13.81:1، أكثر من ثلاثة أضعاف ما تطلبه القاعدة. يتلاشى خلال 300 ms بعد ثبات مدّته 900 ms، والجولة غير المخفَّضة التقطته هناك — ست عقد، وثلاث صفحات رئيسية، وسطح المكتب وحده. أما تحت reduce فهو صفر في كل جولة محفوظة. لم يتغيّر في الصفحة شيء. تغيّر الإطار وحده.

three guarantees · one gate that checks

هل الفحص تحت تخفيض الحركة مجرّد إخفاء للمشكلة؟

كان سيكون كذلك لو أن صفحة الحركة المخفَّضة هي الصفحة المتحرّكة مجمَّدةً عند إطارها الأول. تلك هي النسخة من هذه التقنية التي تستحقّ الريبة: تشغّل التفضيل، وتراقب العدد يهبط، وتنشر الرقم الأصغر ولا تقول شيئًا عن الشرط. والسؤال الذي يفصل بين الاثنين هو: هل حالة الاستقرار مضمونة، وهل يتحقّق منها شيء مستقلّ؟

في هذا الموقع هي مضمونة بثلاث طرق لا يعتمد بعضها على بعض، وبوّابة ثانية تؤكّد النتيجة بدل أن تثق بها.

  1. حالة البدء لا تُسلَّح أصلًا لا تكتب بيئة التشغيل السمة التي تخفي الظهور إلا حين يكون تخفيض الحركة مُطفأً. وتحت reduce لا تدخل حالة البدء المخفيّة التتاليَ إطلاقًا، فلا يبقى شيء في منتصف الانتقال ليُجمَّد.
  2. كل هدف يُعلَّم داخلًا منذ البداية يعمل مُثبِّت الظهور بخيار settleImmediately، فيطبّق الإطار الأخير لكل حركة دفعةً واحدة. ويسمّي عقد الحركة ذلك حالة النهاية، وهو الجواب المطلوب لأي تأثير تكون نتيجته هي المحتوى نفسه.
  3. ورقة الأنماط تفرض الوضع المستقرّ على أي حال كل واحدة من أوراق الأقسام الخمس الحاملة لهذا النمط تضبط أيضًا العتامة الكاملة وانعدام التحويل داخل استعلام وسائط لتخفيض الحركة، تحسّبًا لحالة تشغيل التفضيل في منتصف الجلسة.
  4. طبقة التصفير تُلاشي المُدد تأخذ base/reset.css خاصّيتَي animation-duration وtransition-duration إلى 0.01ms تحت التفضيل، وتفعل ذلك في طبقة التصفير تحديدًا كي لا يستطيع شيء أدنى منها أن يتفوّق عليها بالخصوصية.
  5. بوّابة ثانية تثبت أن لا شيء مخفيّ تمشي بوّابة إمكانية الوصول الأقدم على كل خطّاف متحرّك وعنصر نصّ مقسوم وسطر مولَّد في صفحة الحركة المخفَّضة، وتؤكّد أن لا شيء منها عند رؤية مخفيّة أو عتامة صفر أو مقصوص. والتأكيد هو أن عدد المحتوى المخفيّ صفر.
ما يضمنه شرط reduce في هذا الموقع، والتأكيد الذي يبقيه صادقًا.

وهناك حجّة معيارية أيضًا، وهي الأقوى. فالاستثناء العَرَضي في SC 1.4.3 يعفي النص غير المرئي لأحد، وعنوانٌ عند واحد بالمئة من العتامة ليس مرئيًّا لأحد. وقياس حالة الاستقرار ليس تهرّبًا من الاشتراط؛ بل هي الحالة التي يدور حولها الاشتراط، ولم تكن تلك النتيجة يومًا ممّا يطلبه المعيار.

ووثيقة إمكانية الوصول الخاصّة بهذا الموقع تشدّ في الاتجاه الآخر، والتوتّر يستحقّ التسمية لا التمليس. يقول الالتزام C-4 إن اللون الذي يتحرّك يجب أن يبلغ حدّه عند كل نقطة تُؤخذ عيّنتها من الانتقال، لا عند طرفيه فقط — وهذا، إن أُخذ حرفيًّا، يجعل 1.02:1 إخفاقًا حقيقيًّا. والتمييز الجاري فعليًّا هو بين حالة يكون القارئ فيها، مثل تلاشٍ لوني متقاطع مدفوع بالتمرير تُؤخذ عيّنته كل 10 px، وحالة لا يدركها أحد نصًّا قطّ.

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

project-detail.css:37-46 · not-found.css:53

ما الذي نجا من التصحيح، وكم كلّف إصلاحه

ثلاث نتائج في هاتين الجولتين كانت عن اللون لا عن التوقيت، والسبيل إلى معرفة ذلك كان مقارنة الشرطين. وواحدة منها كانت كبيرة وحقيقية وأكبر بـ 420 عقدة ممّا قالته الجولة الأولى.

ولون تمييز دراسات الحالة هو القطع من أخضر الموقع الذي يبقى مقروءًا على الورق، حيث يقيس 4.82:1. لكن صفحة دراسة الحالة تطبعه على سطح بطاقتها الخاصّ، #e2eae7، وفوق تلك الأرضية يقيس الزوج نفسه 4.36:1 — تحت الحدّ بأربعة عشر جزءًا من مئة، عبر 612 عقدة وكل مستند دراسة حالة. وهو بالضبط نوع الفوات الذي لا يراه المصمّم أبدًا ويراه الماسح دائمًا.

النتائج الثلاث التي نجت من تغيير شرط الفحص. والصفّ الأوسط هو الضابط: لون ثابت في صفحة لا يتحرّك فيها شيء أعاد العقد الست نفسها تحت الشرطين.
النتيجة الزوج والموضع الحدّ المقيس، ثم المُصلَح إليه
لون تمييز دراسات الحالة نصًّا للمتن #0c7a55 على البطاقة #e2eae7، 612 عقدة، كل مستند دراسة حالة 4.5:1 4.36:1، ثم 5.55:1
علامة 404 المائية حبر الصفحة عند 10 بالمئة فوق الورق، 6 عقد على 3 مسارات 3:1 عند 70px 1.25:1، ثم 3.12:1
عنوان الشهادة، نصفه المميَّز #21f1a8 على #edf5f3، 5 عقد على 3 مسارات 3:1 1.33:1، دون إصلاح

إصلاح دراسة الحالة سطر واحد: خمسة عشر بالمئة من حبر الصفحة نفسه ممزوجًا في لون التمييز، وهو ما يأخذه إلى 5.55:1 على البطاقة و6.13:1 على الورق ولا يغيّر شيئًا يستطيع أحد إدراكه. أما علامة 404 المائية فانتقلت من 10 بالمئة حبرًا إلى 44 بالمئة، أي 3.12:1 في مواجهة حدّ 3:1 الذي ينطبق عند 70 بكسل، وتبقى تابعةً بوضوح للعنوان المجاور لها.

وأُصلح كلاهما خلال ثماني دقائق من الجولة التي وجدتهما. وأبلغت الجولة المحفوظة التالية، بعد سبع دقائق وثمانٍ وخمسين ثانية، عن صفر، ثم ثبت العدد عند صفر تسع جولات متتالية على مدى يومين قبل أن ينقله قرارٌ إلى خمسة.

وتستحقّ صفحة 404 جملة أخرى، لأنها أنظف ضابط في المجموعة. لا شيء في تلك الصفحة يتحرّك، فأبلغت عن ست عقد تحت الشرطين ولم تُكتشف بتغيير أي شيء. والحجم الحقيقي لعيب دراسات الحالة وحده هو ما توقّف على الشرط — 192 مُبلَّغًا عنها، و612 حقيقية.

والمستندات التي توزّعت عليها تلك العقد الـ 612 هي دراسات الحالة نفسها — عشرة أعمال، لكلٍّ منها قياساته.

published-measurements.json:33, 56-62

لماذا يقول الرقم المنشور خمسة لا صفرًا؟

يضع عنوان قسم الشهادة نصفه الثاني بلون التمييز الخاصّ بالموقع، #21f1a8، فوق الأرضية الفاتحة التي بُني عليها ذلك القسم. وهذا يقيس 1.33:1 حيث ينطبق 3:1. أما الرمز الموجود لهذه الحالة بالذات — لون التمييز مُعتَّمًا حتى يصير مقروءًا على الورق — فيقيس 3.23:1، وحلّ معادلة التباين لتلك الأرضية يحدّ لون التمييز عند #0aa16c، وهو غير قابل للتمييز عن الرمز الذي كان يُشحن أصلًا.

وعُرِض القياس على صاحب الموقع أولًا فطلب لون التمييز رغم ذلك. لذلك يُشحَن قرارًا مرفقًا برقمه لا ضبطًا: خمس عقد، وعنصر واحد، وثلاثة مسارات، ونافذتا عرض. وهو غير مشمول بأي استثناء أيضًا — فبند الشعار يغطّي شعارًا أو اسم علامة، وعنوان قسم بلون العلامة نصٌّ كأي نص.

  • 144 فحصًا 72 مستندًا بعرضين اثنين، وفق WCAG 2.1 المستويين A وAA
  • 5 مخالفات عنصر واحد، وثلاثة مسارات، ونافذتا عرض
  • 4.11.0 إصدار axe-core محقون من node_modules، لا من شبكة توزيع محتوى
  • 0 جولات قارئ شاشة لم يُجرَ هنا أي فحص يدوي قطّ
السجلّ المنشور كما ينصّ عليه contracts/published-measurements.json. وكل حقل يُعاد تأكيده في مقابل النسخة الظاهرة بثلاث لغات في كل جولة تحقّق.

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

وللمطابِق حدّ حادّ يستحقّ القول صراحةً. فهو لا يختبر إلا أول عقدة مُخفِقة من كل مجموعة نتائج، فعذرُ مجموعةٍ عذرٌ لكل عقدة فيها. وما يحدّ من هذه الخشونة هو الرقم: تطبع البوّابة، وينشر الموقع، مجموع عقد كل ما جرى عذره، والمجموع خمسة. ولا مجال خلفه لشيء آخر كي يختبئ.

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

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

144 scans · 0 keystrokes

ما الذي لا يخبرك به فحصٌ أخضر رغم كل شيء

الماسح يقرأ الوسوم. لا يستطيع ضغط Tab، ولا أن يخبرك بأن عنوانًا خاطئ، ولا أن يعرف أن عنصر تحكّم غير قابل للوصول عمليًّا. وما ينشره هذا الموقع هو عدد مخالفات آلية، وهو ليس أبدًا كلمة سهل الوصول.

وللقاعدة موضع الحديث بقعة عمياء مقابلة على الجانب الآخر من الصفحة نفسها. تقول قائمة الحدود عند Deque نفسها إن قاعدة colour-contrast لا تبلّغ عن نصٍّ يحجبه عنصر آخر — وكل سطر من ظهورات هذا الموقع يغطّيه شريط معتم ينمحي. فطوال الستمئة ميلي ثانية التي يكون فيها ذلك الشريط على الشاشة يكون النص غير مرئي حرفيًّا ويسجّل axe نجاحًا؛ وطوال الثمانمئة ميلي ثانية التي يجري فيها التلاشي يكون النص مقروءًا لإنسان عند ستين بالمئة ويسجّل axe إخفاقًا خطيرًا. وكلا الخطأين يأتي من الفكرة الغائبة نفسها.

شغّل الجولة مرّتين
مرّة تحت prefers-reduced-motion: reduce ومرّة بدونه، ثم قارن الاثنتين. ما ينجو من الجولتين شأنه اللون. وما يظهر في واحدة فقط شأنه التوقيت.
تحقّق من الحالة التي تجلس عندها ظهوراتك
العتامة صفر تمامًا تُمرَّر بوصفها مخفيّة. والفحص الذي لا يُطلق ظهوراتك أبدًا لا يخبرك أنها سليمة — إنه لا يخبرك عنها شيئًا على الإطلاق.
احسب نقطة العبور الخاصّة بك
ادمج حبرك فوق ورقك وجد قيمة ألفا التي يعبر عندها 4.5:1. تلك النسبة هي مقدار ما لا يستطيع الماسح قراءته بصدق من كل انتقال في موقعك.
لا تصلح نتيجة بتغيير الحركة أبدًا
إن كانت الألوان المستقرّة تنجح، فالنتيجة عن ساعة إيقاف الماسح. وتقصير مدّة كي يصير تقرير أخضر ينقل العيب بدل أن يزيله.
انشر عدد عقد كل ما تعذره
سماحٌ مسمّى بجانبه رقم لا يستطيع أن ينمو بهدوء، والذي يتوقّف عن المطابقة ينبغي أن يُسقِط البناء بدل أن يجلس في الملف دون أن ينتبه إليه أحد.
كيف تميّز أثر الفحص من العيب دون جدال حوله.

وحدّان آخران ينتميان إلى النفس نفسه. فالمسار الذي يخفق في التحميل لا ينتج أي نتائج، وإن كان خارج المجموعة المحتسبة فهو لا يُسقِط الجولة كذلك — فحصت إحدى الجولات المحفوظة 143 صفحة بدل 144 لأن مسار عرض توضيحي انتهت مهلته عند ثلاثين ثانية. والرقم المنشور دليل على بناء واحد في تاريخ واحد: فمجموعة المسارات هنا تغيّرت بالفعل منذ 24 أغسطس 2026، ولهذا يقول السجلّ نفسه إن على المرء إعادة القياس قبل النشر.

وفي التباين، الموقع القديم هو المثال المضادّ المفيد. أعادت جولة axe عليه عبر 40 مسارًا بنافذتَي عرض 379 عقدة مخالفة، كلّها تباين لوني، من أربعة أزواج لونية فريدة فقط بين 1.26:1 و1.47:1 — لون التمييز نفسه على أربع أرضيات تكاد تكون بيضاء. لا ضجيج منتصف ظهور إطلاقًا، لأن تلك المنصّة كانت تقرأ الصفحة بخطوات مقدارها 600 بكسل وتنتظر 800 ms للاستقرار قبل الفحص، فكانت مداخلها قد انتهت. الأداة نفسها، والقاعدة نفسها، وضجيج مختلف اختلافًا هائلًا. فإجراء الفحص متغيّر، وينبغي أن يُنشر بجانب الرقم الذي أنتجه.

وإن كان في تقرير عن بنائك أرقام لا يستطيع أحد تفسيرها، فتلك عادةً مشكلة شرط لا مشكلة لون — لنتحدّث فيها.

أسئلة

هل نتيجة التباين في منتصف الحركة خلل في axe؟

لا، وتسميتها كذلك تُفوِّت المغزى. فقد قاس axe الإطار قياسًا صحيحًا: العنوان الذي قطع واحدًا بالمئة من تلاشيه هو فعلًا #eaf2f0 فوق #edf5f3، وذلك فعلًا 1.02:1. الأداة لا تملك مفهومًا للزمن، فلا تستطيع أن تعرف أن الإطار عابر. ويسجّل متعقّب المشكلات عند Deque نفسها قول أحد المشرفين بذلك في 2019 — فما لم يُترك فحص المحتوى خارج إطار العرض المرئي كلّيًّا، ليس هناك الكثير ممّا يمكن فعله. والإصلاح في كيفية تشغيلك للفحص، لا في القاعدة.

هل تشترط WCAG فعلًا تباينًا على نصٍّ في طور التلاشي إلى الظهور؟

لا. الاستثناء العَرَضي في SC 1.4.3 يعفي النص غير المرئي لأحد، والنص في منتصف تلاشيه عند واحد بالمئة من العتامة ليس مرئيًّا لأحد. وقياس حالة الاستقرار ليس تهرّبًا من المعيار؛ بل هي الحالة التي يدور حولها المعيار. أما الاستثناء الذي لا ينطبق فهو استثناء الشعار، وهو يغطّي شعارًا أو اسم علامة — وعنوان قسم بلون تمييز العلامة نصٌّ كامل.

هل الفحص تحت prefers-reduced-motion مجرّد إخفاء للمشكلة؟

كان سيكون كذلك لو أن صفحة الحركة المخفَّضة هي الصفحة المتحرّكة مجمَّدة. وهي ليست كذلك في هذا الموقع، وبوّابة منفصلة تثبت ذلك: تمشي منصّة إمكانية الوصول الأقدم على كل خطّاف متحرّك وعنصر نصّ مقسوم وسطر مولَّد في صفحة الحركة المخفَّضة وتؤكّد أن لا شيء منها مخفيّ أو عند عتامة صفر أو مقصوص. وتحت reduce لا تكتب بيئة التشغيل أبدًا السمة التي تسلّح حالة البدء المخفيّة، فلا يوجد هناك ما يُجمَّد.

كيف أعرف أن الرقم المنخفض ليس مجرّد فحص لم ينظر؟

في الغالب لا تعرف، وهذا هو النصف المزعج من الأمر. والجولات هنا تُظهره وهو يحدث: دون reduce أبلغت صفحات دراسات الحالة عن 192 عقدة تباين، ومعه عن 612. والعقد الـ 420 الغائبة كانت جالسة عند عتامة صفر تمامًا، وهو ما يعامله axe إخفاءً ويمرّره. فإن كان الفحص لا يبلغ الحالات التي يراها زوّارك، فالرقم الأصغر ليس خبرًا أفضل — إنه خبر أقلّ.

ما الذي لم يغيّره شرط الفحص؟

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

المصادر

مقيس في هذا المستودع

  • contracts/published-measurements.json كتلة إمكانية الوصول: الأداة، والإصدار، والأمر، والتاريخ، والمعيار، وعدد المستندات وعدد الفحوص، وعدد المخالفات، وشرط الفحص، وقائمة صريحة بما لم يُقَس.
  • tools/golden/site-a11y.mjs الجولة نفسها — نافذتا عرض، والسطر الواحد الذي يضبط تفضيل الحركة، وتمريرة التمرير، ونسخة axe المحقونة، والحدّ الذي تفرضه، والسماح المسمّى الوحيد الذي يُسقِط الجولة حين يتوقّف عن المطابقة.
  • src/styles/sections/project-detail.css لون التمييز مقيسًا عند 4.82:1 على الورق و4.36:1 على بطاقة دراسة الحالة، والمزج ذو السطر الواحد الذي يأخذه إلى 5.55:1 و6.13:1.
  • src/styles/sections/not-found.css علامة 404 المائية مقيسةً عند 1.25:1 ومضبوطةً على 3.12:1 عند 44 بالمئة حبرًا، في الصفحة الوحيدة التي لا حركة فيها إطلاقًا.
  • src/styles/sections/home-certificate.css عنوان الشهادة عند 1.33:1، والرمز البديل عند 3.23:1، والحدّ الأقصى الذي تضعه معادلة التباين على تلك الأرضية، والقرار المسجَّل مع كلفته.

مُقابَل بـ

Alaa Abbod

بقلم

علاء عبّود

مطوّر إبداعي — هيرنه، ألمانيا

مصمّم ومطوّر يبني مواقع ويب سهلة الوصول وتطبيقات جوال ومتاجر إلكترونية وهويات بصرية كعملٍ واحد، وبيديه. هذا الموقع منشور بالإنجليزية والألمانية والعربية من مصدر واحد، ومن هناك جاء معظم هذه الأسئلة.

Alaa Abbod

هل رقم إمكانية الوصول عندك قياس أم ادّعاء؟

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

من فضلك أدر جهازك،
هذا الموقع مبني عموديًا.