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

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

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

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

  • إمكانية تحريك display وcontent-visibility على مخطط زمني للإطار الرئيسي (من Chrome 116)
  • تشير السمة transition-behavior إلى الكلمة الرئيسية allow-discrete لتفعيل عمليات نقل الخصائص المنفصلة مثل display (من Chrome 117).
  • القاعدة @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 هي صورة متحركة عند الخروج. أولاً، ستدور البطاقة على المحور الصادي، وسيتم إجراؤها من خلال تدوير تدرُّج تدرُّج الألوان، ثم في 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. BEFORE-OPEN STATE   */
/*  Starting point for the transition */
@starting-style {
  .item {
    opacity: 0;
    height: 0;
  }
}

/*  1. 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;
}

/*  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. BEFORE-OPEN STATE   */
@starting-style {
  dialog[open] {
    translate: 0 100vh;
  }
}

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

/*   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. 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;
    }
    
    /*  1. IS-OPEN STATE  */
    /*  state when popover is open, BOTH:
        what we're transitioning *in* to 
        and transitioning *out* from */
    transform: translateY(0);
    opacity: 1;
  }
  
  /*  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 فريد لكل بطاقة يتم إنشاؤها.

الخلاصة

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