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