Navegação por âncora em sites é algo tão velho quanto a própria Web. Mas, com os avanços de CSS, já é possível fazer navegação âncora com scroll suave (smooth scroll) usando CSS puro!
Esse tipo de navegação por âncora é comum de ser vista em sites One Page, Landing Pages e afins. Há não muito tempo atrás, para se ter esse tipo de navegação, ainda mais com rolagem suave — a famosa smooth scroll –, era preciso recorrer a JavaScript.
Na verdade, atualmente, na data de publicação deste artigo, recorrer a códigos JavaScript, incluindo bibliotecas inteiras para conseguir navegação por âncora com smooth scroll — acredite, o drama de adicionar jQuery somente para scroll suave é real –, ainda é o padrão; é o que se encontra na quase totalidade dos casos em que o recurso é implementado.
Felizmente, com o avanço de CSS e surgimento de novas possibilidades e técnicas, agora é possível conseguir o efeito sem o uso de JavaScript, ficando a tecnologia dispensada ou usada somente para dar retoques à experiência e/ou interações complementares menores.
:target
Segundo consta na documentação de :target
na MDN,
A pseudo-classe CSS :target representa um único elemento (o elemento alvo) com uma id correspondente ao fragmento da URL.
Na prática, :target
serve para estilizar elementos que recebeu o foco através de um fragmento de URL (sinal de #
).
Por exemplo, o seguinte HTML:
1 2 3 4 5 6 7 8 9 10 11 12 |
<h3>Sumário</h3> <ol> <li><a href="#p1">Ir para o primeiro parágrafo!</a></li> <li><a href="#p2">Ir para o segundo parágrafo!</a></li> </ol> <h3>Meu artigo divertido</h3> <p id="p1">Você pode definir este parágrafo como alvo usando um fragmento de URL.</p> <p id="p2">Esse é <i>outro parágrafo</i>, também acessível pelos links acima.</p> |
Associado a este CSS:
1 2 3 |
p:target { background-color: gold; } |
Faz com que, ao clicar em algum link da lista, seu correspondente (mesmo #
) tenha a cor de fundo alterada.
scroll-behavior
com scroll-margin-top
Para atingir o resultado de scroll suave com CSS puro, é preciso comentar a existência de uma nova aliada nas folhas de estilo: a propriedade scroll-behavior
.
Basicamente, ela admite 2 valores:
auto
. O comportamento padrão de rolagem (dando “pulo” ou “tranco” até o target);smooth
. Rolagem suave!
O bom é que é possível determinar o comportamento de scroll (scroll-behavior
) para diferentes elementos do site, mas, caso você queira e/ou seja preciso, definir que o scroll geral (o da viewport) será suave, bastante, para isso, especificar a propriedade no html
:
1 2 3 |
html { scroll-behavior: smooth; } |
Só fica uma pequena questão: a tela vai rolar para o exato ponto em que o título (ou o conteúdo que seja) começa, sendo bastante comum o “corte” do texto desse título — o que não é bom para a experiência de quem acessa o site.
Obviamente, a maioria dos (bons) códigos JavaScript e libs de scroll comentados anteriormente já trata da questão que, até há não muito tempo atrás, era algo insolúvel com CSS puro.
Felizmente, agora é possível contar com a propriedade scroll-margin-top
.
Como é possível inferir pelo próprio nome da propriedade, scroll-margin-top
adiciona espaçamento entre o target e o topo da viewport, sanando o problema de o texto do alvo ficar total ou parcialmente “fora de tela”.
Juntando tudo: navegação com smooth scroll usando CSS puro
Então, a partir do que foi mostrado até agora, usando o que já existia e novidades CSS quentíssimas, é possível sim conseguir o efeito de navegação suave com smooth scroll usando apenas CSS puro!
Independentemente de como é o layout de sua página, é possível juntar tudo o que foi visto e conseguir smooth scroll só com CSS através do seguinte snippet:
1 2 3 4 5 6 7 |
html { scroll-behavior: smooth; } :target { scroll-margin-top: .8em; } |
Perceba que :target
pode ser usado em elementos específicos, mas, assim como muitos outros pseudo em CSS, se usado “solto”, representa a estilização em tudo o que é afetado pelo estilo em questão.
Dica bônus!
Na verdade, é possível aprimorar esse snippet para que ele atenda a mais casos e agrade a mais pessoas. Para isso, como gostamos, vamos usar de CSS moderno.
Mais especificamente, a media query prefers-reduced-motion
.
Da nova fornada de media queries, prefers-reduced-motion
é usado para detectar se a pessoa habilitou que o sistema minimizasse a quantidade de movimento não-essencial que será mostrado.
Se você está se perguntando porque alguém faria isso, vai desde uma mera preferência de interação até evitar passar mal — há pessoas que podem ficar com tontura/vertigem com determinados tipos de animação (distúrbios vestibulares).
prefers-reduced-motion
aceita 2 valores:
no-preference
. Nenhuma configuração específica sobre redução de motion foi especificada;reduce
. Foi requisitado ao sistema a redução de animações não-essenciais.
Torna-se possível, com isso, o aprimoramento do snippet, permitindo smooth scroll somente nos casos em que a pessoa não tem nenhuma configuração específica sobre redução de movimentos:
1 2 3 4 5 6 7 8 9 |
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } } :target { scroll-margin-top: .8em; } |
Conclusão
Na data de publicação deste artigo, o suporte cross-browser total para o snippet não é uma realidade. Entretanto, se você já quiser usá-lo dentro de uma estratégia de suporte condicional com fallback, seu código já fica preparado para o futuro — além de bem elegante.
Começar a dar atenção para outros tipos de media queries, tal como prefers-reduced-motion
, e também pensar mais globalmente nas possibilidades de interação (ou falta de) na Web, adequando seu CSS a isso, é um passo importante a se dar rumo a um código mais maduro e profissional.
E aí, vale a pena trocar dezenas de KB de JavaScript por 8 linhas de código CSS puro? :)