Rolagem bem controlada com o ajuste de rolagem do CSS

Crie experiências de rolagem bem controladas declarando as posições de ajuste da rolagem.

Robert Flack
Robert Flack
Majid Valipour
Majid Valipour

O recurso Ajuste de rolagem CSS permite que os desenvolvedores da Web criem experiências de rolagem bem controladas declarando posições de ajuste de rolagem. Artigos paginados e carrosséis de imagens são dois exemplos frequentemente usados. O CSS Scroll Snap oferece uma API consistente e fácil de usar para criar esses padrões de UX conhecidos.

Contexto

O caso do ajuste de rolagem

A rolagem é uma maneira popular e natural de interagir com conteúdo na Web. Ela é o meio nativo da plataforma de fornecer acesso a mais informações do que o visível na tela de uma só vez, tornando-se especialmente essencial em plataformas móveis com espaço limitado na tela. Portanto, não é nenhuma surpresa que os autores da Web cada vez mais preferem organizar o conteúdo em listas planas roláveis em vez de hierarquias profundas.

A principal desvantagem da rolagem é a falta de precisão. Raramente ocorre uma rolagem alinhada a um parágrafo ou frase. Isso é ainda mais evidente para conteúdo paginado ou itemizado com limites significativos quando a rolagem termina no meio da página ou imagem, deixando-a parcialmente visível. Esses casos de uso se beneficiam de uma experiência de rolagem bem controlada.

Os desenvolvedores da Web dependem há muito tempo em soluções baseadas em JavaScript para controlar a rolagem e solucionar essa deficiência. No entanto, as soluções baseadas em JavaScript não oferecem uma solução de fidelidade total devido à falta de primitivos de personalização de rolagem ou de acesso à rolagem composta. O CSS Scroll Snap garante uma solução rápida, de alta fidelidade e fácil de usar que funciona de maneira consistente em todos os navegadores.

O alinhamento de rolagem CSS permite que os autores da Web marquem cada contêiner de rolagem com limites para operações de rolagem que precisam ser concluídas. Em seguida, os navegadores escolhem a posição final mais adequada, dependendo das características da operação de rolagem, do layout e da visibilidade do contêiner de rolagem, e dos detalhes das posições de ajuste, para depois animar a visualização. Voltando ao exemplo anterior, à medida que o usuário termina de rolar o carrossel, a imagem visível se ajusta ao lugar. O JavaScript não precisa de ajustes de rolagem.

Exemplo de uso do ajuste de rolagem CSS com um carrossel de imagens.
Exemplo de uso do ajuste de rolagem CSS com um carrossel de imagens. Nesse caso, o ajuste de rolagem garante que, ao final da rolagem, um centro horizontal da imagem esteja alinhado com o centro horizontal do contêiner de rolagem.

Snap de rolagem CSS

O ajuste de rolagem é o ato de ajustar o deslocamento de rolagem de um contêiner de rolagem para ficar em uma posição de ajuste preferida assim que a operação de rolagem terminar.

Um contêiner de rolagem pode ativar o ajuste de rolagem usando a propriedade scroll-snap-type. Isso informa ao navegador que ele precisa considerar o ajuste desse contêiner de rolagem nas posições de ajuste produzidas pelos descendentes. scroll-snap-type determina o eixo em que a rolagem ocorre: x, y ou both, e a restrição de ajuste: mandatory, proximity. Falaremos sobre isso mais adiante.

Uma posição de ajuste pode ser produzida declarando-se um alinhamento desejado em um elemento. Essa posição é o deslocamento de rolagem em que o elemento e o contêiner de rolagem ancestral mais próximos estão alinhados conforme especificado para o eixo especificado. Os seguintes alinhamentos são possíveis em cada eixo: start, end, center.

Um alinhamento start significa que a borda inicial do ajuste do contêiner de rolagem precisa ser alinhada com a borda inicial da área de ajuste do elemento. Da mesma forma, os alinhamentos end e center significam que a borda final ou o centro do ajuste do contêiner de rolagem precisam ser alinhados com a borda ou centro da área de ajuste do elemento.

Exemplo de vários alinhamentos no eixo de rolagem horizontal.

Os exemplos a seguir ilustram como usar esses conceitos.

Um caso de uso comum para ajuste de rolagem é um carrossel de imagens. Por exemplo, para criar um carrossel de imagens horizontal que se ajusta a cada imagem conforme você rola a tela, podemos especificar que o contêiner de rolagem tenha um scroll-snap-type obrigatório no eixo horizontal. Defina cada imagem como scroll-snap-align: center para garantir que o ajuste centralize a imagem dentro do carrossel.

#gallery {
  scroll-snap-type: x mandatory;
  overflow-x: scroll;
  display: flex;
}

#gallery img {
   scroll-snap-align: center;
}
<div id="gallery">
  <img src="cat.jpg">
  <img src="dog.jpg">
  <img src="another_cute_animal.jpg">
</div>

Como as posições de ajuste são associadas a um elemento, o algoritmo pode ser inteligente sobre quando e como o ajuste é feito de acordo com o elemento e o tamanho do contêiner de rolagem. Por exemplo, considere o caso em que uma imagem é maior que o carrossel. Um algoritmo de ajuste simples pode impedir que o usuário mova o mapa para ver a imagem completa. No entanto, a especificação exige que as implementações detectem esse caso e permitam que o usuário role livremente pela imagem, encaixando-a apenas nas bordas.

Confira a demonstração | Fonte

Exemplo: uma página de produto que você já usou

Outro caso comum que pode se beneficiar do ajuste de rolagem são páginas com várias seções lógicas de rolagem vertical, por exemplo, uma página de produto típica. scroll-snap-type: y proximity; é mais natural para casos como esse. Isso não interfere quando um usuário rola até o meio de uma seção específica, mas também se ajusta e chama a atenção para uma nova seção quando rola para perto o suficiente.

Veja como fazer isso:

article {
  scroll-snap-type: y proximity;
  /* Reserve space for header plus some extra space for sneak peeking. */
  scroll-padding-top: 15vh;
  overflow-y: scroll;
}
section {
  /* Snap align start. */
  scroll-snap-align: start;
}
header {
  position: fixed;
  height: 10vh;
}
<article>
  <header> Header </header>
  <section> Section One </section>
  <section> Section Two </section>
  <section> Section Three </section>
</article>

Rolar o padding e a margem

A página do produto tem um cabeçalho superior de posição fixa. O design também pediu que parte da seção superior permanecesse visível quando o contêiner de rolagem for ajustado para fornecer uma dica de design aos usuários sobre o conteúdo acima.

A propriedade scroll-padding é uma nova propriedade CSS que pode ser usada para ajustar a região visível efetiva do contêiner de rolagem, ou Snapport, que é usado no cálculo dos alinhamentos de ajuste de rolagem. A propriedade define um encarte na caixa de padding do contêiner de rolagem. No nosso exemplo, o encarte 15vh extra foi adicionado à parte de cima, o que instrui o navegador a considerar uma posição mais baixa, 15vh abaixo da borda de cima do contêiner de rolagem, como a borda inicial vertical para ajuste de rolagem. Durante o ajuste, a borda inicial do elemento de destino será desenvolvida com essa nova posição, deixando espaço acima.

A propriedade scroll-margin define o valor de início usado para ajustar a caixa efetiva do destino de ajuste da mesma forma que o scroll-padding funciona no contêiner de rolagem rápida.

Você pode ter notado que essas duas propriedades não têm a palavra "snap". Isso é intencional, porque eles modificam a caixa para todas as operações de rolagem relevantes e não estão apenas no ajuste de rolagem. Por exemplo, o Chrome os considera ao calcular o tamanho da página para operações de rolagem de paginação, como as páginas para baixo e para cima, e também ao calcular o valor de rolagem da operação Element.scrollIntoView().

Confira a demonstração | Fonte

Interação com outras APIs de rolagem

API DOM Scrolling

O ajuste de rolagem acontece após todas as operações de rolagem, incluindo aquelas iniciadas pelo script. Quando você usa APIs como Element.scrollTo, o navegador calcula a posição de rolagem pretendida da operação e aplica a lógica de ajuste adequada para encontrar o local final ajustado. Portanto, não é necessário que o script do usuário faça cálculos manuais para ajuste.

Rolagem suave

A rolagem suave controla o comportamento de uma operação de rolagem programática enquanto o ajuste de rolagem determina o destino. Como eles controlam aspectos ortogonais da rolagem, podem ser usados juntos e se complementam.

Comportamento de rolagem

A API de comportamento de rolagem controla como a rolagem é encadeada em vários elementos e não é afetada pelo ajuste de rolagem.

Advertências e práticas recomendadas

Evite usar o ajuste obrigatório quando os elementos de destino estiverem muito espaçados. Isso pode fazer com que o conteúdo entre as posições de ajuste se torne inacessível.

Em muitos casos, o ajuste de rolagem pode ser adicionado como uma melhoria sem a necessidade de detecção de recursos. Se necessário, use @supports ou CSS.supports para detectar o suporte ao alinhamento de rolagem do CSS. Evite usar scroll-snap-type, que também está presente na especificação descontinuada.

Detecção de recursos no CSS

@supports (scroll-snap-align: start) {
  article {
    scroll-snap-type: y proximity;
    scroll-padding-top: 15vh;
    overflow-y: scroll;
  }
}

Detecção de recursos em JavaScript

if (CSS.supports('scroll-snap-align: start')) {
  // use css scroll snap
} else {
  // use fallback
}

Não presuma que as APIs de rolagem programática, como Element.scrollTo, sempre terminam no deslocamento de rolagem solicitado. O ajuste de rolagem pode ajustar o deslocamento de rolagem após a conclusão da rolagem programática. Essa não era uma boa suposição, mesmo antes do ajuste de rolagem, já que a rolagem pode ter sido interrompida por outros motivos, mas é especialmente o caso com o ajuste de rolagem.

Trabalho futuro

A experiência de rolagem foi o foco de uma pesquisa recente da equipe do Chrome. Os resultados da pesquisa identificaram várias áreas que precisam de mais trabalho para diminuir a distância entre as bibliotecas de plug-ins e o CSS. Os próximos trabalhos terão como foco scroll-snap, incluindo:

  1. Disponibilidade da API e compatibilidade entre navegadores.
  2. Trabalhe em novas APIs CSS, como scroll-start.
  3. Trabalhe em novos eventos JS, como snapChanged().