حركة

  • استخدِم clip-path وmask-image لإظهار الأشكال الهندسية المخصّصة والتلاشي السلس.
  • استخدِم صورًا متحركة مستندة إلى التمرير (animation-timeline: scroll()) للتأثيرات غير الأساسية المرتبطة بالتمرير بدلاً من أدوات الاستماع إلى JS.
  • استخدِم View Transitions لإضافة تأثيرات متحركة بين حالات التنسيق المعقّدة بسلاسة.

الأداء

.popover-reveal {
  /* Transition discrete display and top-layer overlay alongside opacity */
  transition:
    opacity ease-out,
    display,
    overlay;
  transition-duration: 0.2s;
  transition-behavior: allow-discrete;
}

تسهيل الاستخدام

استخدِم طلبات البحث عن الوسائط prefers-reduced-motion لإيقاف الحركة الكثيفة للمستخدمين الذين يفضّلون ذلك.

  • توفير آلية الإيقاف المؤقت: اسمح للمستخدمين بإيقاف لوحات العرض الدوّارة أو البانرات أو غيرها من الصور المتحركة الثابتة التي تعمل تلقائيًا.
  • الضبط التلقائي على طرق العرض الثابتة: ننصحك بضبط الإعدادات التلقائية على الحالات الثابتة والسماح للمستخدمين بالموافقة على الحركة.
  • عدم تجاوز حدود الوميض (ثلاث مرات في الثانية): لا تضمِّن أبدًا وميضًا سريعًا من الضوء إلى الظلام. وقد تؤدي هذه التأثيرات إلى حدوث نوبات صرع.

لا تطبّق animation-duration: 0.01ms; بشكل عام لأنّ ذلك قد يؤدي إلى جعل بعض الصور المتحركة أكثر إزعاجًا. بدلاً من ذلك، يمكنك التعامل مع الإعدادات المفضّلة للحركة على أساس كل حالة على حدة باستخدام أحد النهجَين، أي دمج طلب البحث @media داخل القاعدة بحيث يتم الاحتفاظ بالإصدارَين معًا:

  • ابدأ بتفعيل الصور المتحركة تلقائيًا، ثم خفِّفها باستخدام @media (prefers-reduced-motion: reduce):
/* Good: Dampen spin states or slow down animations for reduced motion */
.spinner {
  animation: spin 1s linear infinite;
  @media (prefers-reduced-motion: reduce) {
    animation: none;
    opacity: 0.5;
  }
}

progress:not([value]) {
  animation: slide 1s infinite linear;
  @media (prefers-reduced-motion: reduce) {
    animation-duration: 20s;
  }
}
  • ابدأ بدون صور متحركة تلقائيًا، وفعِّلها باستخدام @media (prefers-reduced-motion: no-preference):
/* Good: Default to static or gentle states and opt-in to full motion */
.spinner {
  opacity: 0.5;
  @media (prefers-reduced-motion: no-preference) {
    opacity: 1;
    animation: spin 1s linear infinite;
  }
}

progress:not([value]) {
  animation: slide 20s infinite linear;
  @media (prefers-reduced-motion: no-preference) {
    animation-duration: 1s;
  }
}

التعامل مع أحداث الحركة والانتقال في JavaScript

في كل من واجهتَي AnimationEvent (animationstart وanimationiteration وanimationend وanimationcancel) وTransitionEvent (transitionrun وtransitionstart وtransitionend وtransitioncancel)، يمنحك event.target عنصر DOM الأصلي. للوصول إلى عنصر Animation المحدّد (Animation أو CSSAnimation أو CSSTransition) الذي أدّى إلى بدء الحدث، استخدِم السمة event.animation للقراءة فقط.

عندما لا يتوفّر event.animation، يمكنك عادةً العثور على مثيل Animation من خلال طلب event.target.getAnimations() والفلترة حسب event.animationName (أو event.propertyName لعمليات النقل). ومع ذلك، يُفضَّل استخدام event.animation مباشرةً لتجنُّب عدة سيناريوهات لا يعمل فيها هذا الإجراء الاحتياطي الذي يفلتر event.target.getAnimations() على النحو المتوقّع:

  • لا تحتوي صور Web Animations API (element.animate()) المتحركة على animationName، لذا لا يمكن مطابقتها بالاسم عند فلترة event.target.getAnimations().
  • تكون الفلترة حسب animationName لـ AnimationEvent غامضة عندما يتم إرفاق عدة صور متحركة بالاسم نفسه بالعنصر نفسه.
    • يُرجى العِلم أنّ الفلترة حسب transitionProperty لـ TransitionEvent تعمل لأنّ هناك حدثًا واحدًا فقط لكل سمة انتقال.
  • يشير event.target دائمًا إلى عنصر DOM الأصلي، لذا لا يميّز بين الصور المتحركة التي يتم تشغيلها على العنصر نفسه وأحد عناصره الزائفة، بينما يعرض event.animation.effect.pseudoElement العنصر الزائف المستهدَف مباشرةً.
// Works in most basic CSS animation cases, but fails for WAAPI animations,
// duplicate animation names on the same element, or pseudo-elements.
document.addEventListener('animationstart', (event) => {
  const animation = event.target
    .getAnimations()
    .find((anim) => anim.animationName === event.animationName);
  console.log(animation);
});

// PREFERRED: Directly access the exact Animation object via event.animation
document.addEventListener('animationstart', (event) => {
  const animation = event.animation;
  console.log(animation);
});

يمكنك رصد الميزات المتوافقة باستخدام 'animation' in AnimationEvent.prototype (أو 'animation' in TransitionEvent.prototype).