أربع ميزات جديدة في CSS تتيح لك الدخول والخروج بسلاسة من خلال الصور المتحركة.

تُعدّ الحركة جزءًا أساسيًا من أي تجربة رقمية، إذ ترشد المستخدم من تفاعل إلى آخر. ولكن هناك بعض الفجوات في الرسومات المتحركة السلسة على منصة الويب. وتشمل هذه الميزات إمكانية إضافة صور متحركة بسهولة إلى مؤثرات الدخول والخروج، وإضافة صور متحركة بسلاسة إلى الطبقة العليا من العناصر التي يمكن إغلاقها، مثل مربّعات الحوار والنوافذ المنبثقة.

لسدّ هذه الفجوات، يتضمّن الإصداران 116 و117 من Chrome أربع ميزات جديدة لمنصّة الويب، ما يتيح استخدام الرسوم المتحرّكة والانتقالات السلسة للمواقع المنفصلة.

تشمل هذه الميزات الأربعة الجديدة ما يلي:

  • إمكانية إضافة رسوم متحركة إلى display وcontent-visibility على مخطط زمني للإطارات الرئيسية (بدءًا من الإصدار 116 من Chrome)
  • سمة transition-behavior التي تحتوي على الكلمة الرئيسية allow-discrete لتفعيل عمليات النقل بين المواقع المنفصلة، مثل display (من الإصدار 117 من Chrome)
  • قاعدة @starting-style لإضافة تأثيرات متحركة عند الدخول من display: none إلى الطبقة العليا (من Chrome 117)
  • سمة overlay للتحكّم في سلوك الطبقة العليا أثناء عرض صورة متحركة (من Chrome 117)

عرض الصور المتحركة في الإطارات الرئيسية

اعتبارًا من الإصدار 116 من Chrome، يمكنك استخدام display وcontent-visibility في قواعد اللقطات الرئيسية. وسيتم تبديلهما بعد ذلك في وقت ظهور اللقطة الرئيسية. ولا يلزم توفير قيم جديدة إضافية لتفعيل هذه الميزة:

.card {
  animation: fade-out 0.5s forwards;
}

@keyframes fade-out {
  100% {
    opacity: 0;
    display: none;
  }
}

يُظهر المثال السابق تأثيرًا متحركًا لمعدل الشفافية إلى 0 على مدار مدة 0.5 ثانية، ثم يضبط العرض على "بدون". بالإضافة إلى ذلك، تضمن الكلمة الرئيسية forwards بقاء الحركة في حالتها النهائية، بحيث يظل العنصر الذي يتم تطبيقها عليه display: none وopacity: 0.

هذا مثال بسيط يحاكي ما يمكنك فعله باستخدام انتقال (راجِع العرض الترويجي في قسم الانتقال). ومع ذلك، لا يمكن للانتقالات إنشاء صور متحركة أكثر تعقيدًا، مثل المثال التالي:

.card {
  animation: spin-and-delete 1s ease-in forwards;
}

@keyframes spin-and-delete {
  0% {
    transform: rotateY(0);
    filter: hue-rotate(0);
  }
  80% {
    transform: rotateY(360deg);
    filter: hue-rotate(180deg);
    opacity: 1;
  }
  100% {
    opacity: 0;
    display: none;
  }
}

الصورة المتحركة spin-and-delete هي صورة متحركة للخروج. أولاً، ستدور البطاقة على محور y، وستتم إعادة ترتيب تدرّج الألوان، ثم في 80% على المخطط الزمني، ستتم إزالة الشفافية من 1 إلى 0. أخيرًا، يتم تبديل البطاقة من display: block إلى display: none.

بالنسبة إلى صور الخروج المتحركة هذه، يمكنك إعداد عامل تشغيل للصور المتحركة بدلاً من تطبيقها مباشرةً على عنصر. على سبيل المثال، من خلال إرفاق أداة معالجة أحداث بزر يؤدي إلى تنشيط فئة لتطبيق الصورة المتحركة، على النحو التالي:

.spin-out {
   animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
 document.querySelector('.card').classList.add('spin-out');
})

أصبح المثال أعلاه يتضمّن الآن حالة نهاية display:none. هناك العديد من الحالات التي قد تحتاج فيها إلى مزيد من الخطوات وإزالة عقدة DOM مع مهلة للسماح بإنهاء الحركة أولاً.

الانتقال إلى صور متحركة منفصلة

على عكس الرسوم المتحركة للخصائص المنفصلة باستخدام الإطارات الرئيسية، عليك استخدام وضع سلوك الانتقال allow-discrete لنقل الخصائص المنفصلة.

سمة transition-behavior

يُتيح وضع allow-discrete إجراء التحولات المنفصلة، وهو قيمة لسمة transition-behavior. تقبل السمة transition-behavior قيمتَين: normal وallow-discrete.

.card {
  transition: opacity 0.25s, display 0.25s;
  transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}

.card.fade-out {
  opacity: 0;
  display: none;
}
ملاحظة: يعرض هذا العرض التوضيحي للانتقال أسلوبًا مختلفًا عن العرض التوضيحي الأول للحركة ولكنّه يبدو مشابهًا من الناحية المرئية.

يحدّد الاختصار transition هذه القيمة أيضًا، لذا يمكنك حذف السمة واستخدام الكلمة الرئيسية allow-discrete في نهاية الاختصار transition لكل انتقال بدلاً من ذلك.

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

إذا كنت تضيف تأثيرًا متحركًا إلى عدة عناصر منفصلة، عليك تضمين allow-discrete بعد كل عنصر تريد إضافة تأثير متحرك إليه. على سبيل المثال:

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

قاعدة @starting-style للصور المتحركة عند الدخول

حتى الآن، تناولت هذه المقالة الرسوم المتحرّكة للخروج، ولإنشاء الرسوم المتحرّكة للدخول، عليك استخدام القاعدة @starting-style.

استخدِم @starting-style لتطبيق نمط يمكن للمتصفّح البحث عنه قبل فتح العنصر على الصفحة. هذه هي حالة "قبل الفتح" (حيث تبدأ الحركة).

/*  0. IS-OPEN STATE   */
/*  The state at which the element is open + transition logic */
.item {
  height: 3rem;
  display: grid;
  overflow: hidden;
  transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}

/*  1. BEFORE-OPEN STATE   */
/*  Starting point for the transition */
@starting-style {
  .item {
    opacity: 0;
    height: 0;
  }
}

/*  2. EXITING STATE   */
/*  While it is deleting, before DOM removal in JS, apply this
    transformation for height, opacity, and a transform which
    skews the element and moves it to the left before setting
    it to display: none */
.is-deleting {
  opacity: 0;
  height: 0;
  display: none;
  transform: skewX(50deg) translateX(-25vw);
}

لديك الآن حالة دخول وخروج لعناصر قائمة "المهام التي يجب إكمالها" هذه:

إضافة حركة إلى العناصر من الطبقة العليا وإليها

لإضافة تأثيرات متحركة للعناصر من الطبقة العليا وإليها، حدِّد الرمز @starting-style في الحالة "مفتوح" لإعلام المتصفّح من أين يبدأ تأثير الحركة. بالنسبة إلى مربّع الحوار، يتم تحديد الحالة المفتوحة باستخدام السمة [open]. بالنسبة إلى النافذة المنبثقة، استخدِم الفئة الزائفة :popover-open.

يمكن أن يظهر مثال بسيط لمربّع حوار على النحو التالي:

/*   0. IS-OPEN STATE   */
dialog[open] {
  translate: 0 0;
}

/*   1. BEFORE-OPEN STATE   */
@starting-style {
  dialog[open] {
    translate: 0 100vh;
  }
}

/*   2. EXIT STATE   */
dialog {
  transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
  translate: 0 100vh;
}

في المثال التالي، يختلف تأثيرا الدخول والخروج. يمكنك الدخول من خلال تحريك الصورة المتحركة للأعلى من أسفل إطار العرض، والخروج من التأثير إلى أعلى إطار العرض. ويتم أيضًا كتابتها باستخدام CSS متداخل لمزيد من الحِزم المرئية.

عند إضافة تأثيرات متحركة إلى نافذة منبثقة، استخدِم الفئة الزائفة :popover-open بدلاً من السمة open المستخدَمة سابقًا.

.settings-popover {
  &:popover-open {
    /*  0. IS-OPEN STATE  */
    /*  state when popover is open, BOTH:
        what we're transitioning *in* to 
        and transitioning *out* from */
    transform: translateY(0);
    opacity: 1;

    /*  1. BEFORE-OPEN STATE  */
    /*  Initial state for what we're animating *in* from, 
        in this case: goes from lower (y + 20px) to center  */
    @starting-style {
      transform: translateY(20px);
      opacity: 0;
    }
  }
  
  /*  2. EXIT STATE  */
  /*  Initial state for what we're animating *out* to , 
      in this case: goes from center to (y - 50px) higher */
  transform: translateY(-50px);
  opacity: 0;
  
  /*  Enumerate transitioning properties, 
      including display and allow-discrete mode */
  transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}

overlay الموقع الإلكتروني

أخيرًا، لإخفاء popover أو dialog من الطبقة العليا، أضِف السمة overlay إلى قائمة الانتقالات. تؤدي علامتا التبويب popover وdialog إلى إزالة المقاطع الأصلية والتحويلات، كما تضع المحتوى في الطبقة العليا. إذا لم تنقل العنصر overlay، سيعود إلى القطع والتحويل والتغطية على الفور، ولن ترى عملية النقل تحدث.

[open] {
  transition: opacity 1s, display 1s allow-discrete;
}

بدلاً من ذلك، يمكنك تضمين overlay في الانتقال أو الحركة لتحريك overlay مع بقية الميزات والتأكّد من بقائها في الطبقة العليا عند إضافة الحركة. سيبدو هذا الإجراء أكثر سلاسة.

[open] {
  transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}

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

ملاحظة حول عمليات النقل في العرض

إذا كنت تُجري تغييرات على نموذج DOM، مثل إضافة عناصر وإزالتها من نموذج DOM، يمكنك استخدام عمليات انتقال العرض كحلّ آخر رائع للرسوم المتحركة السلسة. في ما يلي مثالان من الأمثلة أعلاه تم إنشاؤهما باستخدام عمليات انتقال العرض.

في هذا العرض التوضيحي الأول، بدلاً من إعداد @starting-style وعمليات التحويل الأخرى في CSS، ستتولى عمليات انتقال العرض عملية النقل. يتم إعداد انتقال العرض على النحو التالي:

أولاً، في CSS، امنح كل بطاقة view-transition-name فرديًا.

.card-1 {
  view-transition-name: card-1;
}

.card-2 {
  view-transition-name: card-2;
}

/* etc. */

بعد ذلك، في JavaScript، عليك لفّ عملية تغيير DOM (في هذه الحالة، إزالة البطاقة) في عملية انتقال عرض.

deleteBtn.addEventListener('click', () => {
  // Check for browser support
  if (document.startViewTransition) {
    document.startViewTransition(() => {
      // DOM mutation
      card.remove();
    });
  } 
  // Alternative if no browser support
  else {
    card.remove();
  }
})

يمكن للمتصفّح الآن التعامل مع تلاشي كل بطاقة وتحويلها إلى موضعها الجديد.

ويمكنك الاستفادة من هذه الميزة أيضًا في العرض الترويجي لإضافة/إزالة عناصر القائمة. في هذه الحالة، عليك إضافة view-transition-name فريد لكل بطاقة تم إنشاؤها.

الخاتمة

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