أربع ميزات جديدة في 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 فريد لكل بطاقة يتم إنشاؤها.

الخاتمة

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