Skip to content
This page has been auto-translated and may contain errors.View in English

Tabelas ​

docs.scrimba.com

Algumas informações são naturalmente uma grade. Uma tabela de horários de trem, um plano de preços, uma tabela de classificação, um conjunto de informações nutricionais: cada uma dessas coisas tem linhas e colunas, e o sentido está em como elas se alinham. O HTML tem um conjunto de elementos dedicado exatamente a esse tipo de conteúdo, e usá-los mantém a grade legível tanto na tela quanto para programas que leem a página em voz alta.

Fundamentos de tabelas ​

Uma tabela é uma grade de linhas e colunas, com a mesma estrutura de uma planilha. Você constrói uma usando quatro elementos. <table> envolve toda a grade. Cada <tr> é uma linha (tr vem de table row). Dentro de uma linha, cada <td> é uma célula de dados (td é table data). Quando uma célula rotula sua coluna ou linha, você usa <th> em vez disso (th é table header), e o navegador a exibe em negrito e centralizada, para que ela se destaque dos dados.

Você constrói uma tabela linha por linha, nunca coluna por coluna. <table> é o contêiner, cada <tr> é uma linha, e as células ficam dentro da linha na ordem em que aparecem ao longo da página. Uma célula de dados é <td>; uma célula de cabeçalho é <th>. Não existe um elemento de coluna. As colunas surgem naturalmente do fato de cada linha manter suas células na mesma ordem, então, se uma linha sair de sincronia, a grade deixa de se alinhar.

A diferença entre <th> e <td> não é apenas visual. <th> marca uma célula como um cabeçalho da linha ou coluna em que ela está. O estilo padrão do navegador, negrito e centralizado, é só a parte visível disso. A outra parte é o significado que outros programas conseguem interpretar.

O código-fonte de uma tabela é organizado por linha: você escreve uma linha por vez, e a coluna de cada célula é determinada apenas pela posição dela dentro da linha. O navegador lê esse código linha por linha e constrói a partir dele uma grade bidimensional, encaixando as células nas colunas ao contar a posição de cada uma. Nada na marcação nomeia uma coluna, então a grade só fica alinhada se as suas linhas forem consistentes.

<th> versus <td> é uma distinção semântica, não uma questão de estilo. <th> (uma célula de cabeçalho) diz ao navegador, e a qualquer tecnologia assistiva que esteja lendo a página (programas como leitores de tela, que falam o conteúdo da página em voz alta para pessoas que não conseguem vê-la), que essa célula é um rótulo para os dados ao seu redor. A aparência padrão em negrito e centralizada é incidental: remova-a com CSS e o cabeçalho ainda significa "cabeçalho", porque o significado está no elemento, não na aparência dele. É exatamente por isso que vale a pena usar uma tabela de verdade em vez de desenhar uma grade de outra forma.

html
<table>
  <tr>
    <th>Dia</th>
    <th>Horário de funcionamento</th>
  </tr>
  <tr>
    <td>Segunda-feira</td>
    <td>8:00 às 18:00</td>
  </tr>
  <tr>
    <td>Sábado</td>
    <td>9:00 às 14:00</td>
  </tr>
</table>

Duas células de cabeçalho no topo, depois duas linhas de dados. O navegador desenha a grade, ajusta o tamanho de cada coluna ao conteúdo e renderiza as duas células <th> em negrito.

JunoFundamentos de tabelas Quatro elementos formam uma grade: <table> envolvendo tudo, <tr> para cada linha, <td> para uma célula, e <th> para uma célula de cabeçalho. As células de cabeçalho saem em negrito e centralizadas, para se destacarem dos dados. Construa uma linha por vez e as colunas se alinham por conta própria.
JunoFundamentos de tabelas Você monta uma tabela linha por linha com <tr>, e as colunas surgem do fato de cada linha manter suas células na mesma ordem. <th> para cabeçalhos, <td> para dados, e essa escolha tem significado, não é só uma questão visual. Erre a contagem de células em uma linha e a grade toda fica torta.
JunoFundamentos de tabelas A marcação é organizada por linha, então uma coluna só existe porque cada linha mantém suas células na mesma ordem. Conte com cuidado. <th> justifica seu uso ao dizer a um leitor de tela que aquela célula é um rótulo, algo que nenhuma quantidade de negrito via CSS consegue fazer. Essa distinção semântica é o motivo de usar uma tabela de verdade.

Estruturando uma tabela ​

A ordem das suas linhas é a ordem em que as pessoas as leem, então coloque a linha de cabeçalho, aquela feita de células <th>, no topo. Depois mantenha todas as linhas com o mesmo tamanho: se a linha de cabeçalho tem três células, cada <tr> abaixo dela também precisa ter três células <td>. Uma linha com uma célula faltando deixa um buraco na grade, e as colunas deixam de se alinhar. Não há nada novo para aprender aqui, só cuidado com as linhas que você já conhece.

Quando uma tabela cresce, agrupe suas linhas em grupos de linhas para deixar a estrutura explícita. Envolva a linha de cabeçalho em <thead>, as linhas de dados em <tbody>, e qualquer linha de resumo, como uma linha de totais, em <tfoot>. Esses grupos, por si só, não mudam muito o layout, mas rotulam as partes da tabela para estilização, impressão e programas de acessibilidade.

Dê um título à tabela com <caption>, colocado como o primeiro filho de <table>. Ele é exibido acima da grade e, diferente de um cabeçalho que você coloca ao lado da tabela, fica vinculado a ela dentro da própria marcação.

Quando uma célula precisa cobrir mais de uma coluna ou linha, use colspan ou rowspan. colspan="2" faz uma célula ocupar a largura de duas colunas; rowspan="2" faz ela ocupar a altura de duas linhas. As posições cobertas ficam de fora dessas linhas, porque aquele espaço já está ocupado:

html
<thead>
  <tr>
    <th rowspan="2">Região</th>
    <th colspan="2">2024</th>
  </tr>
  <tr>
    <th>T1</th>
    <th>T2</th>
  </tr>
</thead>

"Região" ocupa duas linhas de cabeçalho, "2024" ocupa duas colunas, e T1 e T2 ficam abaixo dela, na segunda linha.

Os grupos de linhas não são decoração. <thead> e <tfoot> são definidos para se repetir em cada página quando uma tabela longa é impressa, para que o cabeçalho permaneça visível mesmo após uma quebra de página, e eles permitem manter um cabeçalho ou rodapé fixo enquanto <tbody> rola. Uma tabela pode ter vários grupos <tbody>, o que é uma forma limpa de dividir um conjunto de dados longo em seções rotuladas sem quebrar a grade única.

colspan e rowspan controlam o espalhamento de células (uma célula que cobre mais de uma coluna ou linha), e é aqui que as tabelas mais frequentemente quebram silenciosamente. Toda linha ainda precisa preencher a largura total da grade. Uma célula com colspan="2" ocupa duas colunas, então as linhas que ela sobrepõe precisam deixar essas posições vazias, em vez de fornecer sua própria célula. Erre a contagem e o navegador ainda vai renderizar algo, mas não a grade que você pretendia. <caption> é o nome acessível da tabela: programas de acessibilidade (ferramentas como leitores de tela que leem a página em voz alta) o anunciam quando o leitor chega até a tabela, fazendo um trabalho que um cabeçalho próximo não consegue fazer.

html
<table>
  <caption>Receita trimestral por região</caption>
  <thead>
    <tr>
      <th>Região</th>
      <th>T1</th>
      <th>T2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>Norte</th>
      <td>R$ 12.000</td>
      <td>R$ 15.400</td>
    </tr>
    <tr>
      <th>Sul</th>
      <td>R$ 9.800</td>
      <td>R$ 11.200</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <th>Total</th>
      <td>R$ 21.800</td>
      <td>R$ 26.600</td>
    </tr>
  </tfoot>
</table>
JunoEstruturando uma tabela As linhas se leem de cima para baixo, então comece com a sua linha de cabeçalho de células <th>. Depois mantenha todas as linhas com o mesmo tamanho: três cabeçalhos no topo significam três células <td> em cada linha abaixo. Uma célula faltando é um buraco na grade, e é isso que costuma pegar as pessoas no começo.
JunoEstruturando uma tabela Agrupe as partes quando a tabela crescer: <thead> para a linha de cabeçalho, <tbody> para os dados, <tfoot> para uma linha de totais, e um <caption> como primeiro filho para o título. colspan e rowspan esticam uma célula por colunas ou linhas, mas lembre-se de que as posições cobertas saem dessas linhas. Acerte a contagem e a grade se mantém firme.
JunoEstruturando uma tabela Os grupos realmente fazem a diferença: <thead> e <tfoot> se repetem quando a tabela é impressa e podem ancorar um corpo que rola na tela, e <caption> é o nome que um leitor de tela lê em voz alta. O espalhamento é a armadilha silenciosa, já que toda linha ainda precisa preencher a largura total da grade, então uma posição coberta não recebe célula própria. O navegador renderiza um erro de contagem sem reclamar, e é exatamente por isso que é difícil perceber.

Tabelas acessíveis ​

Uma tabela acessível é aquela que faz sentido para todo mundo, incluindo pessoas que ouvem a página com um leitor de tela (um programa que lê a página em voz alta) em vez de vê-la. A coisa mais útil que você pode fazer já está no seu repertório: use <th> em toda célula de cabeçalho, não <td>. Assim, um leitor de tela consegue dizer a quem está escutando quais células são rótulos e quais são dados, de modo que um valor como "R$ 15" seja anunciado junto com a coluna a que pertence. Uma tabela em que toda célula é um simples <td> é lida como uma parede de números sem nada que os ancore.

<th> marca uma célula como cabeçalho, mas em uma tabela com cabeçalhos de coluna e de linha ao mesmo tempo, isso não diz qual é qual. O atributo scope deixa isso explícito. scope="col" diz que um cabeçalho rotula toda a sua coluna; scope="row" diz que ele rotula toda a sua linha. Adicione isso a cada <th> e um leitor de tela conseguirá associar qualquer célula de dados ao cabeçalho de coluna e ao cabeçalho de linha corretos, ao mesmo tempo.

html
<th scope="col">Mês</th>
<th scope="row">Chuva</th>

Para uma grade simples, o navegador muitas vezes já consegue adivinhar essas associações, mas declará-las com scope elimina a adivinhação e custa pouco para adicionar.

scope cobre tabelas com um único nível de cabeçalhos de linha e coluna. Tabelas complexas, com um cabeçalho que se estende por várias colunas ou com dois níveis de cabeçalhos de coluna, continuam ambíguas mesmo com scope, porque uma célula de dados deixa de ter exatamente um cabeçalho de coluna e um de linha acima dela. Para esses casos, associe as células explicitamente usando id e headers. Dê a cada célula de cabeçalho um id (um nome único para aquele elemento) e depois liste os ids relevantes no atributo headers de cada célula de dados:

html
<th id="q1">T1</th>
<th id="north">Norte</th>
<td headers="north q1">R$ 12.000</td>

Agora a célula de dados nomeia exatamente quais cabeçalhos a descrevem, na ordem em que devem ser lidos, e nenhum algoritmo precisa inferir essa relação. É verboso, então reserve isso para as tabelas que realmente precisam. Recorra a scope primeiro e só suba para id e headers quando a estrutura de cabeçalhos for irregular demais para o scope expressar.

A acessibilidade vai muito além das tabelas; o capítulo Acessibilidade cobre o resto do panorama.

JunoTabelas acessíveis O maior ganho não custa nada extra: use <th> para cabeçalhos e <td> para dados. Um leitor de tela se apoia nessa distinção para ler cada valor junto com o cabeçalho ao qual pertence, de modo que R$ 15 chegue acompanhado da sua coluna, e não solto. Ignore isso e a tabela toda vira uma parede de números soltos.
JunoTabelas acessíveis Coloque scope nas suas células de cabeçalho: scope="col" para um cabeçalho de coluna, scope="row" para um cabeçalho de linha. Isso permite que um leitor de tela associe cada célula de dados ao cabeçalho certo nos dois eixos. O navegador consegue adivinhar em grades simples, mas declarar isso é barato e elimina a adivinhação.
JunoTabelas acessíveisscope resolve a grade comum, com um cabeçalho para cada lado. Quando os cabeçalhos se estendem ou se empilham e uma célula tem mais de um cabeçalho no mesmo eixo, troque para id nos cabeçalhos e headers nas células de dados para ligá-los manualmente. É mais verboso, então reserve isso para as tabelas que realmente precisam e deixe o scope cuidar do resto.

Para que servem as tabelas ​

Houve uma época, antes de o CSS conseguir cuidar do layout, em que as pessoas construíam páginas inteiras usando tabelas: uma <table> para colocar o menu à esquerda e o conteúdo à direita. Isso funciona visualmente, então você ainda vê esse padrão em páginas antigas e em alguns modelos de e-mail. Não copie isso. Uma tabela serve para dados tabulares, informações que pertencem a uma grade de linhas e colunas. Organizar as partes de uma página é trabalho do CSS. Usar uma tabela para posicionar elementos, em vez de guardar dados, torna a página mais difícil de ler para quem usa um leitor de tela, e mais difícil de ajustar depois.

A regra é curta: uma <table> significa "este conteúdo é uma grade de dados relacionados". Use-a quando a informação realmente tiver linhas e colunas: um cronograma, uma comparação, um conjunto de resultados. Não a use para organizar uma página, e não a use para alinhar coisas que não são dados. CSS grid e flexbox fazem layout de forma adequada, se adaptam ao tamanho da tela e mantêm seu HTML descrevendo conteúdo, em vez de descrever um arranjo visual.

Recorrer a uma tabela só para conseguir colunas é o uso indevido clássico. Se o conteúdo é uma barra de navegação ou um formulário espalhado pela página, isso não é dado tabular, e uma tabela é a ferramenta errada, mesmo que seja possível fazê-la parecer certa.

Quando você usa uma tabela para layout, você entrega a programas de acessibilidade (ferramentas como leitores de tela que falam o conteúdo da página) uma estrutura de dados que não é dado nenhum. Um leitor de tela anuncia uma tabela pelas suas dimensões e permite que o usuário navegue célula por célula, tratando o esqueleto do layout como se cada região fosse um valor relacionado dentro de uma grade. O resultado são anúncios como "tabela, quatro colunas, dez linhas" para algo que, na verdade, é um cabeçalho, uma barra lateral e um artigo.

Existe também um problema de ordem de leitura. Programas de acessibilidade e mecanismos de busca leem a página na ordem do código-fonte, a ordem em que os elementos aparecem no seu HTML, não a ordem em que eles acabam ficando na tela. Uma tabela usada para layout obriga a ordem do código-fonte a coincidir com a grade visual, então um conteúdo que deveria vir primeiro para quem está escutando, o artigo principal, pode acabar depois de uma coluna de navegação, só porque foi ali que a coluna visual precisou dele. O layout em CSS rompe esse vínculo: você pode manter o conteúdo importante no início do código-fonte e ainda assim posicioná-lo em qualquer lugar da tela. Reserve tabelas para dados, e a ordem de leitura continua sob seu controle.

A única área cinzenta é o e-mail em HTML, onde clientes de e-mail mais antigos ainda não têm um suporte confiável a layout em CSS, e estruturas baseadas em tabelas continuam comuns. Isso é uma limitação daquele meio específico, não um padrão para trazer de volta à web.

html
<!-- Errado: uma tabela usada para posicionar uma barra lateral ao lado de um artigo -->
<table>
  <tr>
    <td><nav>...</nav></td>
    <td><article>...</article></td>
  </tr>
</table>

<!-- Certo: elementos reais, com o CSS cuidando das colunas -->
<nav>...</nav>
<article>...</article>

Essa é a mesma separação entre estrutura e apresentação apresentada em O que é HTML: estrutura no HTML, layout no CSS. Para escolher elementos pelo seu significado, veja HTML semântico.

JunoPara que servem as tabelas Uma tabela serve para dados que pertencem a uma grade, linhas e colunas de valores relacionados. Ela não serve para organizar uma página, mesmo que sites antigos a usassem assim. Posicionar as partes de uma página é trabalho do CSS, e misturar isso com uma tabela torna a página mais difícil de ler em voz alta e mais difícil de mudar.
JunoPara que servem as tabelas Use <table> só quando o conteúdo realmente for uma grade de dados: um cronograma, uma comparação, uma lista de resultados. Para organizar uma página ou alinhar coisas que não são dados, recorra ao CSS grid ou flexbox, que se adaptam à tela e mantêm o seu HTML focado em conteúdo. Uma tabela colocada para fazer trabalho de layout é o exemplo clássico de ferramenta errada.
JunoPara que servem as tabelas Uma tabela usada para layout confunde um leitor de tela: ele ouve uma grade de dados e anuncia linhas e colunas que não significam nada. Ela também prende a ordem do código-fonte à grade visual, quando é justamente a ordem do código-fonte que programas de acessibilidade e mecanismos de busca realmente leem. Reserve tabelas para dados, deixe o CSS posicionar as coisas, e a ordem de leitura permanece sob seu controle. O e-mail em HTML é a única exceção, e só porque os clientes de e-mail continuam presos ao passado.