الحركات (Animations) — CSS المتقدم
الحركات (Animations)
الانتقال يحتاج تغيير حالة (hover، صنف جديد) وله بداية ونهاية فقط. الحركة بـ @keyframes تعمل وحدها، بعدة مراحل، وتتكرر إن شئت: مؤشرات التحميل، ظهور العناصر، لفت الانتباه.
التعريف والاستخدام
@keyframes fade-up {
from { opacity: 0; translate: 0 16px; }
to { opacity: 1; translate: 0 0; }
}
.reveal {
animation: fade-up 400ms ease-out both;
}مراحل متعددة
@keyframes pulse {
0%, 100% { scale: 1; }
50% { scale: 1.08; }
}خصائص animation
| الخاصية | المعنى | مثال |
|---|---|---|
| animation-name | اسم @keyframes | pulse |
| animation-duration | مدة الدورة الواحدة | 2s |
| animation-timing-function | المنحنى (لكل مرحلة) | ease-in-out |
| animation-delay | تأخير البدء (يقبل سالباً: يبدأ من المنتصف) | 200ms |
| animation-iteration-count | عدد التكرارات | 3 أو infinite |
| animation-direction | الاتجاه | alternate (ذهاب وإياب) |
| animation-fill-mode | الحالة قبل/بعد التشغيل | both |
| animation-play-state | إيقاف مؤقت | paused |
الاختصار: animation: pulse 2s ease-in-out infinite;
fill-mode: مشكلة "القفزة"
بعد انتهاء الحركة يعود العنصر لتنسيقه الأصلي. حركة ظهور تبدأ من opacity: 0 مع تأخير ستُظهر العنصر أولاً ثم تخفيه ثم تبدأ!
- forwards: يبقى على الإطار الأخير.
- backwards: يطبق الإطار الأول أثناء التأخير.
- both: الاثنان — الأكثر أماناً لحركات الظهور.
ظهور متتابع
.list-item { animation: fade-up 400ms ease-out both; }
.list-item:nth-child(2) { animation-delay: 80ms; }
.list-item:nth-child(3) { animation-delay: 160ms; }أو بمتغير: style="--i: 2" في HTML و animation-delay: calc(var(--i) * 80ms).
مؤشر تحميل
@keyframes spin { to { rotate: 1turn; } }
.spinner {
width: 32px;
height: 32px;
border: 3px solid rgb(0 0 0 / 15%);
border-top-color: currentColor;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}from مُهمَل هنا: المتصفح يأخذ القيمة الحالية كبداية.
الأداء والوصولية
- حرّك transform/translate/scale/rotate و opacity فقط إن أمكن.
- الحركات اللانهائية تشتت الانتباه وتستهلك البطارية؛ استخدمها لمؤشرات التحميل فقط، وأوقفها عندما لا تلزم.
- prefers-reduced-motion إلزامي:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}بعض الناس (اضطرابات الدهليز) تسبب لهم الحركة دواراً وغثياناً حقيقياً.
- تجنب الوميض أكثر من 3 مرات في الثانية (قد يسبب نوبات صرع).
الحركة المرتبطة بالتمرير (حديث)
animation-timeline: view() يربط تقدم الحركة بظهور العنصر أثناء التمرير — بلا JavaScript. الدعم ممتاز في Chrome و Edge ويتوسع؛ استخدمه داخل @supports (animation-timeline: view()) كتحسين إضافي.
تمرين
أنشئ مؤشر تحميل، وحركة ظهور متتابعة لبطاقات المشاريع بـ fill-mode: both، وأوقف كل الحركات مع prefers-reduced-motion. اختبر من أدوات المطور: Rendering ← Emulate prefers-reduced-motion.
/* حركة أساسية */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fade-in {
animation: fadeIn 1s ease forwards;
}
/* حركة متعددة المراحل */
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-30px);
}
}
.bouncing {
animation: bounce 0.5s ease infinite;
}
/* حركة دوران */
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.spinner {
animation: spin 1s linear infinite;
}
/* حركة نبض */
@keyframes pulse {
0% {
transform: scale(1);
box-shadow: 0 0 0 0 rgba(52, 152, 219, 0.4);
}
70% {
transform: scale(1.05);
box-shadow: 0 0 0 20px rgba(52, 152, 219, 0);
}
100% {
transform: scale(1);
}
}
.pulse-button {
animation: pulse 2s infinite;
}
/* حركة كتابة */
@keyframes typing {
from {
width: 0;
}
to {
width: 100%;
}
}
.typing-effect {
overflow: hidden;
white-space: nowrap;
animation: typing 3s steps(30) forwards;
}
/* حركة تحميل */
@keyframes loading {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(400%);
}
}
.loading-bar {
position: relative;
overflow: hidden;
}
.loading-bar::after {
content: '';
position: absolute;
width: 25%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
animation: loading 1.5s infinite;
}اختبر فهمك