1001Ferramentas
📜Geradores

CSS Scroll Snap

Gere CSS scroll-snap para carrosséis e galerias que param em cada item ao rolar. Escolha o eixo horizontal ou vertical e copie o código pronto.

CSS

CSS scroll-snap: carrosséis nativos sem JavaScript

O módulo scroll-snap do CSS permite controlar onde o navegador "encaixa" ao final de um gesto de scroll — em vez de parar em um pixel arbitrário, o viewport "gruda" em pontos pré-definidos ao longo do eixo. Ele substitui uma família inteira de libs JS de carrossel (Slick, parte do Swiper.js, Glide.js) para o caso comum de um slider horizontal ou um feed vertical estilo TikTok/Reels. Como a lógica de snap roda na thread de compositing, momentum, fling e inércia se comportam de forma nativa — sem reflow JS durante o scroll, sem eventos de toque perdidos, e as setas do teclado funcionam de graça.

Suporte de browser é universal nos engines modernos: Chrome 69+, Firefox 68+, Safari 11+ (Edge herda do Chromium). O Safari mobile lida especialmente bem porque integra com o momentum de toque da plataforma.

O contrato de dois lados: pai e filho

Scroll-snap sempre envolve duas propriedades em dois elementos. O container de scroll declara o eixo e a rigidez; cada filho declara onde quer alinhar.

.carousel {
  scroll-snap-type: x mandatory;
  overflow-x: auto;
  scroll-behavior: smooth;
}
.carousel > .slide {
  scroll-snap-align: start;
}

scroll-snap-type aceita x | y | both para o eixo e mandatory | proximity para a rigidez: mandatory sempre encaixa no ponto mais próximo, mesmo se o usuário scrollou só um pixel; proximity só encaixa se já estiver perto, o que dá uma sensação mais tolerante para conteúdo de leitura. No filho, scroll-snap-align é start, center ou end — a borda do filho que se alinha com a mesma borda do container.

scroll-padding e headers fixos

Se sua página tem um header fixo/sticky, os pontos de snap ficam escondidos atrás dele. Use scroll-padding-top: 60px no container para empurrar a origem do snap para baixo, equivalente à altura do header — os filhos alinham abaixo da barra em vez de atrás dela. O shorthand scroll-padding espelha os lados de padding, e scroll-margin faz o mesmo trabalho pelo lado do filho. Combine com scroll-snap-stop: always para impedir que flicks rápidos pulem slides intermediários — útil para wizards de onboarding ou tours passo a passo.

Pagination dots e estado ativo

scroll-snap não expõe um evento de "slide atual" nativamente. A forma idiomática de iluminar os dots de paginação é um IntersectionObserver com threshold: 0.5 observando cada slide e alternando um atributo aria-current="true" no dot correspondente. Se precisar de um callback exatamente quando o snap assenta, escute o novo evento scrollend (Chrome 114+, Firefox 109+) — browsers anteriores precisam de um listener debounced de scroll.

Exemplos reais

  • Páginas de produto da Apple — carrosséis horizontais de feature com snap mandatory.
  • Stripe.com — sliders de case-study que pausam de forma precisa em cada logo de cliente.
  • TikTok / Instagram Reels web — snap vertical full-viewport, um vídeo por vez.
  • Galerias de imagens — fileiras de thumbnail com scroll-snap-align: center no estilo Netflix.

Perguntas frequentes

Posso substituir o Swiper.js totalmente? Para um slider horizontal básico com paginação, sim — scroll-snap mais um pequeno IntersectionObserver ganha do Swiper em bundle size e performance. Para features avançadas (loop, slides virtuais, parallax, sync de thumbnail) o Swiper ainda vence.

Como intercepto o evento de snap? Use o evento scrollend quando disponível, senão debouncing de scroll com ~150ms após o último disparo. Calcule o índice ativo via container.scrollLeft / container.clientWidth.

Por que containers de scroll aninhados se comportam mal? Quando um container com snap fica dentro de outro pai com scroll, o browser precisa decidir qual captura o gesto. Defina overscroll-behavior: contain no container interno para que os flicks não vazem para o scroll externo.

mandatory ou proximity? Use mandatory para carrosséis de imagem e cards discretos (você quer que todo snap aterrize). Use proximity para conteúdo longo como uma revista, onde o usuário está lendo no meio de um parágrafo e não deve ser arrastado para a próxima seção.

Ferramentas Relacionadas