Băng chuyền khoảnh khắc nổi bật trên Snap

Truy vấn vùng chứa trạng thái cuộn cho phép bạn tạo kiểu cho các phần tử dựa trên trạng thái cuộn hiện tại của chúng, chẳng hạn như liệu một phần tử có bị "kẹt" (thông qua vị trí cố định) hay "cố định vị trí cuộn" (thông qua tính năng cố định vị trí cuộn) hay không. Điều này cho phép trải nghiệm băng chuyền hoặc thư viện, trong đó mục đang hoạt động có thể được phân biệt trực quan mà không cần dựa vào trình quan sát giao lộ JavaScript hoặc trình nghe sự kiện cuộn.

Triển khai cốt lõi

Để làm nổi bật các mục được cố định vị trí, bạn phải thiết lập một vùng chứa cố định vị trí cuộn, xác định các mục tiêu cố định vị trí làm vùng chứa trạng thái cuộn, sau đó truy vấn trạng thái đó để tạo kiểu cho các phần tử con.

1. Thiết lập vùng chứa cố định vị trí cuộn

Vùng chứa gốc phải bật 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. Xác định mục tiêu đính kèm dưới dạng vùng chứa trạng thái cuộn

Mỗi mục trong băng chuyền cần được theo dõi để bắt dính phải được khai báo là vùng chứa 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. Truy vấn trạng thái snapped

Vì truy vấn vùng chứa tạo kiểu cho phần tử con, nên bạn phải áp dụng kiểu làm nổi bật cho một phần tử bên trong mục tiêu đính vào. Vì vùng chứa cuộn được đặt thành tràn trên trục x, hãy sử dụng truy vấn scroll-state(snapped: x).

BẮT BUỘC: Gói các kiểu trong @media (prefers-reduced-motion: no-preference) để chỉ hiển thị hiệu ứng cho những người dùng chưa yêu cầu giảm chuyển động. Tuỳ thuộc vào trường hợp sử dụng, bạn có thể giữ lại một số phần của hiệu ứng, nhưng trong trường hợp này, các thẻ nhấp nháy từ màu trắng sang màu xanh dương theo cách có thể gây ra vấn đề cho một số người dùng, vì vậy, chúng tôi sẽ tắt hoàn toàn hiệu ứng này.

/* 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;
  }
}

Phần mô tả snapped có thể truy vấn các trục cụ thể: x, y, inline, block hoặc both.

Hỗ trợ tiếp cận

AVOID: sử dụng scroll-state với các thành phần tương tác.

Điểm nổi bật về hình ảnh cho các mục được chụp nhanh có thể cải thiện trải nghiệm người dùng, nhưng mục được chụp nhanh không hiển thị trong cây hỗ trợ tiếp cận. Giao diện hình ảnh áp dụng cho một mục được chụp nhanh không được thể hiện rằng phần tử đó đang hoạt động hoặc được lấy tiêu điểm, đồng thời vòng lấy tiêu điểm bàn phím phải dễ nhìn thấy và khác biệt với vùng đánh dấu snapped. Nếu mục được đính vào có tính tương tác, bạn phải sử dụng các phương pháp hỗ trợ tiếp cận tiêu chuẩn khác để giúp mục đó dễ tiếp cận.

Thao tác chụp nhanh xảy ra do thao tác cuộn, không di chuyển tiêu điểm bàn phím. Tuy nhiên, tiêu điểm bàn phím có thể khiến vùng chứa cuộn di chuyển, dẫn đến thay đổi về mục được đính vào, có thể là mục được làm tâm điểm hoặc không. Điều này có thể gây nhầm lẫn cho người dùng và không được khuyến khích.

Chiến lược dự phòng

Đối với những trình duyệt không hỗ trợ truy vấn trạng thái cuộn, bạn nên cung cấp trải nghiệm cơ bản có chức năng, trong đó tất cả các mục đều dễ đọc, ngay cả khi không có phần đánh dấu "đang hoạt động".

Phát hiện tính năng

Bạn có thể sử dụng @supports để chỉ cung cấp các tính năng nâng cao cho những trình duyệt được hỗ trợ:

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

Dự phòng JavaScript

Nếu phần được làm nổi bật là quan trọng đối với trải nghiệm người dùng, hãy sử dụng IntersectionObserver để xác định mục được đính vào. Điều chỉnh khu vực được quan sát thành một lát mỏng ở giữa băng chuyền bằng cách cung cấp rootMargin có giá trị cùng dòng âm. Ví dụ: để coi một phần tử là giao nhau nếu phần tử đó nằm trong 2% chính giữa của băng chuyền, hãy đặt rootMargin thành "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);
  });
}