Legendas e acessibilidade em tabelas: caption e scope

Aprenda a adicionar legendas às tabelas e a usar o atributo scope para torná-las acessíveis a leitores de tela.

Uma tabela bem estruturada com <thead>, <tbody>, <tfoot>, <th> e <td> já é um ótimo começo. Mas para que ela seja realmente acessível e compreensível para todos os usuários — especialmente aqueles que usam leitores de tela —, precisamos adicionar duas peças-chave: uma legenda que descreva o conteúdo da tabela e o atributo scope para associar corretamente os cabeçalhos aos dados.


caption: a legenda da tabela

A tag <caption> fornece um título ou legenda descritiva para a tabela. Ela deve ser o primeiro elemento filho da tag <table>.

<table>
  <caption>Vendas mensais da empresa X no último trimestre</caption>
  <thead>
    <tr>
      <th>Mês</th>
      <th>Vendas</th>
      <th>Lucro</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Janeiro</td>
      <td>R$ 10.000</td>
      <td>R$ 2.000</td>
    </tr>
    <tr>
      <td>Fevereiro</td>
      <td>R$ 12.000</td>
      <td>R$ 2.500</td>
    </tr>
    <tr>
      <td>Março</td>
      <td>R$ 15.000</td>
      <td>R$ 3.000</td>
    </tr>
  </tbody>
</table>

Por que usar caption?

  • Acessibilidade: Leitores de tela anunciam o conteúdo do <caption> logo no início, dando ao usuário um contexto claro sobre o que a tabela representa antes mesmo de começar a navegar pelos dados. Isso é crucial para decidir se a tabela é relevante.
  • Usabilidade: Ajuda todos os usuários a entenderem rapidamente o propósito da tabela, especialmente em páginas com múltiplas tabelas.
  • Semântica: O <caption> é semanticamente ligado à tabela, ao contrário de um <p> ou <h2> solto acima dela.

Posicionamento do caption

Por padrão, o navegador posiciona o <caption> acima da tabela. Você pode mudar isso com CSS usando a propriedade caption-side:

/* Posiciona a legenda abaixo da tabela */
caption {
  caption-side: bottom;
}

scope: associando cabeçalhos e dados

O atributo scope é usado nas células de cabeçalho (<th>) para indicar se aquele cabeçalho se aplica a uma coluna ou a uma linha de dados. Isso é vital para leitores de tela.

Valores do atributo scope

Valor Propósito
col O <th> é um cabeçalho para a coluna abaixo dele.
row O <th> é um cabeçalho para a linha à direita dele.
colgroup O <th> é um cabeçalho para um grupo de colunas.
rowgroup O <th> é um cabeçalho para um grupo de linhas.

Exemplo de scope="col"

Para cabeçalhos de coluna (o caso mais comum):

<table>
  <caption>Notas dos alunos por disciplina</caption>
  <thead>
    <tr>
      <th>Aluno</th>
      <th scope="col">Matemática</th>
      <th scope="col">Português</th>
      <th scope="col">História</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Ana Silva</th>
      <td>8.5</td>
      <td>9.0</td>
      <td>7.5</td>
    </tr>
    <tr>
      <th scope="row">Carlos Lima</th>
      <td>7.0</td>
      <td>8.0</td>
      <td>9.0</td>
    </tr>
  </tbody>
</table>

Neste exemplo:

  • <th> "Matemática" com scope="col" informa que ele é o cabeçalho para a coluna de notas de Matemática.
  • <th> "Ana Silva" com scope="row" informa que ele é o cabeçalho para a linha de notas da Ana Silva.

Por que usar scope?

  • Acessibilidade: Leitores de tela usam o scope para associar corretamente cada célula de dado (<td>) ao seu cabeçalho (<th>). Ao navegar por uma célula como "8.5", o leitor de tela pode anunciar: "8.5, coluna Matemática, linha Ana Silva". Sem scope, essa associação pode ser ambígua ou inexistente, especialmente em tabelas complexas.
  • Clareza: Ajuda a entender a estrutura da tabela, especialmente quando há cabeçalhos de linha e coluna.

Tabelas com cabeçalhos de linha e coluna

Quando uma tabela tem cabeçalhos tanto na primeira linha (para colunas) quanto na primeira coluna (para linhas), o uso de scope se torna ainda mais importante:

<table>
  <caption>Disponibilidade de Salas de Reunião (Horário Comercial)</caption>
  <thead>
    <tr>
      <th></th> <!-- Célula vazia no canto superior esquerdo -->
      <th scope="col">Sala Alfa</th>
      <th scope="col">Sala Beta</th>
      <th scope="col">Sala Gama</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">09:00 - 10:00</th>
      <td>Livre</td>
      <td>Ocupada</td>
      <td>Livre</td>
    </tr>
    <tr>
      <th scope="row">10:00 - 11:00</th>
      <td>Ocupada</td>
      <td>Livre</td>
      <td>Ocupada</td>
    </tr>
    <tr>
      <th scope="row">11:00 - 12:00</th>
      <td>Livre</td>
      <td>Livre</td>
      <td>Livre</td>
    </tr>
  </tbody>
</table>

Neste exemplo, ao navegar para a célula "Ocupada" na segunda linha e segunda coluna, um leitor de tela pode anunciar: "Ocupada, coluna Sala Beta, linha 10:00 - 11:00". Isso é possível graças ao scope="col" nos cabeçalhos de sala e scope="row" nos cabeçalhos de horário.


Tabelas com colspan e rowspan

Em tabelas que usam colspan e rowspan, o scope é ainda mais crítico para manter a acessibilidade. Ele ajuda a desambiguar a relação entre células de dados e cabeçalhos mesclados.

<table>
  <caption>Relatório de Vendas por Região e Ano</caption>
  <thead>
    <tr>
      <th rowspan="2">Região</th>
      <th colspan="2" scope="colgroup">Vendas (Milhões)</th>
      <th rowspan="2" scope="col">Crescimento (%)</th>
    </tr>
    <tr>
      <th scope="col">2025</th>
      <th scope="col">2026</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Norte</th>
      <td>12.5</td>
      <td>14.8</td>
      <td>18.4</td>
    </tr>
    <tr>
      <th scope="row">Sul</th>
      <td>20.1</td>
      <td>22.5</td>
      <td>11.9</td>
    </tr>
  </tbody>
</table>

Neste exemplo:

  • <th> "Vendas (Milhões)" tem colspan="2" e scope="colgroup". Isso indica que ele é o cabeçalho para o grupo de colunas "2025" e "2026".
  • <th> "2025" e "2026" têm scope="col", indicando que são cabeçalhos para suas respectivas colunas.
  • <th> "Região" e "Crescimento (%)" têm rowspan="2" e scope="col", indicando que são cabeçalhos para suas colunas e se estendem por duas linhas.
  • <th> "Norte" e "Sul" têm scope="row", indicando que são cabeçalhos para suas respectivas linhas.

Resumindo

  • <caption> → O primeiro filho de <table>, fornece um título/legenda descritiva para a tabela. Essencial para contexto e acessibilidade.
  • scope → Atributo em <th> que indica se o cabeçalho se aplica a uma coluna (col), linha (row), grupo de colunas (colgroup) ou grupo de linhas (rowgroup).
  • scope é crucial para leitores de tela associarem corretamente as células de dados aos seus cabeçalhos, especialmente em tabelas complexas ou com colspan/rowspan.
  • Sempre use <caption> e scope em suas tabelas para garantir a máxima acessibilidade.