EduFlow

الوحدة 4 · التصميم البصري والمحتوى

التكبير وإعادة التدفّق وحجم الهدف والحركة

17 دقراءة 4 دبيئة تجريب الكود

الدرس في لمحة

حافظ على قابلية استخدام Ticketly عند تكبير 400% ومع تباعد نصي مخصّص، واضبط أحجام أهداف اللمس كما ينبغي، واحترم المستخدمين الذين يحتاجون إلى حركة أقل باستخدام prefers-reduced-motion وأزرار الإيقاف المؤقت.

  1. 1التكبير وإعادة التدفّق
  2. 2حجم الهدف من جديد
  3. 3الحركة: أوقفها مؤقتًا، واحترم التفضيل

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

تقرأ مها Ticketly بتكبير 400% على حاسوب محمول بشاشة 13 بوصة. عند هذا التكبير، يصبح عرض نافذة متصفّحها فعليًا 320 بكسل CSS. بطاقات المهرجان، المصفوفة في ثلاثة أعمدة ثابتة بعرض 320px، تجبرها على التمرير أفقيًا مع كل سطر نص، وهذا يعني عند ذلك التكبير أنها تفقد موضعها باستمرار. وفي الوقت نفسه يمرّر الشريط المتحرّك في الصفحة الرئيسية أسماء الفنانين إلى ما لا نهاية، فيصاب زميلها توم، الذي يعاني اضطرابًا دهليزيًا (vestibular disorder) يؤثّر في التوازن، بصداع خلال دقيقة.

يتناول هذا الدرس ما يحدث حين يغيّر الناس حجم صفحتك، وحين تتحرّك صفحتك من تلقاء نفسها.

التكبير وإعادة التدفّق

ثلاثة معايير تعمل معًا:

  • 1.4.4 Resize Text ‏(AA): يمكن تكبير النص إلى 200% دون فقدان محتوى أو وظيفة.
  • 1.4.10 Reflow ‏(AA): عند عرض 320 بكسل CSS، يتّسع المحتوى دون تمرير أفقي. (نافذة بعرض 1280px عند تكبير 400% عرضها 320 بكسل CSS.) جداول البيانات والخرائط والمخطّطات مستثناة، لأنها تحتاج إلى بُعدين.
  • 1.4.12 Text Spacing ‏(AA): لا ينكسر شيء حين يفرض المستخدمون ارتفاع سطر قدره 1.5، والمسافة بين الفقرات إلى 2em، والمسافة بين الحروف إلى 0.12em، والمسافة بين الكلمات إلى 0.16em، كما يفعل كثير من ذوي عُسر القراءة عبر إضافة للمتصفّح.

إن كنت تبني بأسلوب متجاوب، فقد قطعت معظم الطريق. والمتّهمان المعتادان هما العروض الثابتة والارتفاعات الثابتة. شبكة البطاقات في Ticketly:

before.css
.cards {
  display: grid;
  grid-template-columns: repeat(3, 320px);
  gap: 16px;
}
.card h3 {
  height: 24px;      /* clips the title when text spacing grows */
  font-size: 18px;   /* doesn't follow the user's default font size */
}
after.css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 1rem;
}
.card h3 {
  font-size: 1.125rem;
}

الجزء min(100%, 16rem) مهم: في viewport عرضه 320px قد يظلّ عمود بعرض 16rem ‏(256px يُضاف إليها الحشو) يفيض، وmin() تسمح للعمود بالانكماش إلى عرض الحاوية. وضبط النص بوحدة rem يعني أنه يكبر حين يضبط المستخدم حجم خط افتراضيًا أكبر في متصفّحه، وهي حالة لا يغطّيها التكبير وحده.

لاختبار إعادة التدفّق، اضبط نافذة المتصفّح على عرض 1280px وكبّر إلى 400%، أو استخدم الوضع المتجاوب في أدوات المطوّر بعرض 320px. مرّر عموديًا عبر الصفحة كلها. أي شريط تمرير أفقي، أو نص متداخل، أو زر مقطوع، خطأ.

حجم الهدف من جديد

قابلت معيار 2.5.8 Target Size (Minimum) في درس WCAG 2.2 ومبادئ POUR والقانون: أهداف المؤشّر لا تقلّ عن 24 × 24 بكسل CSS، أو تكون حول الأهداف الأصغر مسافة كافية. كان عدّاد الكمية في Ticketly يستخدم أزرار أيقونات بحجم 16px متلاصقة. والإصلاح بالحشو، لا بتكبير الأيقونات:

CSS
.stepper button {
  min-inline-size: 2.75rem; /* 44px, comfortably above the 24px minimum */
  min-block-size: 2.75rem;
}

واطمح إلى ما هو أعلى من الحدّ الأدنى للأفعال الرئيسية على شاشات اللمس. إرشادات منصّتي Apple وGoogle تقترح نحو 44 إلى 48 بكسل، وسيشكرك المصابون بالرعاش.

الحركة: أوقفها مؤقتًا، واحترم التفضيل

الحركة تسبّب مشكلتين مختلفتين. المحتوى الذي يتحرّك من تلقاء نفسه ينافس على الانتباه، وهذا عائق حقيقي لذوي اضطرابات الانتباه ولأي شخص يقرأ ببطء. والحركة الكبيرة، مثل الـ parallax أو الانتقالات المكبِّرة أو اللوحات المنزلقة، قد تثير الدوار والغثيان لدى المصابين باضطرابات دهليزية.

تعالج WCAG المشكلة الأولى بمعيار 2.2.2 Pause, Stop, Hide ‏(A): كل ما يبدأ تلقائيًا، ويتحرّك (أو يومض أو يتمرّر) أكثر من خمس ثوانٍ، ويظهر إلى جانب محتوى آخر، يحتاج إلى طريقة لإيقافه مؤقتًا أو إيقافه أو إخفائه. ويمنع معيار 2.3.1 Three Flashes or Below Threshold ‏(A) المحتوى الذي يومض أكثر من ثلاث مرات في أي ثانية واحدة، إلا إن كانت الومضات صغيرة وخافتة بما يكفي لتبقى دون عتبات الوميض، لأن الوميض قد يثير نوبات صرع.

وللمشكلة الثانية، تتيح أنظمة التشغيل للمستخدمين طلب تقليل الحركة (في macOS: ‏Accessibility ثم Display ثم Reduce motion؛ وفي Windows: ‏Accessibility ثم Visual effects ثم إيقاف Animation effects)، ويستطيع CSS قراءة هذا الإعداد:

ticketly/motion.css
.marquee__track {
  animation: scroll-names 20s linear infinite;
}
.marquee--paused .marquee__track {
  animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
  .marquee__track {
    animation: none;
  }
  .card {
    transition: opacity 0.2s; /* a fade instead of a slide */
  }
}
HTML
<button type="button" class="marquee-toggle" aria-pressed="false">Pause animation</button>

زر الإيقاف المؤقت ما زال ضروريًا: كثيرون ممّن تزعجهم الحركة لا يجدون إعداد النظام أبدًا، ومعيار 2.2.2 يشترط عنصر تحكّم في الصفحة. و«تقليل» الحركة لا يعني بالضرورة «انعدامها». التلاشي القصير أو تغيّر اللون نادرًا ما يسبّب مشكلة؛ الحركة الكبيرة عبر الشاشة هي التي تسبّبها.

يمرّ إعداد تقليل الحركة في نظام التشغيل عبر الـ media query ‏prefers-reduced-motion ليحذف الحركات الكبيرة افتراضيًا، بينما يتيح زر إيقاف مؤقت في الصفحة لأي شخص إيقاف الشريط المتحرّك؛ ومعًا يغطّيان من ضبطوا التفضيل ومن لم يضبطوه. النظام: تقليل الحركة prefers-reduced-motion زر الإيقاف المؤقت animation-play-state صفحة هادئة
طبقتان للتحكّم في الحركة

الحركات التي تديرها JavaScript تحتاج إلى الفحص نفسه. تخبرك window.matchMedia('(prefers-reduced-motion: reduce)').matches بالتفضيل الحالي، ويمكنك الاستماع إلى حدث change الخاص بها لتستجيب إن غيّره المستخدم والصفحة مفتوحة.

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

أهم النقاط

  • يجب أن يُعاد تدفّق المحتوى داخل viewport عرضه 320 بكسل CSS، وهو عرض نافذة بعرض 1280px عند تكبير 400%، دون تمرير أفقي.
  • اضبط أحجام النصوص بوحدة rem، وتجنّب الارتفاعات الثابتة لحاويات النص، ولا تعطّل أبدًا التكبير باللمس (pinch zoom) في وسم viewport.
  • كل ما يتحرّك من تلقاء نفسه لأكثر من خمس ثوانٍ يحتاج إلى طريقة لإيقافه مؤقتًا أو إيقافه أو إخفائه (2.2.2).
  • ضع الحركة غير الضرورية داخل فحص prefers-reduced-motion، واستبدل الحركة الكبيرة بتلاشٍ أو بلا شيء.

قراءات إضافية

تحقّق من فهمك

4 أسئلة

السؤال 1 من 4

لماذا يُختبر معيار 1.4.10 Reflow عند عرض 320 بكسل CSS؟

السؤال 2 من 4

أيّ وسم viewport يخالف معيار WCAG ‏1.4.4 Resize Text؟

HTML
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
السؤال 3 من 4

يمرّر الشريط الرئيسي في Ticketly أسماء الفنانين تلقائيًا في شريط متحرّك (marquee) إلى ما لا نهاية. ماذا تشترط WCAG 2.2 في المستوى A؟

السؤال 4 من 4

أيّ CSS يحترم إعداد تقليل الحركة لدى المستخدم في البطاقات المنزلقة في Ticketly؟

تدريب

بيئة تجريب الكود

هدّئ الصفحة الرئيسية وامنحها مرونة

تمرّر الصفحة الرئيسية في Ticketly أسماء الفنانين إلى ما لا نهاية، وتفرض شبكة من ثلاثة أعمدة لبطاقات ثابتة العرض 320px، وتستخدم أزرار عدّاد بحجم 16px. أصلحها:

  1. أضِف كتلة @media (prefers-reduced-motion: reduce) توقف حركة .marquee__track.
  2. أضِف زرًّا يحتوي نصه “Pause” يوقف الشريط المتحرّك مؤقتًا عند نقره (مثلًا باستخدام animation-play-state: paused).
  3. اجعل شبكة .cards يُعاد تدفّقها فلا يتمرّر شيء أفقيًا في viewport ضيّق (عرض المعاينة نحو 300px فقط).
  4. اجعل زرّي .stepper كليهما لا يقلّان عن 24 × 24 بكسل CSS.
<section class="marquee" aria-label="Artists">
  <div class="marquee__track">Nour Quartet · The Saltmarsh Band · Layla &amp; the Tides · Harbour Brass · DJ Marwa</div>
</section>

<div class="cards">
  <article class="card">
    <h3>Friday pass</h3>
    <p>SAR 180</p>
    <div class="stepper">
      <button type="button" aria-label="Fewer Friday passes">−</button>
      <span>1</span>
      <button type="button" aria-label="More Friday passes">+</button>
    </div>
  </article>
  <article class="card"><h3>Saturday pass</h3><p>SAR 180</p></article>
  <article class="card"><h3>Weekend pass</h3><p>SAR 320</p></article>
</div>جارٍ تحميل المحرّر…

Ctrl/⌘ + Enter للتشغيل · يعمل في بيئة معزولة داخل متصفّحك. لا شيء يغادر جهازك.

المعاينة

الـ console

(لا مخرجات)

الفحوص

  • كتلة prefers-reduced-motion: reduce توقف حركة الشريط المتحرّك
  • زر Pause يوقف الشريط المتحرّك مؤقتًا
  • لا تتمرّر الصفحة ولا شبكة البطاقات أفقيًا
  • زرّا العدّاد كلاهما لا يقلّان عن 24 × 24 بكسل