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

Tabelas

docs.scrimba.com

Algumas informações formam uma grade. Um horário de trens, um plano de preços, uma tabela de classificação, um conjunto de informações nutricionais: cada um tem linhas e colunas, e o significado está em como elas se alinham. HTML possui um conjunto dedicado de elementos para exatamente esse tipo de conteúdo, e usá-los mantém a grade legível tanto na tela quanto para software que lê a página em voz alta.

Noções básicas de tabelas

Uma tabela é uma grade de linhas e colunas, com a mesma forma que uma planilha. Você a constrói a partir de quatro elementos. <table> envolve toda a grade. Cada <tr> é uma linha (tr é abreviação 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 mostra em negrito e centralizada para se destacar 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 na página. Uma célula de dados é <td>; uma célula de cabeçalho é <th>. Não existe elemento de coluna. As colunas são um efeito emergente de cada linha manter suas células na mesma ordem, então se uma linha sair do ritmo a grade para de se alinhar.

A diferença entre <th> e <td> não é apenas cosmética. <th> marca uma célula como um cabeçalho para a linha ou coluna em que ela fica. O estilo padrão do navegador, negrito e centralizado, é apenas a metade visível disso. A outra metade é significado que outro software pode ler.

A origem de uma tabela é orientada por linhas: você a escreve uma linha por vez, e a coluna de cada célula é decidida puramente por sua posição dentro da linha. O navegador lê essa origem linha por linha e constrói uma grade bidimensional a partir dela, correspondendo células em colunas contando. Nada na marcação nomeia uma coluna, então a grade é apenas tão alinhada quanto suas linhas forem consistentes.

<th> versus <td> é uma distinção semântica, não estilística. <th> (uma célula de cabeçalho) diz ao navegador, e a qualquer tecnologia assistiva lendo a página (software como um leitor de tela, que fala a 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. O aspecto negrito-e-centralizado padrão é incidental: remova-o com CSS e o cabeçalho ainda significa "cabeçalho", porque o significado vive no elemento, não em sua aparência. Essa é toda a razão para usar uma tabela real 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 a 18:00</td>
  </tr>
  <tr>
    <td>Sábado</td>
    <td>9:00 a 14:00</td>
  </tr>
</table>

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

JunoNoções básicas de tabelas Quatro elementos fazem uma grade: <table> em volta de 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 centralizado para se destacarem dos dados. Construa linha por linha e as colunas se alinham sozinhas.
JunoNoções básicas de tabelas Você dispõe uma tabela linha por linha com <tr>, e as colunas surgem de cada linha mantendo suas células na mesma ordem. <th> para cabeçalhos, <td> para dados, e essa escolha é significado, não apenas a aparência em negrito. Conte errado as células em uma linha e a grade inteira fica torta.
JunoNoções básicas de tabelas A marcação é orientada por linhas, então uma coluna só existe porque cada linha mantém suas células em sincronia. Conte com cuidado. <th> ganha seu lugar ao dizer a um leitor de tela que a célula é um rótulo, algo que nenhuma quantidade de negrito CSS pode fazer. Essa divisão semântica é a razão para usar uma tabela real.

Estruturando uma tabela

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

Uma vez que uma tabela cresce, agrupe suas linhas em grupos de linhas para que a estrutura seja 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 não mudam muito o layout por si só, mas rotulam as partes da tabela para estilo, para impressão e para software assistivo.

Dê à tabela um título com <caption>, colocado como o primeiro filho de <table>. É renderizado acima da grade e, diferentemente de um cabeçalho que você coloca ao lado da tabela, está vinculado à tabela na marcação.

Quando uma célula precisa cobrir mais de uma coluna ou linha, use colspan ou rowspan. colspan="2" faz uma célula tão larga quanto duas colunas; rowspan="2" a faz tão alta quanto duas linhas. As posições que cobre são então deixadas de fora daquelas linhas, porque esse espaço já está ocupado:

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

"Região" preenche duas linhas de cabeçalho, "2024" preenche duas colunas, e Q1 e Q2 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, então um cabeçalho fica visível em uma quebra de página, e eles permitem que você mantenha um cabeçalho ou rodapé fixo enquanto <tbody> rola. Uma tabela pode conter vários grupos <tbody>, 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 espaçamento de células (uma célula cobrir mais de uma coluna ou linha), e é aqui que as tabelas mais frequentemente quebram silenciosamente. Cada linha ainda deve contar para a largura completa da grade. Uma célula com colspan="2" preenche duas colunas, então as linhas que ela sobrepõe devem deixar essas posições vazias em vez de fornecer sua própria célula. Conte errado, e o navegador ainda renderizará algo, mas não a grade que você pretendia. <caption> é o nome acessível para a tabela: software assistivo (ferramentas como leitores de tela que leem a página em voz alta) o anuncia quando o leitor alcança a tabela, fazendo o trabalho que um cabeçalho próximo não pode.

html
<table>
  <caption>Receita trimestral por região</caption>
  <thead>
    <tr>
      <th>Região</th>
      <th>Q1</th>
      <th>Q2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>Norte</th>
      <td>£12.000</td>
      <td>£15.400</td>
    </tr>
    <tr>
      <th>Sul</th>
      <td>£9.800</td>
      <td>£11.200</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <th>Total</th>
      <td>£21.800</td>
      <td>£26.600</td>
    </tr>
  </tfoot>
</table>
JunoEstruturando uma tabela As linhas são lidas de cima para baixo, então comece com sua linha de cabeçalho de células <th>. Depois mantenha cada linha com o mesmo comprimento: três cabeçalhos no topo significa três células <td> em cada linha abaixo. Uma célula faltante é um espaço na grade, e é isso que confunde as pessoas no início.
JunoEstruturando uma tabela Agrupe as partes uma vez que uma tabela cresce: <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 entre colunas ou linhas, mas lembre-se de que as posições cobertas saem daquelas linhas. Acerte as contagens e a grade se mantém.
JunoEstruturando uma tabela Os grupos têm peso real: <thead> e <tfoot> se repetem quando a tabela é impressa e podem ancorar um corpo em rolagem, e <caption> é o nome que um leitor de tela lê. O espaçamento é a armadilha silenciosa, já que cada linha ainda tem que preencher a largura completa da grade, então uma posição coberta não recebe célula. O navegador renderiza uma contagem incorreta com felicidade, que é exatamente por que é difícil de detectar.

Tabelas acessíveis

Uma tabela acessível é aquela que faz sentido para todos, incluindo pessoas que ouvem a página com um leitor de tela (software que lê a página em voz alta) em vez de vê-la. A coisa mais útil que você pode fazer já está em seu kit de ferramentas: use <th> para cada célula de cabeçalho, não <td>. Um leitor de tela pode então dizer ao seu ouvinte quais células são rótulos e quais são dados, então um valor como "£15" é anunciado junto com a coluna à qual pertence. Uma tabela onde cada célula é um <td> simples lê como uma parede plana de números sem nada para ancorar.

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

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

Para uma grade simples o navegador frequentemente consegue adivinhar essas associações, mas afirmá-las com scope remove a adivinhação e é barato adicionar.

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

html
<th id="q1">Q1</th>
<th id="norte">Norte</th>
<td headers="norte q1">£12.000</td>

A célula de dados agora nomeia exatamente quais cabeçalhos a descrevem, na ordem em que devem ser lidos, e nenhum algoritmo precisa inferir a relação. É verboso, então use-o para as tabelas que realmente precisam. Recorra a scope primeiro e apenas escale para id e headers quando a estrutura de cabeçalho for muito irregular para scope expressar.

A acessibilidade se estende além de apenas tabelas; o capítulo Acessibilidade cobre o resto da imagem.

JunoTabelas acessíveis A maior vitória não custa nada extra: use <th> para cabeçalhos e <td> para dados. Um leitor de tela depende dessa divisão para ler cada valor com o cabeçalho ao qual pertence, então £15 chega com sua coluna em vez de sozinho. Pule isso e a tabela inteira pousa como uma parede de números soltos.
JunoTabelas acessíveis Coloque scope em 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 vincule cada célula de dados ao cabeçalho correto em ambos os eixos. O navegador consegue adivinhar para grades simples, mas afirmá-lo é barato e remove a adivinhação.
JunoTabelas acessíveisscope lida com a grade ordinária de um cabeçalho de cada forma. Quando cabeçalhos se estendem ou empilham e uma célula tem mais de um em um eixo, mude para id nos cabeçalhos e headers nas células de dados para conectá-los manualmente. É extenso, então mantenha-o para as tabelas que realmente precisam e deixe scope cuidar do resto.

Tabelas são para dados, não para layout

Houve uma época, antes do CSS conseguir lidar com layout, quando as pessoas construíam layouts de página inteira a partir de tabelas: uma <table> para colocar o menu à esquerda e o conteúdo à direita. Funciona visualmente, então você ainda vê em páginas antigas e alguns modelos de email. Não copie. Uma tabela é para dados tabulares, informações que pertencem a uma grade de linhas e colunas. Organizar as peças de uma página é o trabalho do CSS. Usar uma tabela para posicionar coisas em vez de manter dados torna a página mais difícil de ler para qualquer pessoa usando um leitor de tela, e mais difícil de ajustar depois.

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

Recorrer a uma tabela para obter colunas é o uso clássico errado. Se o conteúdo é uma barra de navegação ou um formulário espalhado pela página, não é dados tabulares, e uma tabela é a ferramenta errada mesmo que possa parecer correta.

Quando você usa uma tabela para layout, você entrega ao software assistivo (ferramentas como leitores de tela que falam a página) uma estrutura de dados que não é dados. Um leitor de tela anuncia uma tabela por suas dimensões e permite que o usuário se mova célula por célula, tratando a estrutura de layout como se cada região fosse um valor relacionado em uma grade. O resultado são anúncios como "tabela, quatro colunas, dez linhas" para o que é realmente um cabeçalho, uma barra lateral e um artigo.

Há também um problema de ordem de leitura. Software assistivo e mecanismos de busca leem a página em ordem de origem, a ordem em que os elementos aparecem em seu HTML, não a ordem em que acabam na tela. Uma tabela de layout força sua ordem de origem a corresponder à grade visual, então o conteúdo que deveria vir primeiro para um ouvinte, o artigo principal, pode acabar depois de uma coluna de navegação porque é aí que a coluna visual precisava dele. Layout CSS quebra esse acoplamento: você pode manter o conteúdo importante no início da origem e ainda colocá-lo em qualquer lugar na tela. Mantenha tabelas para dados, e a ordem de leitura permanece sob seu controle.

A única área cinzenta é email HTML, onde clientes de email mais antigos ainda carecem de layout CSS confiável e a estrutura baseada em tabelas permanece comum. Essa é uma restrição desse meio, não um padrão para trazer de volta à web.

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

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

Essa é a mesma separação de estrutura e apresentação estabelecida em O que é HTML: estrutura em HTML, layout em CSS. Para escolher elementos por seu significado, veja HTML Semântico.

JunoTabelas são para dados, não para layout Uma tabela é para dados que pertencem a uma grade, linhas e colunas de valores relacionados. Não é para organizar uma página, mesmo que sites antigos tenham feito dessa forma. Posicionar as partes de uma página é trabalho do CSS, e dobrar isso em uma tabela torna a página mais difícil de ler em voz alta e mais difícil de mudar.
JunoTabelas são para dados, não para layout Use <table> apenas quando o conteúdo realmente for uma grade de dados: um cronograma, uma comparação, uma lista de resultados. Para dispor uma página ou alinhar não-dados, recorra a CSS grid ou flexbox, que se adaptam à tela e mantêm seu HTML sobre conteúdo. Uma tabela forçada em duty de layout é a ferramenta clássica errada.
JunoTabelas são para dados, não para layout Uma tabela de layout engana um leitor de tela: ele ouve uma grade de dados e lê linhas e colunas que não significam nada. Também fixa sua ordem de origem à grade visual, quando a ordem de origem é o que a tecnologia assistiva e os mecanismos de busca realmente leem. Mantenha tabelas para dados, deixe CSS colocar coisas, e a ordem de leitura permanece sob seu controle. Email HTML é a única exceção, e apenas porque seus clientes estão presos no passado.