تخطَّ إلى المحتوى

الحركة في CSS: animation و keyframes

الدرس 17 من 19 · CSS

في الدرس السابق حرّكت العناصر بـ transition، لكنها تحتاج دائماً سبباً: مرور فأرة أو تغيّر كلاس. وهي تنتقل بين حالتين فقط. ماذا عن دائرة تحميل تدور بلا توقف؟ أو عنصر يدخل الصفحة منزلقاً عند فتحها؟ هنا تحتاج animation: حركة تعمل وحدها، وتمر بأي عدد من المراحل، وتتكرر كما تشاء.

الحركة في CSS تُبنى في خطوتين:

  1. تعريف المشاهد بقاعدة @keyframes: كيف يبدو العنصر في بداية الحركة، وفي نهايتها، وربما في منتصفها.
  2. ربط الحركة بعنصر بخاصية animation: كم تستمر، وكم مرة تتكرر.

تخيّل دفتر الرسوم المتحركة: ترسم في صفحاته أوضاعاً مختلفة للشخصية، ثم تقلّب الصفحات بسرعة فتراها تتحرك. أنت ترسم الأوضاع الرئيسية فقط في @keyframes، والمتصفح يرسم كل ما بينها.

@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.message {
animation: fade-in 1s;
}
  • @keyframes fade-in: حركة سمّيناها fade-in. الاسم من اختيارك.
  • from: حالة البداية. و to: حالة النهاية.
  • animation: fade-in 1s: شغّل هذه الحركة على العنصر لمدة ثانية.

النتيجة: العنصر يظهر تدريجياً عند تحميل الصفحة، بلا أي تفاعل من المستخدم.

بدلاً من from و to اكتب نسباً مئوية من زمن الحركة:

@keyframes traffic {
0% { background: crimson; }
50% { background: gold; }
100% { background: green; }
}

0% تساوي from، و 100% تساوي to. وتستطيع أن تضيف أي عدد من المراحل بينهما. وإذا تشابهت مرحلتان فاجمعهما:

@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.15); }
}

العنصر يكبر في منتصف الحركة ثم يعود إلى حجمه، مثل نبضة قلب.

الخاصية وظيفتها أمثلة
animation-name اسم الحركة pulse
animation-duration مدة الدورة الواحدة 2s أو 500ms
animation-timing-function منحنى السرعة linear و ease-in-out
animation-delay تأخير قبل البدء 0.5s
animation-iteration-count عدد مرات التكرار 3 أو infinite
animation-direction اتجاه التشغيل normal و alternate
animation-fill-mode حالة العنصر قبل الحركة وبعدها forwards و both

وتُكتب كلها غالباً في سطر واحد مختصر:

.heart {
animation: pulse 1s ease-in-out infinite;
}

الاسم، ثم المدة، ثم المنحنى، ثم عدد المرات. والمتصفح يميّز بين القيم من نوعها. وإذا كتبت زمنين فالأول هو المدة والثاني هو التأخير.

  • infinite: الحركة لا تتوقف أبداً.
  • alternate: بعد كل دورة تنعكس الحركة، فتذهب ثم تعود بدلاً من أن تقفز إلى البداية.
@keyframes slide {
from { transform: translateX(0); }
to { transform: translateX(100px); }
}
.ball {
animation: slide 1s ease-in-out infinite alternate;
}

الكرة تذهب إلى اليمين ثم ترجع بنعومة، بلا توقف.

الأصل أن العنصر يعود إلى شكله الأصلي فور انتهاء الحركة. إذا أردته أن يبقى على حالة النهاية فأضف forwards:

.toast {
animation: fade-in 0.4s forwards;
}

مثال عملي: مؤشر التحميل

Section titled “مثال عملي: مؤشر التحميل”

الدائرة التي تدور أثناء الانتظار ليست صورة. هي عنصر واحد وحركة واحدة:

.spinner {
width: 40px;
height: 40px;
border: 4px solid #e6e8f0;
border-top-color: #5b5bf0;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}

إطار دائري رمادي، وجزؤه العلوي ملون، والعنصر كله يدور. لاحظ أمرين:

  • كتبنا to فقط. المتصفح يعتبر الحالة الحالية للعنصر هي البداية.
  • المنحنى linear، لأن الدوران المستمر يحتاج سرعة ثابتة، وإلا بدا متقطعاً.
transition animation
متى تبدأ؟ عند تغيّر خاصية: hover أو كلاس وحدها، من لحظة ظهور العنصر
عدد المراحل اثنتان: قبل وبعد أي عدد
التكرار لا نعم، حتى بلا نهاية
تناسب الاستجابة لتفاعل المستخدم التحميل، ولفت النظر، والدخول

احترم خيار تقليل الحركة

Section titled “احترم خيار تقليل الحركة”

الحركة المستمرة تتعب بعض الناس، وقد تسبب لهم دواراً. أوقفها لمن طلب ذلك من إعدادات جهازه:

@media (prefers-reduced-motion: reduce) {
.ball, .heart {
animation: none;
}
}

غيّر مدة حركة الدائرة من 0.8s إلى 3s، واحذف كلمة alternate من حركة الكرة وشاهد القفزة. ثم أضف مرحلة 50% إلى حركة slide تغيّر فيها لون الكرة:

جرّب بنفسكCSS
أو اضغط Ctrl + Enter

الناتج

  • اسم الحركة لا يطابق: الاسم بعد @keyframes يجب أن يطابق الاسم في animation حرفاً بحرف، وإلا لم يحدث شيء.
  • نسيان المدة: المدة الافتراضية صفر، فالحركة تنتهي قبل أن تراها.
  • العنصر يرجع فجأة عند النهاية: أضف forwards ليبقى على حالة النهاية.
  • حركات كثيرة لا تتوقف: تشتت القارئ وتستهلك البطارية. اجعل الحركة المستمرة لمؤشرات التحميل، والباقي مرة واحدة.

سؤال

ما وظيفة قاعدة @keyframes؟

سؤال

ماذا تعني animation: bounce 2s infinite alternate؟

  • @keyframes تعرّف مراحل الحركة بـ from و to أو بنسب مئوية.
  • animation تربط الحركة بالعنصر: الاسم، والمدة، والمنحنى، وعدد المرات.
  • infinite للتكرار الدائم، و alternate للذهاب والعودة، و forwards للبقاء على حالة النهاية.
  • transition للاستجابة لتفاعل، و animation لحركة تعمل وحدها.
  • استخدم الحركة باعتدال، وأوقفها مع prefers-reduced-motion.