Uma navegação scrollspy é um padrão de interface comum que destaca automaticamente o link de navegação correspondente à seção da página que está na janela de visualização. Isso dá aos usuários uma noção clara de onde estão em um documento longo enquanto rolam a tela.
Esse padrão é comum em dois cenários:
- Sites de página única: em que a navegação principal do site leva a diferentes seções de uma única página, em vez de URLs separados.
- Conteúdo longo: quando um sumário ou menu lateral de navegação acompanha o progresso do usuário em um artigo, guia ou documentação.
Como fazer a implementação
Tradicionalmente, o padrão scrollspy exigia JavaScript e a API IntersectionObserver. O CSS moderno oferece uma maneira nativa de fazer isso usando a propriedade scroll-target-group e a pseudoclasse :target-current.
- Verifique se os links de navegação usam identificadores de fragmento: sua navegação precisa consistir em links fixos (
<a>) que apontam para seções na mesma página usando identificadores de fragmento (por exemplo,<a href="#section-1">) que correspondem aoiddas suas seções de conteúdo. - Ativar o agrupamento de destinos de rolagem: aplique a propriedade
scroll-target-group: autoao contêiner dos seus links de navegação. Isso informa ao navegador que esses links devem ser tratados como marcadores que rastreiam os respectivos destinos. - Estilizar o link ativo: use a pseudoclasse
:target-currentnos links de navegação para aplicar estilos quando a seção de destino estiver visível no contêiner de rolagem. - Estado semântico: use um script para atualizar
aria-current="true"no link ativo quando a rolagem parar para garantir que o estado seja comunicado corretamente às tecnologias adaptativas.
Exemplo de código
Este exemplo destaca o link ativo em um menu de navegação fixo conforme o usuário rola pelas seções.
/* MANDATORY: The container of markers must have scroll-target-group: auto */
nav {
/* Enables automatic tracking of fragment links */
scroll-target-group: auto;
}
/* MANDATORY: Use :target-current to style the link whose target is in view. */
nav a:target-current {
color: var(--accent, #007bff);
border-bottom-color: var(--accent, #007bff);
}
<nav>
<a href="#intro">Introduction</a>
<a href="#features">Features</a>
<a href="#pricing">Pricing</a>
</nav>
<main>
<!-- MANDATORY: Each section must have a unique ID matching a link fragment in the <nav>. -->
<section id="intro">
<h2>Introduction</h2>
<!-- content -->
</section>
<section id="features">
<h2>Features</h2>
<!-- content -->
</section>
<section id="pricing">
<h2>Pricing</h2>
<!-- content -->
</section>
</main>
<script type="module">
if (CSS.supports('scroll-target-group: auto')) {
const syncAriaCurrent = () => {
const currentLink = document.querySelector('nav a:target-current');
document.querySelectorAll('nav a').forEach(link => {
link.setAttribute('aria-current', link === currentLink ? 'true' : 'false');
});
};
// Update the aria on initial page load. Ensure the DOM content is loaded, either by using `<script type="module">` or an event listener for `DOMContentLoaded`.
syncAriaCurrent();
// Update the aria after scroll ends
document.addEventListener('scrollend', syncAriaCurrent);
}
</script>
Práticas recomendadas
- USE
scroll-target-group: autoem um contêiner dedicado para links de navegação: isso garante que o navegador saiba quais links devem ser rastreados. - É RECOMENDÁVEL garantir que os destinos tenham atributos
idexclusivos que correspondam aos atributoshrefdos links. - FORNEÇA espaço vertical suficiente para as seções: o
scroll-target-groupidentifica com mais clareza o destino visível quando as seções são grandes o suficiente para que apenas uma ou duas fiquem visíveis por vez. - OBRIGATÓRIO: para acessibilidade, o estado visual precisa ser espelhado com
aria-current. Embora o:target-currentlide com o aspecto visual, ele não é exposto aos leitores de tela. - AVOID usar apenas cores para o estado ativo: inclua outras dicas visuais, como espessura da fonte, sublinhado ou um ponto indicador, ou garanta que haja contraste suficiente entre as cores para que a diferença seja acessível a usuários com deficiências de visão de cores.
Estratégias de fallback
Para navegadores que não são compatíveis com scroll-target-group, use um substituto com base na API IntersectionObserver.
<script>
// Feature detection for scroll-target-group
const supportsScrollTargetGroup = CSS.supports('scroll-target-group: auto');
if (!supportsScrollTargetGroup) {
const navLinks = document.querySelectorAll('nav a');
const sections = document.querySelectorAll('main section');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const id = entry.target.getAttribute('id');
navLinks.forEach(link => {
const isActive = link.getAttribute('href') === `#${id}`;
// Use the escaped colon class for consistent styling
link.classList.toggle('\:target-current', isActive);
link.setAttribute('aria-current', isActive);
});
}
});
}, { rootMargin: '-50% 0px -50% 0px', threshold: 0 });
sections.forEach(section => observer.observe(section));
}
</script>
<style>
/* Fallback style if :target-current is not supported.
Use :is() to combine the native pseudo-class with a fallback class for older browsers. DO NOT use `nav a:target-current, nav a.\:target-current, as the unrecognized pseudoselector invalidates the entire rule in older browsers. */
nav a:is(:target-current, .\:target-current) {
color: var(--accent, #007bff);
border-bottom-color: var(--accent, #007bff);
font-weight: bold;
}
</style>