حركات CSS: نصائح وحيل
تتيح حركات CSS القيام بأشياء لا تصدق على العناصر التي تشكل صفحات مواقعك وتطبيقاتَك الخاصة. ومع ذلك، هناك أشياء ترغب في القيام بها لكنها ليست واضحة، أو طرق ذكية للقيام بأشياء قد لا تتوصل إليها على الفور. هذه المقالة عبارة عن مجموعة من النصائح والحيل التي قد تسهل عملك مع حركات CSS، بما في ذلك كيفية توقيف الحركة وتشغيلها مرة أخرى.
إعادة تشغيل الحركة
لا تقدم طبيعة حركات CSS طريقةً لإعادة تشغيل الحركة مرة أخرى. لا توجد دالة مثل ()resetAnimation
فعَّالة للعناصر، ولا يمكنك حتى ضبط حالة تشغيل الحركة (أي الخاصية animation-play-state
) للعنصر على "running" ثانيةً. بدلًا من ذلك، يجب عليك استخدام الحيل الذكية لإعادة تشغيل الحركة بعد توقفها.
إليك طريقة متوازنة وموثوقة يمكن أن تُقتَرح للقيام بذلك.
محتوى HTML
أولاً، دعنا نحدد الحاوية <div>
التي نود تحريكها والزر الذي سيشغل (أو سيعيد) الحركة:
<div class="box">
</div>
<div class="runButton">Click me to run the animation</div>
محتوى CSS
سنقوم الآن بتعريف الحركة نفسها باستخدام CSS. بعض شيفرات CSS غير المهمة (تنسيقات زر التشغيل) ستجد أنها غير معروضة هنا، للإيجاز.
@keyframes colorchange {
0% { background: yellow }
100% { background: blue }
}
.box {
width: 100px;
height: 100px;
border: 1px solid black;
}
.changing {
animation: colorchange 2s;
}
تم استخدام صنفان هنا، صنف "box" يشمل الوصف الأساسي لمظهر الصندوق، دون أن يحتوي أي معلومات عن الحركة، فتفاصيل الحركة يتم تضمينها في الصنف "changing"
الذي ينص بالقاعدة @keyframes
القاعدة أن الإطارات المفتاحية المسماة "colorchange"
يجب أن تُستخدَم على مدار ثانيتين لتحريك المربع.
لاحظ أنه بسبب هذا؛ فإن المربع لا يبدأ بأي تأثيرات للحركة في مكانه، لذلك لن يكون متحركًا في أصله.
محتوى JavaScript
سنلقي نظرة على شِيفرة JavaScript التي تعمل معنا، جوهر هذه التقنية هو في الدالة ()play
، والتي تُستدعى عندما ينقر المستخدم على زر "Run".
function play() {
document.querySelector(".box").className = "box";
window.requestAnimationFrame(function(time) {
window.requestAnimationFrame(function(time) {
document.querySelector(".box").className = "box changing";
});
});
}
هذا يبدو غريبًا، أليس كذلك؟ ذلك لأن الطريقة الوحيدة لتشغيل الحركات مرة أخرى هي إزالة تأثير الحركة، والسماح للمستند بإعادة تشغيل أنماط CSS، ثم إضافة تأثير الحركة مرة أخرى للعنصر. لتحقيق ذلك، علينا أن نكون مبدعين.
إليك ما يحدث عندما يتم استدعاء الدالة ()play
:
- يتم تعيين قائمة أصناف CSS الخاصة بالمربع إلى
"box"
فقط. هذا تأثير إزالة أي أصناف أخرى مطبقة حاليًا على المربع، بما في ذلك صنف"changing"
الذي تتعامل معه الحركات. بمعنى آخر، قمنا بإزالة تأثير الحركات من المربع. ومع ذلك، لا تسري التغييرات التي تم إجراؤها على قائمة الأصناف حتى تكتمل إعادة تشكيل النمط وعمل تحديث لإظهار التغيير. - للتأكد من إعادة تشغيل الأنماط، نستخدم التابع
()window.requestAnimationFrame
، مع تحديد رد اتصال. يتم تنفيذ رد الاتصال قبل إعادة التخطيط التالي للمستند، وبسبب ذلك، لم تتم إعادة صياغة النمط لدينا بعد! - رد النداء لدينا يقوم باستدعاء
()requestAnimationFrame
مرة ثانية بذكاء! هذه المرة، يُشغَّل رد النداء قبل إعادة التخطيط التالي، والذي يكون بعد حدوث إعادة تشغيل النمط. يضيف رد الاتصال هذا الصنف"changing"
مرة أخرى إلى المربع، بحيث يتسبب إعادة التخطيط في تشغيل الحركة ثانيةً.
بالطبع، نحتاج أيضًا إلى إضافة معالج حدث إلى زر التشغيل لدينا، "Run"
، حتى يقوم بعمل إضافي:
document.querySelector(".runButton").addEventListener("click", play, false);
إيقاف الحركة
ببساطة، إزالة الخاصية animation-name
من العنصر تجعله ينتقل لحالته التالية، إذا كنت ترغب بدلًا من ذلك في إكمال الحركة ثم توقيفها، فعليك تجربة طريقة مختلفة. التلميحات الرئيسية هي:
- اجعل حركاتك قائمة بذاتها قدر الإمكان، هذا يعني أنك يجب ألا تعتمد على
animation-direction: alternate
، بل يجب أن تكتب بوضوح رسمًا متحركًا للإطار المفتاحي يمر بالحركات الكاملة في تكرار واحد متتابع. - استخدم JavaScript وقم بتفريغ الحركات المستخدمة عند انطلاق حدث تكرار الحركة (animationiteration).
توضح التجرية الحية هذه كيف يمكنك تحقيق تقنية JavaScript المذكورة أعلاه:
- شيفرة CSS:
.slidein {
animation-duration: 5s;
animation-name: slidein;
animation-iteration-count: infinite;
}
.stopped {
animation-name: none;
}
@keyframes slidein {
0% {
margin-left: 0%;
}
50% {
margin-left: 50%;
}
100% {
margin-left: 0%;
}
}
- شيفرة HTML:
<h1 id="watchme">Click me to stop</h1>
- شيفرة JavaScript:
let watchme = document.getElementById('watchme')
watchme.className = 'slidein'
const listener = (e) => {
watchme.className = 'slidein stopped'
}
watchme.addEventListener('click', () =>
watchme.addEventListener('animationiteration', listener, false)
)