Links internos e âncoras na mesma página

Crie links que levam o usuário para uma seção específica da mesma página, usando IDs como destino.

Na lição sobre a tag <a>, você viu que é possível usar href="#id" para levar o usuário a uma seção da mesma página. Nesta lição, vamos explorar esse recurso com profundidade — como ele funciona por baixo dos panos, como construir sumários e menus de navegação interna, como implementar o botão "voltar ao topo", como o hash aparece na URL, os problemas com cabeçalhos fixos e, principalmente, como tornar toda essa navegação acessível.


Como as âncoras funcionam

Uma âncora de navegação interna funciona com dois elementos:

1. O link — a tag <a> com href começando com # seguido de um identificador:

<a href="#introducao">Ir para a introdução</a>

2. O destino — qualquer elemento HTML com um id cujo valor corresponda ao identificador usado no href:

<h2 id="introducao">Introdução</h2>

Quando o usuário clica no link, o navegador rola a página até o elemento que tem aquele id e o posiciona no topo da viewport.


O hash na URL

Uma característica importante das âncoras é que elas modificam a URL da página ao serem ativadas. O identificador após o # — chamado de fragment identifier ou simplesmente hash — é adicionado ao endereço no navegador:

Antes do clique:
https://meusite.com/artigo

Depois do clique em href="#secao-2":
https://meusite.com/artigo#secao-2

Esse comportamento traz vantagens reais:

  • Compartilhamento direto → você pode copiar e enviar a URL com hash para alguém, que vai chegar exatamente na seção correta ao abrir o link
  • Histórico do navegador → o botão "voltar" funciona entre posições da página visitadas por âncoras
  • Marcadores → o usuário pode salvar nos favoritos a URL com hash para retornar àquela seção específica

Boas práticas para valores de id

O valor do id usado como destino de âncora deve seguir algumas regras para funcionar corretamente e ser fácil de usar em URLs:

<!-- ✅ Boas práticas -->
<h2 id="como-instalar">Como instalar</h2>
<h2 id="configuracao">Configuração</h2>
<h2 id="primeiros-passos">Primeiros passos</h2>

<!-- ❌ Evite -->
<h2 id="Como Instalar">Como instalar</h2>   <!-- espaços -->
<h2 id="seção-1">Seção 1</h2>              <!-- acento -->
<h2 id="1-introducao">Introdução</h2>       <!-- começa com número -->
<h2 id="introducao">Intro 1</h2>
<h2 id="introducao">Intro 2</h2>            <!-- id duplicado -->
  • Use apenas letras minúsculas, números e hífens
  • Comece sempre com uma letra
  • Evite acentos, espaços e caracteres especiais
  • Nunca repita um id na mesma página — ids são únicos por definição; duplicar um id cria comportamento imprevisível e invalida o documento HTML

Sumário de artigo: o caso de uso clássico

O uso mais comum de âncoras internas é o sumário — uma lista de links no início de um artigo longo que permite ao usuário ir direto para a seção desejada:

<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <title>Guia Completo de CSS</title>
</head>
<body>

  <h1>Guia Completo de CSS</h1>

  <!-- Sumário com âncoras -->
  <nav aria-label="Sumário do artigo">
    <h2>Neste artigo</h2>
    <ol>
      <li><a href="#o-que-e-css">O que é CSS</a></li>
      <li><a href="#seletores">Seletores</a></li>
      <li><a href="#box-model">Box Model</a></li>
      <li><a href="#flexbox">Flexbox</a></li>
      <li><a href="#referencias">Referências</a></li>
    </ol>
  </nav>

  <!-- Seções do artigo com ids correspondentes -->
  <section>
    <h2 id="o-que-e-css">O que é CSS</h2>
    <p>CSS, ou Cascading Style Sheets...</p>
  </section>

  <section>
    <h2 id="seletores">Seletores</h2>
    <p>Seletores definem quais elementos...</p>
  </section>

  <section>
    <h2 id="box-model">Box Model</h2>
    <p>O Box Model é o modelo de caixas...</p>
  </section>

  <section>
    <h2 id="flexbox">Flexbox</h2>
    <p>Flexbox é um modelo de layout...</p>
  </section>

  <section>
    <h2 id="referencias">Referências</h2>
    <p>...</p>
  </section>

</body>
</html>

💡 O <nav> com aria-label="Sumário do artigo" comunica explicitamente a função daquele bloco de navegação para leitores de tela e outros agentes, diferenciando-o do menu principal do site.


Botão "Voltar ao topo"

Um uso clássico e muito prático de âncoras é o botão "Voltar ao topo" em páginas longas. O destino é o próprio início da página:

<!-- Destino: a tag html ou o início do body -->
<html lang="pt-BR" id="topo">

<!-- Ou um elemento no início do conteúdo -->
<main id="topo">
  ...conteúdo longo...

  <!-- Botão ao final do conteúdo -->
  <a href="#topo">↑ Voltar ao topo</a>
</main>

Uma variação muito usada é colocar o destino na própria tag <body> ou em um <header> fixo:

<header id="cabecalho">
  <h1>Meu Site</h1>
</header>

<main>
  <p>Conteúdo longo da página...</p>

  <a href="#cabecalho">↑ Voltar ao topo</a>
</main>

Scroll suave com CSS

Por padrão, ao clicar em uma âncora o navegador pula abruptamente para a seção de destino. Para uma experiência mais agradável, você pode ativar o scroll suave com uma única linha de CSS:

html {
  scroll-behavior: smooth;
}

Com isso, a página desliza suavemente até o destino em vez de pular instantaneamente.

<!-- No HTML: o link de âncora não muda nada -->
<a href="#contato">Ir para contato</a>

<!-- No CSS: ativa o scroll suave para toda a página -->
<style>
  html {
    scroll-behavior: smooth;
  }
</style>

⚠️ Atenção ao scroll suave e acessibilidade: alguns usuários têm condições vestibulares ou de sensibilidade a movimentos que tornam animações de rolagem desconfortáveis. A boa prática é respeitar a preferência do sistema operacional com a media query prefers-reduced-motion:

html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

O problema do cabeçalho fixo

Um problema muito comum em sites com cabeçalho fixo (sticky header ou fixed header) é que ao clicar em uma âncora, o destino fica parcialmente coberto pelo cabeçalho:

┌─────────────────────────┐
│ CABEÇALHO FIXO (60px)   │  ← cobre o início da seção
├─────────────────────────┤
│← Seção de destino       │  ← começa aqui, mas o título
│  fica escondido atrás   │    ficou atrás do cabeçalho
│  do cabeçalho           │
└─────────────────────────┘

Solução com scroll-margin-top (CSS)

A solução moderna e recomendada é usar a propriedade CSS scroll-margin-top nos elementos de destino, adicionando uma margem de rolagem equivalente à altura do cabeçalho:

/* Cabeçalho com 60px de altura */
h2, h3, section, [id] {
  scroll-margin-top: 70px; /* altura do header + folga */
}

E no HTML:

<header style="position: fixed; top: 0; height: 60px;">
  <nav>...</nav>
</header>

<main style="margin-top: 60px;">
  <h2 id="sobre">Sobre nós</h2>
  <p>...</p>
</main>

Com scroll-margin-top: 70px, o navegador vai parar a rolagem 70px antes do elemento de destino — deixando espaço suficiente para o cabeçalho fixo não cobrir o conteúdo.


Skip navigation: âncoras para acessibilidade

Um dos usos mais importantes de âncoras internas é o skip navigation — ou "pular para o conteúdo" —, um link que permite a usuários de teclado e leitores de tela pular o menu de navegação e ir diretamente para o conteúdo principal da página.

Sem esse recurso, um usuário que navega apenas pelo teclado (usando Tab) precisa passar por todos os itens do menu toda vez que carrega uma nova página — o que pode ser dezenas de pressionamentos de Tab antes de chegar ao conteúdo.

<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <title>Meu Site</title>
  <style>
    /* O link fica invisível por padrão */
    .skip-link {
      position: absolute;
      top: -100px;
      left: 0;
    }

    /* Aparece quando recebe foco via teclado */
    .skip-link:focus {
      top: 0;
    }
  </style>
</head>
<body>

  <!-- Skip link: primeiro elemento focável da página -->
  <a href="#conteudo-principal" class="skip-link">
    Pular para o conteúdo principal
  </a>

  <header>
    <nav>
      <a href="/">Início</a>
      <a href="/sobre">Sobre</a>
      <a href="/blog">Blog</a>
      <a href="/contato">Contato</a>
      <!-- ... mais itens de menu ... -->
    </nav>
  </header>

  <!-- O destino do skip link -->
  <main id="conteudo-principal">
    <h1>Bem-vindo ao meu site</h1>
    <p>Conteúdo principal aqui...</p>
  </main>

</body>
</html>

O link é visualmente oculto por padrão, mas aparece na tela quando o usuário navega por teclado e o link recebe foco. É o primeiro elemento focável da página, garantindo que o usuário possa pular para o conteúdo sem precisar atravessar o menu.

💡 O skip link é um requisito das Diretrizes de Acessibilidade para Conteúdo Web (WCAG) — nível AA. Todo site acessível deve tê-lo implementado.


Âncoras em links externos

Você pode combinar uma URL externa com um hash para direcionar o usuário a uma seção específica de outra página — desde que essa página tenha o id correspondente:

<!-- Leva o usuário direto para a seção de atributos no MDN -->
<a
  href="https://developer.mozilla.org/pt-BR/docs/Web/HTML/Element/a#atributos"
  target="_blank"
  rel="noopener noreferrer"
>
  Atributos da tag a no MDN
</a>

Âncora sem destino: o href="#" isolado

Um uso muito comum — mas problemático — é o href="#" sem nenhum id correspondente na página:

<!-- ❌ Problema: rola para o topo e suja a URL -->
<a href="#">Ver mais</a>

Ao clicar, o navegador rola para o topo da página e adiciona o # na URL — o que raramente é o comportamento desejado. Evite usar href="#" como placeholder.

Se o link ainda não tem destino definido, a abordagem mais honesta é comentá-lo e usar um <button> ou outro elemento mais semântico para ações sem navegação:

<!-- ✅ Para ações sem navegação, use button -->
<button type="button">Ver mais</button>

<!-- ✅ Para link com destino ainda indefinido -->
<!-- <a href="pagina-em-construcao.html">Ver mais</a> -->

Resumindo

Recurso Como fazer
Âncora básica <a href="#id"> + elemento com id="id"
Hash na URL Adicionado automaticamente ao clicar
Sumário Lista de <a href="#secao"> + <hN id="secao">
Voltar ao topo <a href="#topo"> + id="topo" no início
Scroll suave scroll-behavior: smooth no CSS do html
Cabeçalho fixo scroll-margin-top nos elementos de destino
Skip navigation Primeiro link da página apontando para #main
Link externo com seção href="https://site.com/pagina#secao"

Regras de ouro:

  • id deve ser único na página — nunca repita
  • Use apenas letras, números e hífens no valor do id
  • Respeite prefers-reduced-motion ao usar scroll suave
  • Implemente skip navigation em todo site acessível
  • Evite href="#" como placeholder sem destino real