- استخدِم
clip-pathوmask-imageلإظهار الأشكال الهندسية المخصّصة والتلاشي السلس. - استخدِم صورًا متحركة مستندة إلى التمرير (
animation-timeline: scroll()) للتأثيرات غير الأساسية المرتبطة بالتمرير بدلاً من أدوات الاستماع إلى JS. - استخدِم View Transitions لإضافة تأثيرات متحركة بين حالات التنسيق المعقّدة بسلاسة.
الأداء
- يُفضَّل تحريك
opacityوtransform(بما في ذلك خصائص التحويل الفردية، مثلtranslateبدلاً منleft/right/top/bottom) لضمان بقاء الصور المتحركة في سلسلة عمليات برنامج التجميع. - استخدِم
transition-behavior: allow-discreteو@starting-styleوoverlay(للعناصر في الطبقة العليا مثل<dialog>أو[popover]) لإضافة حركة إلى حالات الدخول والخروج المنفصلة بشكلٍ أصلي. اطّلِع على إضافة حركة إلى دخول العناصر وخروجها وإضافة حركة إلى العناصر من الطبقة العليا وإليها.
.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).