برگزیده‌های گردونه Snap

پُرسمان‌های محفظه وضعیت پیمایش به شما امکان می‌دهد عناصر را براساس وضعیت پیمایش فعلی‌شان سبک‌بندی کنید، مثلاً اینکه آیا عنصری «چسبیده» (ازطریق موقعیت‌یابی چسبنده) یا «میزان‌شده» (ازطریق میزان کردن پیمایش) است یا نه. این ویژگی امکان ایجاد تجربه‌های گردونه‌ای یا گالری را فراهم می‌کند که در آن مورد فعال می‌تواند بدون تکیه بر ناظران تقاطع جاوا اسکریپت یا شنوندگان رویداد پیمایش، به‌صورت بصری متمایز شود.

پیاده‌سازی اصلی

برای برجسته کردن موارد میزان‌شده، باید یک محفظه میزان کردن پیمایش ایجاد کنید، هدف‌های میزان کردن را به‌عنوان محفظه‌های وضعیت پیمایش تعریف کنید، و سپس آن وضعیت را برای سبک‌دهی به فرزندان پرسمان کنید.

۱. ایجاد کردن محفظه میزان کردن پیمایش

ظرف اصلی باید 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;
}

۲. تعریف اهداف چسبیدن به‌عنوان محفظه‌های حالت پیمایش

هر موردی در گردونه که باید برای چسباندن ردیابی شود باید به‌عنوان محفظه 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;
}

۳. پرس‌وجو کردن وضعیت 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 باشد. اگر مورد چسبیده تعاملی است، باید از دیگر روش‌های استاندارد دسترس‌پذیری استفاده کنید تا آن را دسترس‌پذیر کنید.

پرش به‌دلیل پیمایش اتفاق می‌افتد که تمرکز صفحه‌کلید را جابه‌جا نمی‌کند. بااین‌حال، فوکوس صفحه‌کلید ممکن است باعث حرکت محفظه پیمایش شود و درنتیجه مورد چسبیده تغییر کند، که ممکن است مورد فوکوس‌شده باشد یا نباشد. این کار احتمالاً باعث سردرگمی کاربران می‌شود و توصیه نمی‌شود.

راهبردهای جایگزین

برای مرورگرهایی که از پُرسمان‌های scroll-state پشتیبانی نمی‌کنند، باید یک تجربه پایه کاربردی ارائه دهید که در آن همه موارد خوانا باشند، حتی بدون برجسته‌سازی «فعال».

تشخیص ویژگی

می‌توانید از @supports برای ارائه بهبودها فقط به مرورگرهای پشتیبانی‌شده استفاده کنید:

@supports (container-type: scroll-state) {
  /* Enhancement styles here */
}

گزینه جایگزین جاوا اسکریپت

اگر برجسته‌سازی برای تجربه کاربری حیاتی است، از IntersectionObserver برای تعیین کردن مورد چسبیده استفاده کنید. با ارائه rootMargin با مقدار درون‌خطی منفی، ناحیه مشاهده‌شده را به یک برش نازک در مرکز گردونه تنظیم کنید. برای مثال، برای اینکه عنصری در مرکز ۲٪ گردونه به‌عنوان متقاطع درنظر گرفته شود، 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);
  });
}