أطلق العنان لتجارب ويب سلسة شبيهة بالتطبيقات. يستكشف هذا الدليل الشامل العناصر الزائفة القوية لانتقالات عرض CSS لتنسيق انتقالات الصفحات الديناميكية، مع أمثلة عملية وأفضل الممارسات.
إتقان انتقالات عرض CSS: دليل متعمق لتنسيق العناصر الزائفة
في المشهد دائم التطور لتطوير الويب، يعد السعي وراء تجربة مستخدم سلسة وجذابة أمرًا ثابتًا. لسنوات، سعى المطورون جاهدين لسد الفجوة بين الويب والتطبيقات الأصلية، خاصة فيما يتعلق بسلاسة انتقالات الصفحات. غالبًا ما يؤدي التنقل التقليدي عبر الويب إلى إعادة تحميل قاسية للصفحة بأكملها - شاشة بيضاء فارغة تقطع انغماس المستخدم للحظات. لقد خففت تطبيقات الصفحة الواحدة (SPAs) من هذا الأمر، لكن إنشاء انتقالات مخصصة وذات مغزى ظل مهمة معقدة وغالبًا ما تكون هشة، وتعتمد بشكل كبير على مكتبات جافا سكريبت وإدارة الحالة المعقدة.
نقدم لكم واجهة برمجة تطبيقات انتقالات عرض CSS (CSS View Transitions API)، وهي تقنية ثورية ستغير الطريقة التي نتعامل بها مع تغييرات واجهة المستخدم على الويب. توفر واجهة برمجة التطبيقات القوية هذه آلية بسيطة ومرنة بشكل لا يصدق للتحريك بين حالات DOM المختلفة، مما يجعل إنشاء التجارب المصقولة الشبيهة بالتطبيقات التي يتوقعها المستخدمون أسهل من أي وقت مضى. في قلب قوة واجهة برمجة التطبيقات هذه تكمن مجموعة من عناصر CSS الزائفة الجديدة. هذه ليست محدداتك النموذجية؛ إنها عناصر ديناميكية ومؤقتة ينشئها المتصفح لمنحك تحكمًا دقيقًا في كل مرحلة من مراحل الانتقال. سيأخذك هذا الدليل في رحلة عميقة إلى شجرة العناصر الزائفة هذه، مستكشفًا كيفية تنسيق كل مكون لبناء رسوم متحركة مذهلة وعالية الأداء ومتاحة لجمهور عالمي.
تشريح انتقال العرض
قبل أن نتمكن من تنسيق انتقال، يجب أن نفهم ما يحدث تحت الغطاء عند تشغيله. عندما تبدأ انتقال عرض (على سبيل المثال، عن طريق استدعاء document.startViewTransition())، يقوم المتصفح بسلسلة من الخطوات:
- التقاط الحالة القديمة: يأخذ المتصفح "لقطة شاشة" لحالة الصفحة الحالية.
- تحديث DOM: يقوم كودك بعد ذلك بإجراء تغييراته على DOM (مثل الانتقال إلى عرض جديد، إضافة أو إزالة عناصر).
- التقاط الحالة الجديدة: بمجرد اكتمال تحديث DOM، يأخذ المتصفح لقطة شاشة للحالة الجديدة.
- بناء شجرة العناصر الزائفة: يقوم المتصفح بعد ذلك ببناء شجرة مؤقتة من العناصر الزائفة في طبقة تراكب الصفحة. تحتوي هذه الشجرة على الصور الملتقطة للحالتين القديمة والجديدة.
- التحريك: يتم تطبيق رسوم CSS المتحركة على هذه العناصر الزائفة، مما يخلق انتقالًا سلسًا من الحالة القديمة إلى الجديدة. الافتراضي هو التلاشي المتقاطع البسيط.
- التنظيف: بمجرد اكتمال الرسوم المتحركة، تتم إزالة شجرة العناصر الزائفة، ويمكن للمستخدم التفاعل مع DOM الجديد المباشر.
مفتاح التخصيص هو شجرة العناصر الزائفة المؤقتة هذه. فكر فيها كمجموعة من الطبقات في أداة تصميم، موضوعة مؤقتًا فوق صفحتك. لديك سيطرة كاملة عبر CSS على هذه الطبقات. إليك الهيكل الذي ستعمل به:
- ::view-transition
- ::view-transition-group(*)
- ::view-transition-image-pair(*)
- ::view-transition-old(*)
- ::view-transition-new(*)
- ::view-transition-image-pair(*)
- ::view-transition-group(*)
دعنا نحلل ما يمثله كل من هذه العناصر الزائفة.
طاقم العناصر الزائفة
::view-transition: هذا هو جذر الهيكل بأكمله. إنه عنصر واحد يملأ إطار العرض ويقع فوق كل محتوى الصفحة الآخر. يعمل كحاوية لجميع المجموعات الانتقالية وهو مكان رائع لتعيين خصائص الانتقال الشاملة مثل المدة أو دالة التوقيت.
::view-transition-group(*): لكل عنصر انتقالي مميز (يتم تحديده بواسطة خاصية CSS view-transition-name)، يتم إنشاء مجموعة. هذا العنصر الزائف مسؤول عن تحريك موضع وحجم محتواه. إذا كان لديك بطاقة تنتقل من جانب من الشاشة إلى آخر، فإن ::view-transition-group هو الذي يتحرك بالفعل.
::view-transition-image-pair(*): متداخل داخل المجموعة، يعمل هذا العنصر كحاوية وقناع قص (clipping mask) للعروض القديمة والجديدة. دوره الأساسي هو الحفاظ على تأثيرات مثل border-radius أو transform أثناء التحريك والتعامل مع التحريك الافتراضي للتلاشي المتقاطع.
::view-transition-old(*): يمثل هذا "لقطة الشاشة" أو العرض المعالج للعنصر في حالته القديمة (قبل تغيير DOM). بشكل افتراضي، يتحرك من opacity: 1 إلى opacity: 0.
::view-transition-new(*): يمثل هذا "لقطة الشاشة" أو العرض المعالج للعنصر في حالته الجديدة (بعد تغيير DOM). بشكل افتراضي، يتحرك من opacity: 0 إلى opacity: 1.
الجذر: تنسيق العنصر الزائف ::view-transition
العنصر الزائف ::view-transition هو اللوحة التي يتم رسم حركتك بأكملها عليها. كونه الحاوية ذات المستوى الأعلى، فهو المكان المثالي لتعريف الخصائص التي يجب تطبيقها عالميًا على الانتقال. بشكل افتراضي، يوفر المتصفح مجموعة من الرسوم المتحركة، ولكن يمكنك تجاوزها بسهولة.
على سبيل المثال، الانتقال الافتراضي هو تلاشي متقاطع يستمر 250 ميلي ثانية. إذا كنت ترغب في تغيير هذا لكل انتقال على موقعك، يمكنك استهداف العنصر الزائف الجذر:
::view-transition {
animation-duration: 500ms;
animation-timing-function: ease-in-out;
}
هذه القاعدة البسيطة تجعل الآن جميع تلاشي الصفحات الافتراضي يستغرق ضعف المدة ويستخدم منحنى 'ease-in-out'، مما يمنحها إحساسًا مختلفًا قليلاً. بينما يمكنك تطبيق رسوم متحركة معقدة هنا، فمن الأفضل عمومًا استخدامه لتعريف التوقيت والتسريع الشامل، وترك العناصر الزائفة الأكثر تحديدًا تتعامل مع التصميم التفصيلي.
التجميع والتسمية: قوة الخاصية `view-transition-name`
بشكل افتراضي، وبدون أي عمل إضافي، توفر واجهة برمجة تطبيقات انتقالات العرض تلاشيًا متقاطعًا للصفحة بأكملها. يتم التعامل مع هذا بواسطة مجموعة عناصر زائفة واحدة للجذر. يتم إطلاق العنان للقوة الحقيقية لواجهة برمجة التطبيقات عندما تريد انتقال عناصر محددة وفردية بين الحالات. على سبيل المثال، جعل صورة مصغرة لمنتج في صفحة قائمة تنمو وتتحرك بسلاسة إلى موضع صورة المنتج الرئيسية في صفحة التفاصيل.
لإخبار المتصفح بأن عنصرين عبر حالات DOM مختلفة هما نفس الشيء من الناحية المفاهيمية، يمكنك استخدام خاصية CSS view-transition-name. يجب تطبيق هذه الخاصية على كل من العنصر المبدئي والعنصر النهائي.
/* في CSS صفحة القائمة */
.product-thumbnail {
view-transition-name: product-image;
}
/* في CSS صفحة التفاصيل */
.main-product-image {
view-transition-name: product-image;
}
من خلال إعطاء كلا العنصرين نفس الاسم الفريد ('product-image' في هذه الحالة)، فإنك توجه المتصفح: "بدلاً من مجرد تلاشي الصفحة القديمة وظهور الصفحة الجديدة، قم بإنشاء انتقال خاص لهذا العنصر المحدد." سيقوم المتصفح الآن بإنشاء ::view-transition-group(product-image) مخصص للتعامل مع حركته بشكل منفصل عن تلاشي الجذر. هذا هو المفهوم الأساسي الذي يتيح تأثير الانتقال "التشكلي" أو "العنصر المشترك" الشهير.
ملاحظة هامة: في أي لحظة معينة أثناء الانتقال، يجب أن يكون view-transition-name فريدًا. لا يمكن أن يكون لديك عنصران مرئيان بنفس الاسم في نفس الوقت.
تنسيق متعمق: العناصر الزائفة الأساسية
مع تسمية عناصرنا، يمكننا الآن الغوص في تنسيق العناصر الزائفة المحددة التي ينشئها المتصفح لها. هنا يمكنك إنشاء رسوم متحركة مخصصة ومعبرة حقًا.
`::view-transition-group(name)`: المحرك
المسؤولية الوحيدة للمجموعة هي الانتقال من حجم وموضع العنصر القديم إلى حجم وموضع العنصر الجديد. لا تحتوي على المظهر الفعلي للمحتوى، بل فقط صندوقه المحيط. فكر فيه كإطار متحرك.
بشكل افتراضي، يقوم المتصفح بتحريك خصائص transform و width/height الخاصة به. يمكنك تجاوز هذا لإنشاء تأثيرات مختلفة. على سبيل المثال، يمكنك إضافة قوس إلى حركته عن طريق تحريكه على طول مسار منحني، أو جعله يتوسع ويتقلص أثناء رحلته.
::view-transition-group(product-image) {
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
في هذا المثال، نقوم بتطبيق دالة تسريع محددة فقط على حركة صورة المنتج، مما يجعلها تبدو أكثر ديناميكية ومادية، دون التأثير على التلاشي الافتراضي لبقية الصفحة.
`::view-transition-image-pair(name)`: القاص والمخفي
متداخل داخل المجموعة المتحركة، يحتفظ زوج الصور (image-pair) بالعروض القديمة والجديدة. يعمل كقناع قص، لذا إذا كان العنصر الخاص بك يحتوي على border-radius، يضمن زوج الصور أن يظل المحتوى مقصوصًا بهذا نصف القطر طوال حركة الحجم والموضع. وظيفته الرئيسية الأخرى هي تنظيم التلاشي المتقاطع الافتراضي بين المحتوى القديم والجديد.
قد ترغب في تنسيق هذا العنصر لضمان الاتساق البصري أو لإنشاء تأثيرات أكثر تقدمًا. خاصية رئيسية يجب مراعاتها هي isolation: isolate. هذا أمر بالغ الأهمية إذا كنت تخطط لاستخدام تأثيرات mix-blend-mode متقدمة على العناصر الأبناء (القديمة والجديدة)، حيث إنها تنشئ سياق تكديس جديد وتمنع المزج من التأثير على العناصر خارج مجموعة الانتقال.
::view-transition-image-pair(product-image) {
isolation: isolate;
}
`::view-transition-old(name)` و `::view-transition-new(name)`: نجوم العرض
هذه هي العناصر الزائفة التي تمثل المظهر المرئي للعنصر الخاص بك قبل وبعد تغيير DOM. هذا هو المكان الذي سيحدث فيه معظم عملك في الرسوم المتحركة المخصصة. بشكل افتراضي، يقوم المتصفح بتشغيل حركة تلاشي متقاطع بسيطة عليها باستخدام opacity و mix-blend-mode. لإنشاء حركة مخصصة، يجب أولاً إيقاف الحركة الافتراضية.
::view-transition-old(name),
::view-transition-new(name) {
animation: none;
}
بمجرد تعطيل الحركة الافتراضية، أنت حر في تطبيق حركتك الخاصة. دعنا نستكشف بعض الأنماط الشائعة.
حركة مخصصة: الانزلاق
بدلاً من التلاشي المتقاطع، دعنا نجعل محتوى الحاوية ينزلق للداخل. على سبيل المثال، عند التنقل بين المقالات، نريد أن ينزلق نص المقال الجديد من اليمين بينما ينزلق النص القديم إلى اليسار.
أولاً، حدد الإطارات الرئيسية (keyframes):
@keyframes slide-from-right {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
@keyframes slide-to-left {
from { transform: translateX(0); }
to { transform: translateX(-100%); }
}
الآن، طبق هذه الحركات على العناصر الزائفة القديمة والجديدة للعنصر المسمى 'article-content'.
::view-transition-old(article-content) {
animation: 300ms ease-out forwards slide-to-left;
}
::view-transition-new(article-content) {
animation: 300ms ease-out forwards slide-from-right;
}
حركة مخصصة: قلب ثلاثي الأبعاد
للحصول على تأثير أكثر دراماتيكية، يمكنك إنشاء قلب بطاقة ثلاثي الأبعاد. يتطلب هذا تحريك خاصية transform باستخدام rotateY وأيضًا إدارة backface-visibility.
/* المجموعة تحتاج إلى سياق ثلاثي الأبعاد */
::view-transition-group(card-flipper) {
transform-style: preserve-3d;
}
/* زوج الصور يحتاج أيضًا إلى الحفاظ على السياق ثلاثي الأبعاد */
::view-transition-image-pair(card-flipper) {
transform-style: preserve-3d;
}
/* العرض القديم يقلب من 0 إلى -180 درجة */
::view-transition-old(card-flipper) {
animation: 600ms ease-in forwards flip-out;
backface-visibility: hidden;
}
/* العرض الجديد يقلب من 180 إلى 0 درجة */
::view-transition-new(card-flipper) {
animation: 600ms ease-out forwards flip-in;
backface-visibility: hidden;
}
@keyframes flip-out {
from { transform: rotateY(0deg); }
to { transform: rotateY(-180deg); }
}
@keyframes flip-in {
from { transform: rotateY(180deg); }
to { transform: rotateY(0deg); }
}
أمثلة عملية وتقنيات متقدمة
النظرية مفيدة، لكن التطبيق العملي هو حيث نتعلم حقًا. دعنا نستعرض بعض السيناريوهات الشائعة وكيفية حلها باستخدام عناصر انتقالات العرض الزائفة.
مثال: الصورة المصغرة للبطاقة "المتشكلة"
هذا هو انتقال العنصر المشترك الكلاسيكي. تخيل معرضًا لملفات تعريف المستخدمين. كل ملف تعريف عبارة عن بطاقة بها صورة رمزية. عند النقر فوق بطاقة، تنتقل إلى صفحة تفاصيل حيث يتم عرض نفس الصورة الرمزية بشكل بارز في الأعلى.
الخطوة 1: تعيين الأسماء
في صفحة المعرض الخاصة بك، تحصل الصورة الرمزية على اسم. يجب أن يكون الاسم فريدًا لكل بطاقة، على سبيل المثال، بناءً على معرف المستخدم.
/* في gallery-item.css */
.card-avatar { view-transition-name: avatar-user-123; }
في صفحة تفاصيل الملف الشخصي، تحصل الصورة الرمزية الكبيرة في العنوان على نفس الاسم تمامًا.
/* في profile-page.css */
.profile-header-avatar { view-transition-name: avatar-user-123; }
الخطوة 2: تخصيص الحركة
بشكل افتراضي، سيقوم المتصفح بتحريك وتغيير حجم الصورة الرمزية، ولكنه سيقوم أيضًا بتلاشي متقاطع للمحتوى. إذا كانت الصورة متطابقة، فإن هذا التلاشي غير ضروري ويمكن أن يسبب وميضًا طفيفًا. يمكننا تعطيله.
/* النجمة (*) هنا هي حرف بدل لأي مجموعة مسماة */
::view-transition-image-pair(*) {
/* تعطيل التلاشي الافتراضي */
animation-duration: 0s;
}
انتظر، إذا قمنا بتعطيل التلاشي، فكيف يتم تبديل المحتوى؟ بالنسبة للعناصر المشتركة حيث تكون العروض القديمة والجديدة متطابقة، يكون المتصفح ذكيًا بما يكفي لاستخدام عرض واحد فقط للانتقال بأكمله. يحتفظ `image-pair` بشكل أساسي بصورة واحدة فقط، لذا فإن تعطيل التلاشي يكشف ببساطة عن هذا التحسين. بالنسبة للعناصر التي يتغير فيها المحتوى بالفعل، ستحتاج إلى حركة مخصصة بدلاً من التلاشي الافتراضي.
التعامل مع تغييرات نسبة العرض إلى الارتفاع
ينشأ تحدي شائع عندما يغير عنصر انتقالي نسبة العرض إلى الارتفاع الخاصة به. على سبيل المثال، قد تنتقل صورة مصغرة أفقية بنسبة 16:9 في صفحة قائمة إلى صورة رمزية مربعة بنسبة 1:1 في صفحة التفاصيل. السلوك الافتراضي للمتصفح هو تحريك العرض والارتفاع بشكل مستقل، مما يؤدي إلى ظهور الصورة مضغوطة أو ممتدة أثناء الانتقال.
الحل أنيق. ندع ::view-transition-group يتعامل مع تغيير الحجم والموضع، لكننا نتجاوز تنسيق الصور القديمة والجديدة بداخله.
الهدف هو جعل "لقطات الشاشة" القديمة والجديدة تملأ حاويتها دون تشويه. يمكننا القيام بذلك عن طريق تعيين عرضها وارتفاعها على 100% والسماح لخاصية object-fit الافتراضية للمتصفح (التي يتم توريثها من العنصر الأصلي) بالتعامل مع القياس بشكل صحيح.
::view-transition-old(hero-image),
::view-transition-new(hero-image) {
/* منع التشويه عن طريق ملء الحاوية */
width: 100%;
height: 100%;
/* تجاوز التلاشي المتقاطع الافتراضي لرؤية التأثير بوضوح */
animation: none;
}
باستخدام هذا CSS، سيقوم `image-pair` بتحريك نسبة العرض إلى الارتفاع الخاصة به بسلاسة، وسيتم قص الصور بالداخل أو وضع أشرطة سوداء لها (اعتمادًا على قيمة `object-fit` الخاصة بها)، تمامًا كما لو كانت في حاوية عادية. يمكنك بعد ذلك إضافة الرسوم المتحركة المخصصة الخاصة بك، مثل التلاشي المتقاطع، فوق هذه الهندسة المصححة.
التصحيح ودعم المتصفحات
قد يكون تنسيق العناصر التي توجد فقط لجزء من الثانية أمرًا صعبًا. لحسن الحظ، توفر المتصفحات الحديثة أدوات مطور ممتازة لهذا الغرض. في أدوات مطوري Chrome أو Edge، يمكنك الانتقال إلى لوحة "Animations"، وعندما تقوم بتشغيل انتقال عرض، يمكنك إيقافه مؤقتًا. مع إيقاف الحركة مؤقتًا، يمكنك بعد ذلك استخدام لوحة "Elements" لفحص شجرة العناصر الزائفة `::view-transition` بأكملها تمامًا مثل أي جزء آخر من DOM. يمكنك رؤية الأنماط التي يتم تطبيقها وحتى تعديلها في الوقت الفعلي لإتقان الرسوم المتحركة الخاصة بك.
اعتبارًا من أواخر عام 2023، يتم دعم واجهة برمجة تطبيقات انتقالات العرض في المتصفحات المستندة إلى Chromium (Chrome، Edge، Opera). والتطبيقات قيد التنفيذ لـ Firefox و Safari. هذا يجعلها مرشحًا مثاليًا للتحسين التدريجي. يحصل المستخدمون الذين لديهم متصفحات مدعومة على تجربة محسنة وممتعة، بينما يحصل المستخدمون على متصفحات أخرى على التنقل الفوري القياسي. يمكنك التحقق من الدعم في CSS:
@supports (view-transition: none) {
/* جميع أنماط view-transition تذهب هنا */
::view-transition-old(my-element) { ... }
}
أفضل الممارسات لجمهور عالمي
عند تنفيذ الرسوم المتحركة، من الضروري مراعاة النطاق المتنوع للمستخدمين والأجهزة في جميع أنحاء العالم.
الأداء: يجب أن تكون الرسوم المتحركة سريعة وسلسة. التزم بتحريك خصائص CSS التي تكون رخيصة على المتصفح لمعالجتها، وبشكل أساسي transform و opacity. يمكن أن يؤدي تحريك خصائص مثل width أو height أو margin إلى إعادة حساب التخطيط في كل إطار، مما يؤدي إلى التقطيع وتجربة سيئة، خاصة على الأجهزة منخفضة الطاقة.
إمكانية الوصول: يعاني بعض المستخدمين من دوار الحركة أو عدم الراحة من الرسوم المتحركة. توفر جميع أنظمة التشغيل الرئيسية تفضيلًا للمستخدم لتقليل الحركة. يجب أن نحترم هذا. يتيح لك استعلام الوسائط prefers-reduced-motion تعطيل أو تبسيط الرسوم المتحركة لهؤلاء المستخدمين.
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
/* تخطي جميع الرسوم المتحركة المخصصة واستخدام تلاشي سريع وبسيط */
animation: none !important;
}
}
تجربة المستخدم (UX): الانتقالات الجيدة هادفة. يجب أن توجه انتباه المستخدم وتوفر سياقًا حول التغيير الذي يحدث في واجهة المستخدم. يمكن أن تجعل الحركة البطيئة جدًا التطبيق يبدو بطيئًا، في حين أن الحركة المبهرجة جدًا يمكن أن تكون مشتتة للانتباه. استهدف مدد انتقال تتراوح بين 200 و 500 ميلي ثانية. الهدف هو أن تكون الحركة محسوسة أكثر من كونها مرئية.
الخاتمة: المستقبل أكثر سلاسة
تمثل واجهة برمجة تطبيقات انتقالات عرض CSS، وتحديداً شجرة العناصر الزائفة القوية الخاصة بها، قفزة هائلة إلى الأمام لواجهات مستخدم الويب. إنها توفر للمطورين مجموعة أدوات أصلية وعالية الأداء وقابلة للتخصيص بدرجة عالية لإنشاء هذا النوع من الانتقالات السلسة والحالة التي كانت في السابق حكرًا على التطبيقات الأصلية. من خلال فهم أدوار ::view-transition و ::view-transition-group وأزواج الصور old/new، يمكنك تجاوز التلاشي البسيط وتصميم رسوم متحركة معقدة وذات مغزى تعزز قابلية الاستخدام وتُسعد المستخدمين.
مع توسع دعم المتصفحات، ستصبح واجهة برمجة التطبيقات هذه جزءًا أساسيًا من مجموعة أدوات مطور الواجهات الأمامية الحديث. من خلال تبني قدراتها والالتزام بأفضل الممارسات للأداء وإمكانية الوصول، يمكننا بناء ويب ليس فقط أكثر وظيفية ولكن أيضًا أكثر جمالًا وبديهية للجميع في كل مكان.