نسّق التمرير المغناطيسي، وانتقالات الحالة التي يحرّكها المتصفح، والاحترام الصارم لـ prefers-reduced-motion.
افتح هذا الدرس في Kodokonيشترك في المحاذاة عند التمرير طرفان: تحدّد الحاوية منفذ محاذاة (snapport) (مساحتها المرئية، مُقلَّصة بـ scroll-padding) واستراتيجيةً عبر scroll-snap-type - proximity لا يحاذي إلا قرب نقطة محاذاة، بينما mandatory يضمن أن تحطّ دائمًا على واحدة، حتى بعد تمرير برمجي. ويعلن الأبناء عن منطقة محاذاتهم بـ scroll-snap-align (قابلة للضبط عبر scroll-margin). دقيقة قلّ من يعرفها: أثناء تمرير سريع، قد يتخطى المتصفح عدة نقاط محاذاة بشكل مشروع؛ ويجبره scroll-snap-stop: always على التوقف عند كل نقطة، وهذا أساسي لدوّار على نمط القصص.
.carousel {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-padding-inline: 1rem;
}
.carousel > article {
flex: 0 0 80%;
scroll-snap-align: center;
scroll-snap-stop: always;
}تحرّك واجهة View Transitions API تغيّر حالة DOM دون أي مكتبة. يلتقط document.startViewTransition(callback) لقطة بصرية للحالة الحالية، ثم يشغّل ردّ ندائك (الذي يطفر DOM)، ثم يحرّك الانتقال بين الحالتين القديمة والجديدة. وفي الخفاء، يبني المتصفح شجرةً من العناصر الزائفة فوق الصفحة: يحتوي ::view-transition على عناصر ::view-transition-group، يحمل كل منها ::view-transition-old (اللقطة، وهي محتوى مستبدَل يشبه صورة) و::view-transition-new (التمثيل الحي). والافتراضي: تلاشٍ متقاطع. وتكون الصفحة غير تفاعلية أثناء الانتقال.
function applyUpdate(updateDom) {
if (!document.startViewTransition) {
updateDom();
return;
}
document.startViewTransition(() => updateDom());
}تأتي القوة الحقيقية من view-transition-name: يُستخرَج العنصر المسمّى إلى مجموعة انتقال خاصة به. فإن وُجد عنصر بنفس الاسم قبل الانتقال وبعده، يستوفي المتصفح تلقائيًا الموضع والحجم بين الاثنين - وهو تأثير التحوّل من صورة مصغّرة إلى عرضها بملء الشاشة، دون سطر واحد من JavaScript للحركة. ويجب أن يكون كل اسم فريدًا على الصفحة في أي لحظة، وإلا هُجِر الانتقال. وتُنسَّق العناصر الزائفة بحركات CSS عادية.
.hero-thumb { view-transition-name: hero; }
::view-transition-old(hero),
::view-transition-new(hero) {
animation-duration: 0.4s;
animation-timing-function: ease-in-out;
}يبقى واجب إمكانية الوصول: يشير prefers-reduced-motion: reduce إلى مستخدم حسّاس للحركة (اضطرابات دهليزية، صداع نصفي). التقليل لا يعني الإزالة: يبقى تلاشي الشفافية مقبولًا؛ إنما الحركات الكبيرة والتكبيرات وتأثيرات المنظر (parallax) هي ما يجب تحييده. أنت تعرف مسبقًا التجاوز الدفاعي الشامل في CSS (مُدد شبه صفرية، تناولناه في الوحدة السابقة)؛ وتضيف انتقالات العرض جبهة ثانية: من جانب JavaScript، استعلم عن window.matchMedia("(prefers-reduced-motion: reduce)") قبل إطلاق انتقال أو تمرير متحرك.
const reduceMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
if (reduceMotion || !document.startViewTransition) {
updateDom();
} else {
document.startViewTransition(() => updateDom());
}