HTML e estrutura semântica

Estrutura do documento, conteúdo semântico, tabelas, formulários e dados enviados ao servidor.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

A ficha de um livro contém um título, uma descrição e um botão de reserva. O HTML identifica a função de cada parte. Um h2 marca o título; um p contém a descrição; um button permite iniciar a ação. O tamanho da letra e a disposição pertencem ao CSS.

O navegador transforma o HTML numa árvore de nós chamada DOM. É essa estrutura em memória que o JavaScript lê e altera, não o ficheiro HTML original.

Cliente e servidor

Ao abrir uma página dinâmica, o navegador envia um pedido HTTP. O servidor executa o PHP, consulta os dados e responde com HTML. O navegador interpreta esse HTML e pode fazer novos pedidos para CSS, imagens e JavaScript.

Internet é a rede que transporta dados; a Web é um dos serviços que a usam. O DNS traduz um nome como biblioteca.example num endereço IP, e o navegador liga-se a esse servidor. Em HTTPS, as partes estabelecem primeiro uma ligação protegida por TLS e só depois trocam as mensagens HTTP.

Nem todo o pedido precisa de uma base de dados. Servir uma imagem ou um ficheiro CSS é uma resposta direta do servidor.

O código PHP não chega ao navegador, por isso abrir pagina.php como ficheiro local não substitui um servidor.

Documento, elementos e atributos

Este é um documento completo:

<!doctype html>
<html lang="pt-PT">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Catálogo da biblioteca</title>
    <link rel="stylesheet" href="estilo.css" />
    <script src="catalogo.js" defer></script>
  </head>
  <body>
    <header><h1>Biblioteca</h1></header>
    <nav aria-label="Principal"><a href="/livros/">Livros</a></nav>
    <main>
      <article>
        <h2>Redes de computadores</h2>
        <p>Disponível para reserva.</p>
      </article>
    </main>
  </body>
</html>

O doctype pede o modo de renderização normal. lang declara a língua do documento. O head contém metadados, incluindo o título do separador; o body contém o conteúdo visível.

O atributo defer permite descarregar o script enquanto o HTML é lido e executá-lo depois de o documento estar analisado. Não torna cada linha do programa assíncrona; apenas adia o arranque.

Um elemento habitual tem etiqueta de abertura, conteúdo e etiqueta de fecho. Os elementos vazios, como img, input e meta, não têm conteúdo nem etiqueta de fecho. Os atributos acrescentam informação à abertura. id identifica um elemento e deve ser único no documento; class pode listar várias classes e repetir-se em vários elementos.

<p id="aviso" class="mensagem urgente">Só resta um exemplar.</p>

aviso é o identificador; mensagem e urgente são duas classes. Um atributo booleano, como disabled, vale pela presença. Escrever disabled="false" continua a desativar o controlo.

Escolher a etiqueta

main identifica o conteúdo principal e nav agrupa a navegação. article representa conteúdo que pode ser lido por si, como uma notícia; section agrupa uma secção temática, normalmente com título. header e footer podem pertencer à página ou a um artigo. div e span agrupam conteúdo sem lhe acrescentar significado.

Usa a para navegar e button para agir. Dentro de um formulário, declara type="button" num botão que não deve submeter. Para listas, escolhe ul quando a ordem não importa, ol para passos ordenados e dl para pares de termos e descrições. Os níveis de título seguem a hierarquia do conteúdo, não o tamanho da letra pretendido; o aspeto ajusta-se com CSS.

strong indica importância e em dá ênfase. code marca código e pre preserva espaços e mudanças de linha. No texto normal, o navegador colapsa sequências de espaços. Escreve &lt; para mostrar < e &amp; para mostrar & quando precisam de ser texto.

Uma imagem informativa precisa de alt que comunique a informação relevante; uma decorativa tem alt="". figure pode reunir imagem e figcaption. Para áudio e vídeo, controls oferece controlos nativos, e legendas com transcrições dão acesso à informação sem depender do som. SVG descreve formas como marcação; canvas oferece uma área onde um programa desenha píxeis.

O vídeo compara estrutura e apresentação. Depois de o veres, identifica os elementos da ficha que continuam a fazer sentido sem CSS.

Abrir no YouTube

Ligações e caminhos

Em https://biblioteca.example/livros/?q=redes#resultados, o fragmento resultados aponta para um id da página. O fragmento não é enviado no pedido HTTP. href="/livros/" começa na raiz do sítio; href="capa.png" resolve relativamente ao endereço do documento; ../ sobe um nível do caminho.

Para prever um caminho relativo, substitui o último segmento da base, não o domínio inteiro. A partir de https://biblioteca.example/catalogo/item.html, ../ajuda.html resolve para https://biblioteca.example/ajuda.html.

Tabelas

Uma tabela representa dados em linhas e colunas. A legenda explica o conjunto, e os cabeçalhos identificam o significado das células:

<table>
  <caption>
    Exemplares disponíveis
  </caption>
  <thead>
    <tr>
      <th scope="col">Livro</th>
      <th scope="col">Exemplares</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Redes</th>
      <td>3</td>
    </tr>
    <tr>
      <th scope="row">SQL</th>
      <td>1</td>
    </tr>
  </tbody>
</table>

rowspan ocupa várias linhas e colspan ocupa várias colunas. Se dividirmos os exemplares de Redes por local, a primeira célula pode ter rowspan="2":

Exemplares por local
LivroLocalN.º

Redes

Biblioteca3
Laboratório2

Na segunda linha escrevemos apenas <td>Laboratório</td><td>2</td>. Repetir Redes deslocaria essas células para as colunas seguintes. Uma célula com colspan="2" ocupa duas posições na própria linha. Marca as posições ocupadas antes de acrescentar células. Para dispor o menu e o conteúdo da página, usa CSS.

Formulários e dados enviados

Um formulário define o destino em action e o método em method. Com GET, os parâmetros aparecem na query string, apropriada para uma pesquisa. Com POST, a codificação habitual coloca-os no corpo do pedido. POST não cifra os dados; HTTPS é que protege o transporte.

Neste exemplo, o JavaScript interceta a submissão e mostra a codificação dos campos, sem fazer um pedido:

HTML / CSS / JavaScript
Código a editar
HTML
CSS e JavaScript
CSS
JavaScript
Pré-visualização

A preparar a pré-visualização…

Consola
Sem mensagens.

O formulário começa com Ana e quantidade 2, cuja codificação é nome=Ana&quantidade=2. Marca a caixa de aviso e carrega em Ver os dados: acrescenta &aviso=sim. Cada controlo com name que participa no envio contribui com um par.

O id liga o campo à sua label; o name dá o nome do parâmetro. Se trocares o id sem atualizar o for, a etiqueta deixa de ativar o campo. Se apagares o name, o valor deixa de viajar no pedido.

A submissão inclui os controlos com nome que participam no envio. Uma checkbox não marcada não envia qualquer valor; se a marcada não tiver value, envia normalmente on. Num grupo de radio buttons com o mesmo name, só a opção selecionada envia. Um campo disabled não envia, mas um campo readonly continua a enviar quando o tipo admite esse atributo. O botão de submissão acionado pode também enviar o seu par nome/valor.

select envia o valor da opção selecionada. Um select multiple pode enviar vários valores com o mesmo nome. textarea escreve o valor inicial entre as etiquetas. fieldset e legend dão nome a um grupo de controlos. Um datalist ligado a um input por list sugere valores, mas permite escrever outro; um select limita a escolha às suas opções.

type="password" oculta o desenho dos caracteres, não os cifra. type="hidden" esconde o controlo na página, mas o cliente pode alterar o valor. Um upload exige method="post" e enctype="multipart/form-data"; o servidor tem de validar o ficheiro recebido.

Validação e limites

required, min, max, minlength, maxlength, tipos como email e pattern ajudam o utilizador antes do envio. placeholder é uma sugestão que desaparece ao escrever, não substitui uma label. type="tel" pode escolher um teclado útil, mas não impõe sozinho um formato de número.

Se o DOM não corresponde ao que escreveste, verifica aninhamento e elementos permitidos. Em <p>Texto<div>Bloco</div></p>, o navegador fecha o parágrafo antes do div. O inspetor mostra a árvore real, e o validador identifica erros estruturais.

Para uma revisão mais longa de programação web, podes acompanhar Rodrigo Dias como complemento ao percurso da cadeira:

Abrir no YouTube

Exercícios

Prever os parâmetros

O utilizador escreve Ana, não marca a checkbox e prime o botão. Escreve os pares enviados e explica cada exclusão.

<form method="post">
  <input id="nome" name="pessoa" value="Ana" />
  <input name="codigo" value="R7" disabled />
  <input name="sala" value="B2" readonly />
  <input type="checkbox" name="aviso" value="sim" />
  <input value="oculto-sem-nome" type="hidden" />
  <button name="acao" value="reservar">Reservar</button>
</form>

Pista

Começa pelos controlos com name. Depois verifica disabled e seleção.

Mais uma pista

O botão acionado também tem name/value; readonly não é disabled.

Solução

Percorre os controlos por ordem. pessoa=Ana viaja porque tem nome e está ativo. codigo tem nome mas está disabled, por isso fica de fora. sala=B2 viaja porque readonly não exclui o envio. A checkbox aviso não está marcada, por isso não produz par. O campo oculto não tem name, por isso o seu valor nunca viaja. O botão acionado contribui com acao=reservar. Resultado: pessoa=Ana, sala=B2 e acao=reservar. O id serve a etiqueta, não o pedido.

Confere a tua resposta:

  • Identifiquei os três pares enviados.
  • Justifiquei disabled, checkbox e ausência de name.

Erros frequentes

Não enviar a checkbox como false, não excluir readonly e não trocar id por name.

Voltar à explicação
Corrigir uma página

Uma página usa <div onclick="abrir()">Ajuda</div> para navegar para ajuda.html e <p>Escolhe<div>Livro</div></p> para um bloco. Corrige os dois fragmentos e explica o efeito para teclado e DOM.

Pista

Pergunta se a primeira interação navega ou executa uma ação local.

Mais uma pista

Uma ligação usa href. Um div não pode permanecer dentro de um p nessa posição.

Solução

Usa <a href="ajuda.html">Ajuda</a>. O navegador dá à ligação foco e ativação por teclado. Para o segundo, usa <div><p>Escolhe</p><div>Livro</div></div>, se o bloco separado for mesmo necessário. O HTML original fecha implicitamente o parágrafo antes do div, alterando a árvore.

Confere a tua resposta:

  • Usei ligação com href para navegar.
  • Corrigi o aninhamento e expliquei a árvore real.

Erros frequentes

Adicionar apenas tabindex ao div não lhe dá toda a semântica de uma ligação.

Voltar à explicação
Resolver um endereço

A página está em https://catalogo.example/ano/lista.html. Resolve ../livros/item.html?id=8#reserva. Qual o caminho e a query enviados ao servidor?

Pista

Resolve o endereço relativamente à pasta /ano/.

Solução

O URL é https://catalogo.example/livros/item.html?id=8#reserva. O alvo HTTP é /livros/item.html?id=8. A parte #reserva não é enviada, mesmo que o servidor produza a página.

Confere a tua resposta:

  • Resolvi o URL para /livros/item.html.
  • Separei query de fragmento.

Erros frequentes

Não anexar ../ ao nome completo lista.html nem enviar o fragmento na query.

Voltar à explicação
Completar uma célula que atravessa linhas

Completa a segunda linha com as células necessárias. As colunas são livro, local e exemplares. Explica por que não repetes a célula Redes.

<table>
  <caption>
    Exemplares por local
  </caption>
  <thead>
    <tr>
      <th scope="col">Livro</th>
      <th scope="col">Local</th>
      <th scope="col">Exemplares</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th rowspan="2" scope="rowgroup">Redes</th>
      <td>Biblioteca</td>
      <td>3</td>
    </tr>
    <tr>
      <!-- Laboratório, 2 exemplares -->
    </tr>
  </tbody>
</table>

Pista

Marca as posições que a linha anterior já ocupa.

Mais uma pista

rowspan=“2” ocupa a coluna Livro em duas linhas.

Solução

A última linha é <tr><td>Laboratório</td><td>2</td></tr>. Conta as posições. A primeira linha preenche as colunas 1, 2 e 3, com Redes a declarar ocupação de duas linhas na coluna 1. Na segunda linha a coluna 1 já pertence a Redes, por isso restam duas células: Laboratório e 2. Repetir Redes criaria quatro colunas lógicas. colspan juntaria colunas na mesma linha, o que não é o caso.

Confere a tua resposta:

  • Acrescentei apenas duas células na última linha.
  • Expliquei a coluna ocupada pelo rowspan.

Erros frequentes

Não repetir Redes nem usar colspan para atravessar linhas.

Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.