استخدام حركات CSS

من موسوعة حسوب
< CSS
اذهب إلى: تصفح، ابحث

تتيح حركات CSS تنشيط التحوُّلات من نمط CSS لآخر. تتكون الحركات من عنصرين، نمط CSS يصفها، ومجموعة من الإطارات المفتاحية التي تشير إلى حالتي البداية والنهاية لنمط الحركة.

هناك ثلاث مزايا أساسية لحركات CSS عبر تقنيات الرسوم المتحركة التقليدية (script-driven):

  1. سهلة الاستخدام للحركات البسيطة؛ يمكنك إنشائها دون الحاجة إلى معرفة بِ JavaScript.
  2. تعمل الحركات بشكل جيد، حتى في ظل تحميل النظام العادي. ممكن أن يكون أداء الحركات البسيطة ضعيفًا باستخدام JavaScript (ما لم تكن جيدة الصنع). حيث يمكن للمحرك المصيِّراستخدام تقنية تخطي الإطار frame-skipping وغيرها من التقنيات للحفاظ على الأداء السلس قدر الإمكان.
  3. السماح للمتصفح بالتحكم في تسلسل الحركات ما يتيح للمتصفح تحسين الأداء والكفاءة، على سبيل المثال، تقليل وتيرة تحديث الحركات التي تعمل في علامات التبويب وهي غير ظاهرة في مشهد المستخدم الحالي.

ضبط الحركات

لإنشاء تسلسل حركات CSS، يمكنك تشكيل العنصر الذي تريد تحريكه باستخدام الخاصية animation أو خصائصها الفرعية. يتيح لك ذلك ضبط التوقيت والمدة والتفاصيل الأخرى لكيفية تسيير تسلسل الحركات. يُضبَط الظهور الفعلي للحركة باستخدام قاعدة keyframes@ كما هو موضح في تعريف تسلسل الحركة باستخدام الإطارات المفتاحية أدناه.

الخاصيات الفرعية للخاصية animation هي:

  • animation-name: تستعمل لتحديد أسماء الحركات التي ستُطبَّق على العنصر، وكل اسم يجب أن يُشير إلى قاعدة ‎@keyframes التي تُعرِّف قيم الخاصيات اللازمة للحركة.
  • animation-duration: تُحدِّد الزمن اللازم لإكمال دورة كاملة من الحركة.
  • animation-timing-function: تستعمل لوصف كيف ستتأثر القيم الوسطية لخاصيات CSS بالحركة، أي أنها تسمح لك بتحديد ما هو منحني التسارع (acceleration curve) للحركة خلال دورة واحدة.
  • animation-delay: تستخدم لتحديد التأخير بين وقت تحميل العنصر وبداية تسلسل الحركة.
  • animation-iteration-count: تستخدم لتحديد عدد مرات تكرار الحركة؛ يمكنك من خلالها تحديد تكرار لا نهائي للحركة عبر الكلمة المفتاحية infinite.
  • animation-direction: تستخدم لتحديد ما إذا كانت الحركة يجب أن تتناوب على الاتجاهات في كل تشغيل من خلال التسلسل ويمكن إعادة تعيين الحركة إلى نقطة البداية وتكرار نفسها.
  • animation-fill-mode: تستخدم لتحديد قيم الخاصيات التي تُطبقها الحركة قبل وبعد تنفيذها.
  • animation-play-state: تتيح إيقاف وتشغيل تسلسل الحركة.

تحديد تسلسل الحركات باستخدام الإطارات المفتاحية

بمجرد تحديد توقيت الحركة، ستحتاج إلى تحديد مظهرها. يتم ذلك عن طريق إنشاء إطارين مفتاحيّين أو أكثر باستخدام قاعدة ‎@keyframes. يصف كل إطار مفتاحي كيف يجب أن يظهر العنصر المتحرك في وقت معين أثناء تسلسل الحركة.

نظرًا لتحديد توقيت الحركة في نمط CSS الذي يقوم بتكوين الحركة، تستخدم الإطارات المفتاحية القيمة <percentage> للإشارة إلى الوقت الذي يحدث فيه تسلسل الحركة. تشير النسبة 0٪ إلى اللحظة الأولى لبداية تسلسل الحركة، بينما تشير النسبة 100٪ إلى الحالة النهائية للحركة. لأن هاتين المرحلتين مهمتان للغاية، فَلديهما أسماء مستعارة خاصة: من from وإلى to، كلاهما اختياري؛ فإذا لم يتم تحديد البداية (عبر from أو 0%‎) أو النهاية (عبر to أو ‎100%‎) فإن المتصفح يبدأ أو يُنهي الحركة باستخدام القيم المحسوبة لجميع الخاصيات.

يمكنك اختياريًا تضمين إطارات مفتاحية إضافية تصف الخطوات الوسيطة بين بداية ونهاية الحركة.

أمثلة

ملاحظة: قد تحتاج بعض المتصفحات القديمة (قبل 2017) إلى بادئات. تتضمن الأمثلة المباشرة التي يمكنك النقر فوقها في متصفحك بُنية بادئة متصفح كروم (webkit-).

إنشاء عرض نصي عبر نافذة المتصفح

يقوم هذا المثال البسيط بتنسيق العنصر <p> بحيث يعبر النص من الطرف الأيمن لِنافذة المتصفح.

لاحظ أن مثل هذه الحركات يمكن أن تجعل عرض الصفحة أكبر من عرض نافذة المتصفح؛ ولِتجنب هذه المشكلة، نقوم بوضع العنصر المراد تحريكه في حاوية (container) ونقوم بضبط الخاصية overflow لِهذه الحاوية على القيمة hidden:
p {
  animation-duration: 3s;
  animation-name: slidein;
}

@keyframes slidein {
  from {
    margin-left: 100%;
    width: 300%; 
  }

  to {
    margin-left: 0%;
    width: 100%;
  }
}
في هذا المثال، يحدد نمط العنصر <p> أن الحركة يجب أن تستغرق 3 ثوانٍ للتنفيذ من البداية إلى النهاية، باستخدام الخاصية animation-duration وأن اسم القاعدة keyframes@ التي تحدد الإطارات المفتاحية لتسلسل الحركة هو "slidein". إذا أردنا أن يظهر أي تصميم مخصص على العنصر <p> في المتصفحات التي لا تدعم حركات CSS، فيمكنك تضمين ذلك التصميم باستخدام البادئات هنا أيضًا؛ لكن في هذه الحالة، لا نريد ذكر أي تصميم مخصص سوى تأثير الحركة.

يتم تعريف الإطارات المفتاحية باستخدام القاعدة keyframes@. في هذه الحالة، لدينا اثنين فقط من الإطارات المفتاحية. يظهر الأول عند النسبة 0٪ باستخدام الكلمة المحجوزة from، نقوم هنا بتحديد الهامش الأيسر للعنصر بحيث يكون عند النسبة 100٪ (أي، في أقصى الحافة اليمينية للعنصر الحاوي) ، ويكون عرض العنصر بنسبة 300٪ (أو ثلاثة أضعاف عرض العنصر الحاوي). يؤدي هذا إلى جعل الإطار الأول للحركة يُخرج عنصر الترويسة (العنصر <p> في حالتنا) من الحافة اليمنى لِإطار المستعرض.

يظهر الإطار الرئيسي الثاني عند النسبة 100٪ باستخدام الكلمة المحجوزة to، يتم تحديد الهامش الأيسر للعنصر بحيث يكون عند النسبة 0٪ وتعيين عرض العنصر على 100٪. يؤدي هذا إلى إنهاء حركة عنصر الترويسة تجاه الحافة اليسرى لمنطقة المحتوى.
<p>The Caterpillar and Alice looked at each other for some time in silence:
at last the Caterpillar took the hookah out of its mouth, and addressed
her in a languid, sleepy voice.</p>
(قم بإعادة تحميل الصفحة لمشاهدة الحركة، أو انقر فوق الزر CodePen لرؤية الرسوم المتحركة في بيئة CodePen)

إضافة إطار مفتاحي آخر

دعنا نضيف إطارًا مفتاحيًا آخر للحركة في المثال السابق. لنقُل إننا نريد زيادة حجم خط عنصر الترويسة أثناء انتقاله من اليمين إلى اليسار لفترة من الوقت، ثم تقليل حجمه إلى حجمه الأصلي. يعد ذلك بسيطًا مثل إضافة هذا الإطار المفتاحي:
75% {
  font-size: 300%;
  margin-left: 25%;
  width: 150%;
}
هذا يخبر المتصفح أن 75٪ من الطريق خلال تسلسل الحركة؛ يجب أن يمتلك عنصر الترويسة هامشه الأيسر بنسبة 25٪ وعرضه يجب أن يكون 150٪. (قم بإعادة تحميل الصفحة لمشاهدة الحركة، أو انقر فوق الزر CodePen لرؤية الرسوم المتحركة في بيئة CodePen.)

جعل الحركة تتكرر

لجعل الحركة تكرّر نفسها، ما عليك سوى استخدام الخاصية animation-iteration-count (تكرار الحركة) للإشارة إلى عدد مرات تكرار الحركة. في هذه الحالة، دعونا نستخدم القيمة infinite لتكرار الحركة لا نهائيًا:
p {
  animation-duration: 3s;
  animation-name: slidein;
  animation-iteration-count: infinite;
}

جعل الحركة تتحرك ذهابا وإيابا

ذلك جعلها تتكرر، لكن من غير المناسب أن تقفز ثانيةً إلى البداية في كل مرة تبدأ حركتها؛ ما نريده حقًا هو أن تتحرك للأمام والخلف عبر الشاشة، يمكن تحقيق ذلك بسهولة من خلال تحديد الخاصية animation-direction (اتجاه الحركة) إلى القيمة alternate:
p {
  animation-duration: 3s;
  animation-name: slidein;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

استخدام الشيفرة المختزلة للحركة

الشيفرة المختصرة للحركة مفيدة لتوفير المساحة، مثال:
p {
  animation-duration: 3s;
  animation-name: slidein;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}
يمكن أن تُستبدل بالشيفرة التالية:
p {
  animation: 3s infinite alternate slidein;
}
ملاحظة: يمكنك العثور على مزيد من التفاصيل في توثيق animation.

تحديد قيم متعددة للخاصية animation

يمكن أن تقبل الصيغة المطولة لتنسيق حركات CSS قيمًا متعددة، مفصولة بِواصلة (-) يمكن استخدام هذه الميزة عندما تريد تطبيق حركات متعددة في قاعدة keyframe@ واحدة، وتعيين فترات الإنفصال، وعدد مرات التكرار، ...إلخ. للحركات المختلفة. دعونا نلقي نظرة على بعض الأمثلة السريعة لشرح التبديلات المختلفة: في هذا المثال الأول، لدينا ثلاثة أسماء لحركة، لكن مدة واحدة وتكرار واحد فقط. في هذه الحالة، تُعطى جميع الحركات الثلاثة نفس المدة وعدد مرات التكرار:
animation-name: fadeInOut, moveLeft300px, bounce;
animation-duration: 3s;
animation-iteration-count: 1;
في هذا المثال الثاني، لدينا ثلاث قيم تم تعيينها على الخصائص الثلاثة. في هذه الحالة، تُشغَّل كل حركة مع القيم المقابلة في نفس الموضع على كل خاصية، فعلى سبيل المثال الحركة fadeInOut تبلغ مدتها 2.5 ثانية وعدد مرات تكرارها 2، ...إلخ.
animation-name: fadeInOut, moveLeft300px, bounce;
animation-duration: 2.5s, 5s, 1s;
animation-iteration-count: 2, 1, 5;
في هذه الحالة الثالثة، هناك ثلاث حركات محددة، لكن فقط مُدتين وتِكرارين للحركة. في مثل هذه الحالات التي لا توجد فيها قيم كافية لإعطاء قيمة منفصلة لكل حركة، فإن دورة القيم تبدأ من البداية إلى النهاية، على سبيل المثال، تحصل الحركة fadeInOut على مدة 2.5 ثانية، بينما تحصل moveLeft300px على مدة 5 ثوانٍ. لقد وصلنا الآن إلى نهاية القيم المتاحة لمدة الحركة، لذلك نرجع من البداية مرة أخرى؛ وبالتالي فإن الحركة bounce تحصل على مدة 2.5 ثانية. يتم تعيين خاصية التكرار animation-iteration-count (وقيم الخاصيات الأخرى التي حددتَها) بنفس الطريقة.
animation-name: fadeInOut, moveLeft300px, bounce;
animation-duration: 2.5s, 5s;
animation-iteration-count: 2, 1;

استخدام أحداث الحركات

يمكنك الحصول على تحكم إضافي في الحركة (بالإضافة إلى معلومات مفيدة عنها) من خلال الاستفادة من أحداث الحركة، هذه الأحداث الممثلة بالكائن AnimationEvent يمكن استخدامه لمعرفة متى تبدأ الحركة، ومتى تنتهي، ومتى تبدأ بالتكرار من جديد. يتضمن كل حدث الوقت الذي حدث فيه وكذلك اسم الحركة التي أدت إلى الحدث.

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

إضافة شيفرة CSS

نبدأ بإنشاء شِيفرة CSS للحركة، تستمر هذه الحركة لمدة 3 ثوانٍ، وتسمى "slidein"، وتُكرر ثلاث مرات، ولها اتجاه متبادِل في كل مرة. في قاعدة keyframes@، يتم التعامل مع العرض والهامش الأيسر لجعل العنصر ينزلق عبر الشاشة.
.slidein {
  animation-duration: 3s;
  animation-name: slidein;
  animation-iteration-count: 3;
  animation-direction: alternate;
}

@keyframes slidein {
  from {
    margin-left:100%;
    width:300%
  }
  
  to {
    margin-left:0%;
    width:100%;
  }
}

إضافة مستمعي الحدث للحركة

سنستخدم شفرة JavaScript للاستماع لجميع أحداث الأحداث الثلاثة المحتملة للحركة. تعمل هذه الشيفرة على ضبط مستمعي الأحداث لدينا؛ نستدعِيها عند تحميل المستند لأول مرة من أجل إعداد ما يلزم.
var element = document.getElementById("watchme");
element.addEventListener("animationstart", listener, false);
element.addEventListener("animationend", listener, false);
element.addEventListener("animationiteration", listener, false);

element.className = "slidein";
هذه شيفرة معيارية جميلة، يمكنك الحصول على تفاصيل حول كيفية عملها من خلال توثيق eventTarget.addEventListener()‎ آخر شيء تفعله هذه الشيفرة هو تعيين الصنف "slidein" للعنصر الذي نريد تحريكه؛ وذلك لبدء الحركة. لماذا؟ لأن الحدث animationstart يبدأ بمجرد بدء الحركة، وفي حالتنا يحدث ذلك قبل تشغيل الشيفرة. لذلك سنبدأ الحركة بأنفسنا عن طريق تعيين صنف العنصر على النمط الذي يُحركه بعد حدوثه.

استقبال الحدث

يُمرر الحدث للدالة ()listener الموضحة في الشيفرة التالية:
function listener(event) {
  var l = document.createElement("li");
  switch(event.type) {
    case "animationstart":
      l.innerHTML = "Started: elapsed time is " + event.elapsedTime;
      break;
    case "animationend":
      l.innerHTML = "Ended: elapsed time is " + event.elapsedTime;
      break;
    case "animationiteration":
      l.innerHTML = "New loop started at time " + event.elapsedTime;
      break;
  }
  document.getElementById("output").appendChild(l);
}
هذه الشيفرة أيضًا بسيطة جدًا، يبحث في التابع event.type لتحديد نوع حدث الحركة الذي حدث، ثم يضيف ملاحظة مناسبة إلى عنصر القائمة غير المرتبة <ul> التي نستخدمها لتسجيل هذه الأحداث.

النتيجة عند انتهاء التنفيذ ستكون كالتالي:

  • البداية: الوقت المنقضي هو 0
  • بداية حلقة تكرار جديدة في الوقت 3.01200008392334
  • بداية حلقة تكرار جديدة في وقت 6.00600004196167
  • الانتهاء: الوقت المنقضي هو 9.234000205993652 لاحظ أن الأوقات متقاربة جدًا، ولكن ليس بالضبط، تلك الأوقات المتوقعة بالنظر إلى التوقيت الذي أُنْشِئَ عند ضبط الحركة. لاحظ أيضًا أنه لايُرسل حدث الحركة بعد التكرار النهائي للحركة؛ بل يُرسل الحدث animationend.

شيفرة HTML

فقط لإكمال الفكرة، إليك شيفرة HTML التي تعرض محتوى الصفحة، بما في ذلك القائمة التي يُدرَج فيها النص البرمجي معلومات حول الأحداث المستلمة:
<h1 id="watchme">Watch me move</h1>
<p>
  This example shows how to use CSS animations to make <code>H1</code>
  elements move across the page.
</p>
<p>
  In addition, we output some text each time an animation event fires,
  so you can see them in action.
</p>
<ul id="output">
</ul>

اقرأ أيضًا

المصادر