HTML e estrutura semântica
Estrutura do documento, conteúdo semântico, tabelas, formulários e dados enviados ao servidor.
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 < para mostrar < e & 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.
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":
| Livro | Local | N.º |
|---|---|---|
Redes | Biblioteca | 3 |
| Laboratório | 2 |
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:
CSS e JavaScript
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:
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.
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.
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.
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.

