Visão geral
Melhore a experiência do usuário com botões flutuantes, como um link "Voltar ao topo", mostrando-os apenas quando forem úteis. Este guia mostra como criar esses elementos usando o CSS container-scroll-state-queries, que permite estilizar elementos com base na posição de rolagem do contêiner sem depender de listeners ou observadores de rolagem do JavaScript.
Implementação
1. Estabelecer o contêiner de rolagem
O contêiner de rolagem precisa ser declarado como um contêiner de consulta de estado de rolagem.
.scroller {
overflow-y: auto;
/* Establish this element as a scroll-state query container */
container-type: scroll-state;
}
2. Estilizar o elemento flutuante
Coloque o elemento dentro do contêiner e estilize-o. Por padrão, ele precisa ficar oculto.
.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. Responder ao estado de rolagem
Use a regra @container com a função scroll-state. Para verificar se o usuário rolou para baixo, confira se o contêiner pode ser rolado para cima.
/* 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;
}
}
Estratégias de fallback
Fallback básico
Se container-scroll-state-queries não for compatível, o elemento flutuante vai permanecer invisível devido ao visibility: hidden padrão. Para garantir a funcionalidade, você pode optar por deixar o elemento sempre visível em navegadores incompatíveis.
/* 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 avançado (Intersection Observer)
Se a visibilidade dinâmica for necessária, use um IntersectionObserver para alternar uma classe quando um elemento sentinela na parte de cima do scroller sair da visualização.
<!-- 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);
}