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

جوي أرهار
جوي أرهار

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

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

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

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

بدءًا من الإصدار 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. 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" لتخبر المتصفح بالمكان الذي سيتم تحريكه منه. في مربّع الحوار، يتم تحديد الحالة "مفتوح" من خلال السمة [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، مثل إضافة عناصر وإزالتها من نموذج العناصر في المستند، يتوفّر حل آخر رائع للصور المتحركة السلسة وهو الانتقالات في طريقة العرض. في ما يلي مثالان من الأمثلة السابقة تم إنشاؤها باستخدام الانتقالات في طريقة العرض.

في هذا العرض التوضيحي الأول، ستعالج عمليات النقل من طرق العرض عملية النقل، بدلاً من إعداد @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 فريد لكل بطاقة يتم إنشاؤها.

الخلاصة

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