تتيح لك طلبات البحث عن حاويات حالة الانتقال للأعلى أو للأسفل تصميم العناصر استنادًا إلى حالة الانتقال الحالية، مثل ما إذا كان العنصر "ثابتًا" (من خلال تحديد الموضع الثابت) أو "محاذيًا" (من خلال محاذاة مواضع التمرير). يتيح ذلك تجارب لوحة العرض الدوّارة أو معرض الصور حيث يمكن تمييز العنصر النشط بصريًا بدون الاعتماد على أدوات مراقبة تقاطع JavaScript أو متتبِّعات أحداث الانتقال.
التنفيذ الأساسي
لتمييز العناصر التي تمّت محاذاتها، عليك إنشاء حاوية لمحاذاة مواضع التمرير، وتحديد أهداف المحاذاة كحاويات لحالة التمرير، ثم الاستعلام عن هذه الحالة لتصميم العناصر التابعة.
1. إنشاء حاوية محاذاة مواضع التمرير
يجب تفعيل scroll-snap-type في الحاوية الرئيسية.
<div class="carousel">
<div class="carousel-item">
<div class="card">Product 1 content</div>
</div>
<div class="carousel-item">
<div class="card">Product 2 content</div>
</div>
</div>
.carousel {
display: flex;
overflow-x: auto;
/* MANDATORY: Enable scroll snapping on the container */
scroll-snap-type: x mandatory;
}
2. تحديد أهداف المحاذاة كحاويات لحالة الانتقال
يجب تعريف كل عنصر في لوحة العرض الدوّارة التي يجب تتبُّعها من أجل المحاذاة كحاوية scroll-state.
.carousel-item {
/* Define where the item snaps within the container */
scroll-snap-align: center;
/* MANDATORY: Establish this element as a scroll-state query container */
container-type: scroll-state;
}
3- الاستعلام عن حالة snapped
بما أنّ طلبات البحث عن الحاوية تحدّد نمط العناصر التابعة، يجب تطبيق أنماط التمييز على عنصر داخل هدف المحاذاة. بما أنّه تم ضبط حاوية الانتقال على تجاوز المحور x، استخدِم طلب البحث scroll-state(snapped: x).
إجراء إلزامي: يجب تضمين الأنماط في @media (prefers-reduced-motion: no-preference) لعرض التأثير فقط للمستخدمين الذين لم يطلبوا تقليل الحركة. استنادًا إلى حالة الاستخدام، يمكنك الاحتفاظ بأجزاء من التأثير، ولكن في هذه الحالة، تومض البطاقات من الأبيض إلى الأزرق بطريقة قد تسبّب مشاكل لبعض المستخدمين، لذا نوقفها تمامًا.
/* Specify transition outside of queries so that it is applied regardless of state. */
.card {
transition:
scale 0.4s cubic-bezier(0.25, 0.8, 0.25, 1),
background-color 0.4s,
color 0.4s,
box-shadow 0.4s;
}
/*
Only show the effect for users not requesting reduced motion. Disable completely, including the color change, as it causes a flash that may be problematic.
*/
@media (prefers-reduced-motion: no-preference) {
/* Style the content when its parent .carousel-item is snapped on the x axis */
@container scroll-state(snapped: x) {
.card {
background: #007bff;
color: white;
scale: 1.15;
box-shadow: 0 10px 25px rgba(0, 123, 255, 0.3);
}
}
}
/* MANDATORY Copy-Paste Safety: Disable highlight scaling/flashing for motion sensitive users */
@media (prefers-reduced-motion: reduce) {
.card {
transition: none !important;
scale: 1 !important;
}
}
يمكن للواصف snapped الاستعلام عن محاور معيّنة: x أو y أو inline أو block أو both.
تسهيل الاستخدام
AVOID: استخدام scroll-state مع العناصر التفاعلية.
يمكن أن تؤدي ميزة "الإبراز المرئي" للعناصر التي تم التقاطها إلى تحسين تجربة المستخدم، ولكن لا يتم عرض العنصر الذي تم التقاطه في شجرة تسهيل الاستخدام. يجب ألا يشير المظهر المرئي المطبَّق على عنصر تم تثبيته إلى أنّ العنصر نشط أو محدّد، ويجب أن تكون حلقة تركيز لوحة المفاتيح مرئية بوضوح ومختلفة عن تمييز snapped. إذا كان العنصر الذي تم تثبيته تفاعليًا، يجب استخدام ممارسات تسهيل الاستخدام العادية الأخرى لإتاحة الوصول إليه.
يحدث الانطباق بسبب الانتقال للأعلى أو للأسفل، ما لا يؤدي إلى نقل تركيز لوحة المفاتيح. ومع ذلك، قد يؤدي تركيز لوحة المفاتيح إلى تحريك حاوية الانتقال، ما يؤدي إلى تغيير في العنصر الذي تم تثبيته، والذي قد يكون أو لا يكون العنصر الذي تم التركيز عليه. ومن المرجّح أن يؤدي ذلك إلى إرباك المستخدمين، لذا لا ننصح به.
استراتيجيات احتياطية
بالنسبة إلى المتصفحات التي لا تتيح طلبات البحث عن حالة الانتقال، يجب توفير تجربة أساسية فعّالة تكون فيها جميع العناصر واضحة، حتى بدون تمييز العنصر "النشط".
رصد الميزات
يمكنك استخدام @supports لتوفير تحسينات للمتصفّحات المتوافقة فقط:
@supports (container-type: scroll-state) {
/* Enhancement styles here */
}
الاحتياطي لـ JavaScript
إذا كان التمييز مهمًا لتجربة المستخدم، استخدِم IntersectionObserver لتحديد العنصر الذي تم تثبيته. اضبط المنطقة المرصودة على شريحة رفيعة في وسط لوحة العرض الدوّارة من خلال توفير rootMargin بقيمة سلبية مضمّنة. على سبيل المثال، لاعتبار عنصر متقاطعًا إذا كان في وسط% 2 من لوحة العرض الدوّارة، اضبط rootMargin على "0px -49%".
// Optional: detect support and apply a JS-based fallback
if (!CSS.supports('container-type', 'scroll-state')) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
// Toggle a class based on intersection
entry.target.classList.toggle('is-snapped', entry.isIntersecting);
});
}, {
root: document.querySelector(".carousel"),
// Carousel item intersects if any part of the carousel item is in the middle 2% of the carousel.
rootMargin: "0px -49%"
});
document.querySelectorAll('.carousel-item').forEach(item => {
observer.observe(item);
});
}