# Navegação âncora e smooth scroll com CSS puro

> Implemente navegação âncora com smooth scroll usando apenas CSS puro. Aprenda scroll-behavior nativo sem JavaScript para rolagem suave perfeita. Veja como!

URL: https://dpw.dev/css/navegacao-ancora-smooth-scroll-css-puro/  
Publicado em: 2020-12-21  
Categoria: css  
Tags: interface  
Autor: Tárcio Zemel

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](/categoria/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](https://developer.mozilla.org/pt-BR/docs/Web/CSS/:target),

> 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:

```html
<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:

```typescript
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`:

```scss
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:

```scss
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:

```scss
@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? :)

---

Fonte: [dpw - desenvolvimento para web](https://dpw.dev/) (pt-BR).
Guia para agentes: https://dpw.dev/llms.txt
Índice completo: https://dpw.dev/sitemap-index.xml
Feed: https://dpw.dev/rss.xml
