Elementi sensibili alla posizione di scorrimento

Panoramica

Migliora l'esperienza utente dei pulsanti mobili, come un link "Torna all'inizio", mostrandoli solo quando sono utili. Questa guida mostra come creare questi elementi utilizzando la proprietà CSS container-scroll-state-queries, che consente di applicare uno stile agli elementi in base alla posizione di scorrimento del relativo contenitore senza fare affidamento su listener o osservatori di scorrimento JavaScript.

Implementazione

1. Stabilisci il contenitore di scorrimento

Il container di scorrimento deve essere dichiarato come container di query sullo stato di scorrimento.

.scroller {
  overflow-y: auto;
  /* Establish this element as a scroll-state query container */
  container-type: scroll-state;
}

2. Stile dell'elemento mobile

Posiziona l'elemento all'interno del contenitore e applica uno stile. Per impostazione predefinita, dovrebbe essere nascosto.

.back-to-top {
  position: sticky;
  bottom: 20px;
  visibility: hidden;
  opacity: 0;
  translate: 0 20px;
  transition:
    visibility 0.3s,
    opacity 0.3s ease,
    translate 0.3s ease;
}

3. Rispondi allo stato di scorrimento

Utilizza la regola @container con la funzione scroll-state. Per verificare se l'utente ha fatto scorrere la pagina verso il basso, controlla se il container è scorrevole verso l'alto.

/* When the container can be scrolled toward the top, it means the user has scrolled down */
@container scroll-state(scrollable: top) {
  .back-to-top {
    visibility: visible;
    opacity: 1;
    translate: 0 0;
  }
}

Strategie di riserva

Fallback di base

Se container-scroll-state-queries non è supportato, l'elemento mobile rimarrà invisibile a causa del valore predefinito visibility: hidden. Per garantire la funzionalità, puoi scegliere di rendere l'elemento sempre visibile nei browser non supportati.

/* Fallback for browsers that do not support the feature */
.back-to-top {
  visibility: visible; /* Always visible */
  opacity: 1;
}

/* Override for supported browsers to handle dynamic visibility */
@supports (container-type: scroll-state) {
  .back-to-top {
    visibility: hidden;
    opacity: 0;
  }
  
  @container scroll-state(scrollable: top) {
    .back-to-top {
      visibility: visible;
      opacity: 1;
      translate: 0 0;
    }
  }
}

Fallback avanzato (Intersection Observer)

Se è richiesta la visibilità dinamica, utilizza un IntersectionObserver per attivare/disattivare una classe quando un elemento sentinella nella parte superiore dello scroller non è più visibile.

<!-- Sentinel element placed at the top of the scroller -->
<div class="scroll-sentinel"></div>
/* Marker styling to ensure it does not affect layout */
.scroll-sentinel {
  height: 0;
  width: 0;
  visibility: hidden;
}

.scrolled .back-to-top {
  visibility: visible;
  opacity: 1;
  translate: 0 0;
}
if (!CSS.supports('container-type', 'scroll-state')) {
  const sentinel = document.querySelector('.scroll-sentinel');
  const scroller = document.querySelector('.scroller');

  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      // If the sentinel is NOT intersecting, it means the user has scrolled down
      if (!entry.isIntersecting) {
        scroller.classList.add('scrolled');
      } else {
        scroller.classList.remove('scrolled');
      }
    });
  }, { root: scroller });

  observer.observe(sentinel);
}