Aprenda padrões modernos para tabelas e listas. Torne dados fáceis de ler, comparar e acionar. Veja HTML, CSS e JS prontos para copiar.Nesse artigo você verá:
- Fundamentos de legibilidade
- Tabelas modernas e responsivas
- Listas visuais e semânticas
- Tabelas de comparação
- Tabela de preços simples
- Acessibilidade e boas práticas
- Exemplos em código
- Erros comuns
- FAQ
Fundamentos de legibilidade
- Hierarquia clara: títulos, subtítulos e rótulos consistentes.
- Contraste: linhas zebradas e cabeçalho fixo.
- Respiro: célula com padding adequado.
- Ação: ícones e botões discretos ao passar o mouse.
Tabelas modernas e responsivas
Use HTML semântico. Aplique estilos com foco em leitura e toque.
<div class="table-wrap" role="region" aria-labelledby="tabela-produtos" tabindex="0">
<table class="table" aria-describedby="tabela-produtos-desc">
<caption id="tabela-produtos">Produtos e estoque</caption>
<p id="tabela-produtos-desc" class="sr-only">Tabela com ordenação e cabeçalho fixo.</p>
<thead>
<tr>
<th scope="col" data-sort="text">Produto</th>
<th scope="col" data-sort="number">Preço (R$)</th>
<th scope="col" data-sort="number">Estoque</th>
<th scope="col">Ação</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Hospedagem 1GB</th>
<td>49,99</td>
<td>25</td>
<td><button class="btn-xs">Detalhes</button></td>
</tr>
<tr>
<th scope="row">Hospedagem 1GB Semestral</th>
<td>249,99</td>
<td>12</td>
<td><button class="btn-xs">Detalhes</button></td>
</tr>
<tr>
<th scope="row">Hospedagem 1GB Anual</th>
<td>399,99</td>
<td>8</td>
<td><button class="btn-xs">Detalhes</button></td>
</tr>
</tbody>
</table>
</div>
:root{
--bg:#ffffff; --fg:#0f172a; --muted:#6b7280; --brand:#2563eb;
--row:#f8fafc; --row2:#ffffff; --border:#e5e7eb; --radius:12px;
}
.table-wrap{ overflow:auto; max-height:480px; border:1px solid var(--border); border-radius:var(--radius); }
.table{ width:100%; border-collapse:separate; border-spacing:0; min-width:640px; color:var(--fg); }
.table caption{ text-align:left; font-weight:700; padding:12px 14px; }
.table thead th{
position:sticky; top:0; background:#eef2ff; z-index:1; text-align:left; padding:12px 14px; font-size:.95rem;
border-bottom:1px solid var(--border); cursor:pointer;
}
.table tbody th, .table td{ padding:12px 14px; border-bottom:1px solid var(--border); vertical-align:middle; }
.table tbody tr:nth-child(odd){ background:var(--row); }
.table tbody tr:nth-child(even){ background:var(--row2); }
.table tbody tr:hover{ outline:2px solid #dbeafe; outline-offset:-2px; }
.btn-xs{ padding:6px 10px; border:0; border-radius:8px; background:var(--brand); color:#fff; font-weight:700; cursor:pointer; }
.btn-xs:hover{ filter:brightness(.95); }
/* Tabela empilhada no mobile */
@media (max-width:680px){
.table{ min-width:0; }
.table thead{ display:none; }
.table tbody tr{ display:grid; grid-template-columns: 1fr 1fr; gap:8px; padding:12px 10px; }
.table tbody th{ grid-column:1 / -1; padding-bottom:0; }
.table tbody td::before{
content: attr(data-label); font-weight:700; color:var(--muted); margin-right:6px;
}
}
Dica: adicione data-label nos <td> para rótulos no modo empilhado.
Listas visuais e semânticas
Use listas para benefícios, passos e status. Mantenha iconografia simples.
<ul class="list list--checks">
<li>Carregamento rápido</li>
<li>Certificado SSL grátis</li>
<li>Suporte técnico ativo</li>
</ul>
<ol class="list list--steps">
<li>Escolha o plano</li>
<li>Aponte o domínio</li>
<li>Publique o site</li>
</ol>
<dl class="list list--dl">
<div><dt>TTFB</dt><dd>Tempo até o primeiro byte</dd></div>
<div><dt>CDN</dt><dd>Entrega de conteúdo global</dd></div>
</dl>
.list{ margin:0; padding:0; list-style:none; }
.list--checks li{ position:relative; padding-left:28px; margin:8px 0; }
.list--checks li::before{ content:"✓"; position:absolute; left:0; top:0; font-weight:700; color:var(--brand); }
.list--steps{ counter-reset: step; }
.list--steps li{ counter-increment: step; margin:10px 0; padding-left:34px; position:relative; }
.list--steps li::before{
content: counter(step); position:absolute; left:0; top:0; width:24px; height:24px; border-radius:8px;
display:grid; place-items:center; background:#eef2ff; color:#1e3a8a; font-weight:700;
}
.list--dl div{ display:grid; grid-template-columns:140px 1fr; gap:8px; padding:8px 0; border-bottom:1px dashed var(--border); }
.list--dl dt{ font-weight:700; }
Tabelas de comparação
Destaque diferenças. Use checkmarks e cores neutras.
<table class="table compare" aria-label="Comparação de planos">
<thead>
<tr>
<th scope="col">Recursos</th>
<th scope="col">Mensal</th>
<th scope="col">Semestral</th>
<th scope="col">Anual</th>
</tr>
</thead>
<tbody>
<tr><th scope="row">SSL</th><td data-icon="✔"></td><td data-icon="✔"></td><td data-icon="✔"></td></tr>
<tr><th scope="row">Antivírus</th><td data-icon="—"></td><td data-icon="✔"></td><td data-icon="✔"></td></tr>
<tr><th scope="row">Varnish</th><td data-icon="—"></td><td data-icon="—"></td><td data-icon="✔"></td></tr>
</tbody>
</table>
.compare td{ text-align:center; font-weight:700; }
.compare td::before{ content: attr(data-icon); color:#16a34a; }
.compare td[data-icon="—"]::before{ color:#9ca3af; }
Tabela de preços simples
Use cartão em grid. Mostre valor e benefício em destaque.
<section class="pricing">
<article class="price-card">
<h3>Mensal</h3>
<p class="price">R$ 49,99</p>
<ul class="list list--checks">
<li>1 site</li><li>SSL grátis</li><li>Varnish</li>
</ul>
<button class="btn-lg">Contratar</button>
</article>
<article class="price-card featured" aria-label="Mais vantajoso">
<h3>Anual</h3>
<p class="price">R$ 399,99</p>
<ul class="list list--checks">
<li>1 site</li><li>SSL e Antivírus</li><li>Suporte ativo</li>
</ul>
<button class="btn-lg">Contratar</button>
</article>
</section>
.pricing{ display:grid; grid-template-columns: repeat(auto-fit, minmax(220px,1fr)); gap:18px; }
.price-card{
background:#fff; border-radius:14px; padding:18px; box-shadow:0 10px 20px rgba(0,0,0,.06);
}
.price-card .price{ font-size:1.6rem; font-weight:800; margin:8px 0 12px; }
.price-card.featured{ outline:3px solid #dbeafe; }
.btn-lg{ padding:12px 16px; border-radius:12px; border:0; font-weight:700; background:var(--brand); color:#fff; cursor:pointer; }
.btn-lg:hover{ filter:brightness(.95); }
Acessibilidade e boas práticas
- Usar <th scope>: associa rótulos a células.
- Caption e descrição: explique objetivo e estrutura.
- Foco visível: destaque navegação por teclado.
- Resumo por célula no mobile: use
data-labelem <td>.
Exemplos em código
Ordenação simples por coluna (JS)
document.querySelectorAll('.table thead th[data-sort]').forEach((th,i)=>{
th.addEventListener('click', ()=>{
const table = th.closest('table');
const tbody = table.querySelector('tbody');
const dir = th.dataset.dir = th.dataset.dir === 'asc' ? 'desc' : 'asc';
const type = th.dataset.sort;
const rows = Array.from(tbody.querySelectorAll('tr'));
const parse = (v) => type === 'number' ? parseFloat(v.replace('.','').replace(',','.')) : v.toLowerCase();
rows.sort((a,b)=>{
const A = parse(a.children[i].textContent.trim());
const B = parse(b.children[i].textContent.trim());
return dir === 'asc' ? (A>B?1:-1) : (A<B?1:-1);
});
rows.forEach(r=>tbody.appendChild(r));
});
});
Tooltip para termos de lista
<li class="has-tip">Varnish <span role="tooltip">Cache reverso para acelerar entregas.</span></li>
.has-tip{ position:relative; border-bottom:1px dashed #cbd5e1; }
.has-tip span[role="tooltip"]{
position:absolute; inset:auto auto 100% 0; transform:translateY(-6px);
background:#0f172a; color:#fff; padding:6px 8px; border-radius:8px; font-size:.85rem; opacity:0; pointer-events:none;
}
.has-tip:hover span[role="tooltip"]{ opacity:1; }
Erros comuns
- Cabeçalho sem <th> e sem escopo.
- Tabela sem legenda. Falta contexto.
- Células apertadas. Leitura difícil.
- Quebra no mobile sem rótulos.
- Ordenação que altera a semântica sem aviso.
Perguntas Frequentes (FAQ)
Quando usar tabela e não lista?
Quando há dados por linhas e colunas. Quando a comparação é tabular. Como tornar a tabela responsiva?
Use contêiner com rolagem ou empilhamento. Aplique data-label nos <td>. Posso usar ícones em células?
Sim. Mantenha texto alternativo ou rótulo oculto. Sticky header prejudica acessibilidade?
Não, se bem implementado. Preserve contraste e ordem lógica. Vale a pena permitir ordenação?
Sim. Ajuda exploração. Informe estado asc/desc por ARIA quando possível.Tags:
- Tabelas
- Listas
- UI
- UX
- Acessibilidade
- Responsividade
- Sticky Header
- Data Table
- Comparação
- Listas de Passos
- Definition List
- Design de Dados
- Semântica HTML
- Web Design
- Performance
“É necessário construir frases curtas. Toda otimização dividirá em, no mínimo, duas frases.”









