Momenti salienti di Snap carosello

Le query container sullo stato di scorrimento ti consentono di applicare stili agli elementi in base al loro stato di scorrimento attuale, ad esempio se un elemento è "bloccato" (tramite il posizionamento sticky) o "allineato" (tramite l'allineamento dello scorrimento). In questo modo, è possibile creare esperienze di carosello o galleria in cui l'elemento attivo può essere distinto visivamente senza dover fare affidamento su osservatori di intersezione JavaScript o listener di eventi di scorrimento.

Implementazione di base

Per evidenziare gli elementi allineati, devi stabilire un container di allineamento dello scorrimento, definire i target di allineamento come container di stato dello scorrimento e poi eseguire una query su questo stato per applicare lo stile ai discendenti.

1. Stabilisci il container di allineamento dello scorrimento

Il contenitore principale deve avere scroll-snap-type abilitato.

<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. Definisci i target di aggancio come container dello stato di scorrimento

Ogni elemento del carosello che deve essere monitorato per lo snapping deve essere dichiarato come container 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. Esegui una query sullo stato di snapped

Poiché le query container applicano lo stile ai discendenti, devi applicare gli stili di evidenziazione a un elemento all'interno del target di aggancio. Poiché il contenitore di scorrimento è impostato su overflow sull'asse x, utilizza la query scroll-state(snapped: x).

OBBLIGATORIO: inserisci gli stili in @media (prefers-reduced-motion: no-preference) per mostrare l'effetto solo agli utenti che non hanno richiesto la riduzione del movimento. A seconda del caso d'uso, puoi mantenere parti dell'effetto, ma in questo caso le schede lampeggiano da bianco a blu in un modo che potrebbe causare problemi ad alcuni utenti, quindi lo disattiviamo completamente.

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

Il descrittore snapped può eseguire query su assi specifici: x, y, inline, block o both.

Accessibilità

AVOID: l'utilizzo di scroll-state con elementi interattivi.

Gli elementi visivi in evidenza per gli elementi agganciati possono migliorare la UX, ma l'elemento agganciato non viene esposto all'albero di accessibilità. Il tema visivo applicato a un elemento agganciato non deve indicare che l'elemento è attivo o selezionato e l'anello di selezione della tastiera deve essere ben visibile e distinto dall'evidenziazione snapped. Se l'elemento agganciato è interattivo, devi utilizzare altre pratiche di accessibilità standard per renderlo accessibile.

L'aggancio avviene a causa dello scorrimento, che non sposta la selezione della tastiera. Tuttavia, la selezione della tastiera potrebbe causare lo spostamento del container di scorrimento, con conseguente modifica dell'elemento agganciato, che potrebbe essere o meno l'elemento selezionato. Questo potrebbe confondere gli utenti ed è sconsigliato.

Strategie di riserva

Per i browser che non supportano le query scroll-state, devi fornire un'esperienza di base funzionale in cui tutti gli elementi siano leggibili, anche senza l'evidenziazione "attiva".

Rilevamento delle caratteristiche

Puoi utilizzare @supports per fornire miglioramenti solo ai browser supportati:

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

Fallback JavaScript

Se l'evidenziazione è fondamentale per l'esperienza utente, utilizza IntersectionObserver per determinare l'elemento agganciato. Regola l'area osservata in modo che sia una sezione sottile al centro del carosello fornendo un rootMargin con un valore inline negativo. Ad esempio, per considerare un elemento come intersecante se si trova nel 2% centrale del carosello, imposta rootMargin su "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);
  });
}