دسترس‌پذیری وب و کاهش حرکت در سایت های انیمیشن محور

دسترس‌پذیری و احترام به کاهش حرکت

⏱ زمان مطالعه: حدود ۸ دقیقه

به آخرین درس این نقشهٔ راه رسیدیم. تا اینجا یاد گرفتیم صفحهٔ سینمایی را چطور طراحی، بسازیم و سریع کنیم. حالا می‌رسیم به چیزی که اغلب کاملاً نادیده گرفته می‌شود و در عمل، مرز بین کار آماتور و حرفه‌ای است.

یک واقعیت ناخوشایند: صفحه‌های پر از انیمیشن، برای بخشی از کاربران فقط «کمی اذیت‌کننده» نیستند — عملاً غیرقابل‌استفاده‌اند. کسی که اختلال دهلیزی دارد، با پارالاکس شدید دچار سرگیجه و حالت تهوع می‌شود. کسی که فقط با کیبورد کار می‌کند، در بخش پین‌شده گیر می‌افتد. و کسی که از صفحه‌خوان استفاده می‌کند، از متن شکسته‌شده به کلمات، چیز مفهومی نمی‌شنود.

دسترس‌پذیری وب و کاهش حرکت در سایت های انیمیشن محور

کاهش حرکت: مهم‌ترین تنظیمی که نمی‌شناسی

هر سیستم‌عامل مدرن یک تنظیم دارد به‌نام «کاهش حرکت». کاربر آن را روشن می‌کند و مرورگر این خواسته را به سایت اعلام می‌کند. این یک درخواست صریح از سوی کاربر است، نه یک پیشنهاد.

چه کسانی این را روشن می‌کنند؟ افراد مبتلا به میگرن، کسانی با اختلال دهلیزی یا حساسیت حرکتی، افراد مبتلا به صرع حساس به نور، و خیلی‌ها که فقط از انیمیشن خوششان نمی‌آید. جمعیت قابل‌توجهی است.

پیاده‌سازی درست، در سه لایه

لایهٔ CSS:

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
}

لایهٔ جاوااسکریپت:

const mq = matchMedia('(prefers-reduced-motion: reduce)');

function setupMotion(){
  if (mq.matches){
    ScrollTrigger.getAll().forEach(t => t.kill());
    gsap.set('[data-reveal], .panel, .w__in', { clearProps:'all' });
    if (lenis) { lenis.destroy(); lenis = null; }
    return;
  }
  initAnimations();
}
setupMotion();
mq.addEventListener('change', () => location.reload());

لایهٔ محتوا: این مهم‌ترین و فراموش‌شده‌ترین بخش است. وقتی انیمیشن‌ها را خاموش می‌کنی، باید مطمئن شوی هیچ محتوایی گم نشده باشد. تست ساده:

  • تنظیم کاهش حرکت را در سیستم‌عاملت روشن کن.
  • صفحه را باز کن و تا آخر اسکرول کن.
  • آیا هر سه پنل بخش پین‌شده را می‌بینی؟ اگر نه، مشکل داری.

در بخش‌های پین‌شده، معمولاً پنل‌ها روی هم قرار دارند و فقط انیمیشن آن‌ها را جابه‌جا می‌کند. اگر انیمیشن خاموش شود، فقط پنل آخر دیده می‌شود. راه‌حل:

@media (prefers-reduced-motion: reduce){
  .scene--pin{ height:auto; }
  .pin__stage{ height:auto; display:block; }
  .pin__panels{ position:static; height:auto;
                display:grid; gap:var(--s3); }
  .panel{ position:static; opacity:1 !important;
          transform:none !important; }
}

یعنی همان محتوا، به‌شکل سه کارت پشت‌سرهم عادی. ساده، خوانا و کامل.

پیمایش با کیبورد

خیلی‌ها اصلاً با ماوس کار نمی‌کنند. کلید Tab را در صفحهٔ خودت بزن و ببین چه اتفاقی می‌افتد. سه مشکل رایج:

۱. حلقهٔ تمرکز نامرئی

/* ❌ هرگز این کار را نکن */
*:focus{ outline:none; }

/* ✅ حلقهٔ واضح و متناسب با طراحی */
:focus-visible{
  outline:3px solid var(--accent);
  outline-offset:3px;
  border-radius:4px;
}

حالت :focus-visible فقط وقتی فعال می‌شود که کاربر با کیبورد پیمایش کند، نه با کلیک ماوس. یعنی طراحی‌ات به‌هم نمی‌ریزد و کاربر کیبورد هم راهنما دارد.

۲. گیرافتادن در بخش پین‌شده

وقتی کاربر با Tab به لینکی داخل بخش پین‌شده می‌رسد، مرورگر سعی می‌کند آن را به دید بیاورد، اما موقعیت اسکرول با انیمیشن هماهنگ نیست. راه‌حل:

document.querySelectorAll('.pin__panels a, .pin__panels button')
  .forEach(el => {
    el.addEventListener('focus', () => {
      const st = ScrollTrigger.getById('processPin');
      const step = +el.closest('.panel').dataset.step;
      if (st) {
        const p = (step - 1) / 3;
        const y = st.start + (st.end - st.start) * p;
        lenis ? lenis.scrollTo(y) : scrollTo({ top:y });
      }
    });
  });

۳. نبود لینک پرش

<a class="skip" href="#main">پرش به محتوای اصلی</a>
.skip{
  position:absolute; right:-9999px;
  background:var(--accent); color:#111;
  padding:.8rem 1.4rem; z-index:9999;
}
.skip:focus{ right:1rem; top:1rem; }

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

پیمایش با کیبورد و حلقه تمرکز در طراحی وب

صفحه‌خوان و متن شکسته‌شده

یادت هست در درس تایپوگرافی متن را به کلمه شکستیم؟ آن ساختار برای صفحه‌خوان مشکل‌ساز است. راه‌حل استاندارد:

<h1 data-split aria-label="بار شما، سرِ وقت.">بار شما، سرِ وقت.</h1>

و بهتر از آن، بعد از شکستن، ساختار داخلی را از دید صفحه‌خوان پنهان کن:

function splitWords(el){
  const text = el.textContent.trim();
  el.setAttribute('aria-label', text);      // متن کامل برای صفحه‌خوان
  const words = text.split(/\s+/);
  el.innerHTML = words
    .map(w => '<span class="w" aria-hidden="true">' +
              '<span class="w__in">' + w + '</span></span>')
    .join(' ');
  return el.querySelectorAll('.w__in');
}

حالا صفحه‌خوان جملهٔ کامل را یک‌جا می‌خواند و ساختار بصری را نادیده می‌گیرد.

عناصر تزئینی را علامت بزن

<div class="hero__veil" aria-hidden="true"></div>
<div class="hero__hint" aria-hidden="true">اسکرول کنید</div>
<img src="decoration.svg" alt="">   <!-- alt خالی، نه حذف‌شده -->

نکتهٔ ظریف: برای تصویر تزئینی، alt="" بنویس نه اینکه صفت را حذف کنی. اولی به صفحه‌خوان می‌گوید «این مهم نیست، رد شو»؛ دومی باعث می‌شود نام فایل خوانده شود.

کنتراست: مشکل خاص صفحه‌های سینمایی

متن سفید روی تصویر، امضای این سبک است و بزرگ‌ترین دام کنتراست. چون تصویر یکدست نیست، ممکن است متن روی بخشی از آن کاملاً ناخوانا شود.

سه راه‌حل، به‌ترتیب کیفیت:

/* ۱) پردهٔ گرادیانی — بهترین، طبیعی‌ترین */
.hero__veil{
  background:linear-gradient(180deg,
    rgba(0,0,0,.30) 0%, rgba(0,0,0,.70) 100%);
}

/* ۲) سایهٔ متن — برای وقتی نمی‌خواهی تصویر تیره شود */
.hero__title{ text-shadow:0 2px 18px rgba(0,0,0,.85); }

/* ۳) پس‌زمینهٔ نیمه‌شفاف پشت متن — مطمئن‌ترین */
.hero__content{
  background:rgba(10,12,14,.55);
  backdrop-filter:blur(8px);
  padding:var(--s4); border-radius:20px;
}

حداقل نسبت کنتراست برای متن معمولی ۴٫۵ به ۱ و برای متن درشت ۳ به ۱ است. ابزار بررسی کنتراست در همان ابزار توسعه‌دهندهٔ مرورگر موجود است؛ روی متن راست‌کلیک کن و بازرسی بزن.

حالت کنتراست بالا

@media (prefers-contrast: more){
  .hero__veil{ background:rgba(0,0,0,.85); }
  .panel{ border-width:2px; border-color:#fff; }
  :root{ --muted:#D6DCE2; }
}
راه حل های کنتراست متن روی تصویر در سایت سینمایی

هفت قاعدهٔ دسترس‌پذیری برای صفحه‌های متحرک

  1. هیچ حرکتی نباید تنها راه دیدن محتوا باشد. با انیمیشن خاموش، همه‌چیز باید دیده شود.
  2. هیچ‌چیز بیش از سه بار در ثانیه چشمک نزند. این محدودیت برای پیشگیری از تشنج است و جدی است.
  3. حرکت خودکار باید قابل‌توقف باشد. اگر نوار متحرک یا اسلایدر خودکار داری، دکمهٔ توقف بگذار.
  4. ترتیب تمرکز باید منطقی باشد. با Tab از بالا به پایین برو؛ نباید بپرد.
  5. حلقهٔ تمرکز همیشه دیده شود. هرگز outline:none بدون جایگزین.
  6. سلسله‌مراتب عنوان‌ها درست باشد. یک h1، بعد h2ها به‌ترتیب؛ نه بر اساس اندازهٔ فونت.
  7. لمس‌پذیری کافی. هر عنصر قابل‌کلیک حداقل ۴۴ در ۴۴ پیکسل باشد.

پرامپت بازبینی دسترس‌پذیری

نقش: متخصص دسترس‌پذیری وب با تمرکز بر صفحات انیمیشن‌محور.

زمینه: [کل کد صفحه]

کار: مشکلات دسترس‌پذیری را پیدا کن. فایل را بازنویسی نکن.

بررسی کن:
- اگر prefers-reduced-motion فعال شود، آیا محتوایی نامرئی می‌ماند؟
  مخصوصاً پنل‌های داخل بخش پین‌شده را بررسی کن.
- آیا outline تمرکز حذف شده؟ آیا focus-visible تعریف شده؟
- آیا لینک «پرش به محتوا» وجود دارد؟
- متن‌های شکسته‌شده به کلمه: آیا aria-label با متن کامل دارند
  و آیا اسپن‌های داخلی aria-hidden شده‌اند؟
- آیا عناصر تزئینی aria-hidden یا alt خالی دارند؟
- آیا ترتیب h1 تا h3 منطقی است یا بر اساس اندازهٔ فونت انتخاب شده؟
- آیا متن روی تصویر کنتراست کافی دارد؟ نسبت تقریبی را تخمین بزن.
- آیا عناصر قابل‌کلیک کمتر از ۴۴ پیکسل هستند؟
- آیا حرکت خودکاری هست که قابل‌توقف نباشد؟

خروجی: جدول «مشکل | معیار نقض‌شده | شدت | اصلاح»
و بعد فقط قطعه‌کدهای اصلاحی.
ممنوع: بازنویسی کل فایل، حذف انیمیشن‌ها.

تست عملی در ده دقیقه

تست روش انتظار
کاهش حرکت تنظیم سیستم‌عامل را روشن کن محتوای کامل، بدون حرکت
فقط کیبورد ماوس را کنار بگذار، فقط Tab همه‌جا قابل‌دسترس، حلقه دیده شود
بزرگ‌نمایی ۲۰۰٪ Ctrl و + را چند بار بزن بدون اسکرول افقی و بدون متن بریده
صفحه‌خوان ابزار داخلی سیستم‌عامل عنوان‌ها یکپارچه خوانده شوند
بدون تصویر بارگذاری تصاویر را مسدود کن متن‌ها همچنان خوانا
کنتراست بازرسی متن در ابزار مرورگر حداقل ۴٫۵ به ۱

پرسش‌های پرتکرار

اگر دسترس‌پذیری را رعایت کنم، سایتم زشت می‌شود؟
نه. تقریباً همهٔ کارهایی که در این درس گفتیم نامرئی‌اند: حلقهٔ تمرکز فقط برای کاربر کیبورد ظاهر می‌شود، aria-label اصلاً دیده نمی‌شود، و نسخهٔ کاهش حرکت را فقط کسی می‌بیند که خودش خواسته است.

واقعاً چند نفر کاهش حرکت را روشن می‌کنند؟
بیشتر از تصورت. و مهم‌تر از تعداد، این است که برای همان افراد، سایت تو یا قابل‌استفاده است یا نیست — حد وسطی ندارد.

آیا دسترس‌پذیری روی سئو اثر دارد؟
غیرمستقیم و مثبت. ساختار درست عنوان‌ها، متن جایگزین تصاویر و محتوای قابل‌دسترس بدون جاوااسکریپت، همگی برای موتور جستجو هم مفیدند.

از کجا بفهمم استانداردها را رعایت کرده‌ام؟
ابزارهای خودکار بازرسی مرورگر نقطهٔ شروع خوبی هستند، اما حدود نیمی از مشکلات را پیدا می‌کنند. تست دستی با کیبورد و تنظیم کاهش حرکت، ارزشمندتر از هر ابزار خودکاری است.

جمع‌بندی این درس و کل نقشهٔ راه

دسترس‌پذیری در صفحه‌های سینمایی سه ستون دارد: احترام به کاهش حرکت (در هر سه لایهٔ CSS، جاوااسکریپت و محتوا)، پیمایش کامل با کیبورد، و متن قابل‌فهم برای صفحه‌خوان با کنتراست کافی.

و با این درس، هر نُه بخش این نقشهٔ راه کامل شد: از فهمیدن اینکه این سبک چیست، تا استوری‌بورد، ساختار، اسکرول نرم، پین و اسکراب، عمق و تایپوگرافی، سیستم پرامپت، ساخت کامل، کارایی و دسترس‌پذیری.

حالا وقت آن است که همهٔ این‌ها را در یک پروژهٔ واقعی کنار هم بگذاری. نقشهٔ راه را باز کن و سراغ پروژهٔ پایانی برو. و اگر می‌خواهی از انتشار درس‌ها و پروژه‌های تازه باخبر شوی، کانال @MrChatGPT_IR منتظر توست.

(0 رأی)

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *