Skip to content

HTML Folha de referência

A linguagem de marcação padrão para criar páginas web.

01

Estrutura de Documento

Template Básico de Página

Todo documento HTML5 começa com <!DOCTYPE html>, seguido por <html> com um atributo lang para acessibilidade e SEO. O <head> contém metadados (charset, viewport, title), e <body> contém conteúdo visível. A meta tag viewport garante renderização adequada em dispositivos móveis.

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Web Page</title>
</head>
<body>
  <h1>Hello, World!</h1>
  <p>Welcome to my page.</p>
</body>
</html>

Seção Head & Metadados

O elemento <head> contém metadados legíveis por máquina. charset declara codificação de caracteres (UTF-8 cobre quase todos os caracteres). A meta tag description é crucial para SEO — motores de busca a exibem nos resultados. Use defer em scripts para carregá-los após o parsing do HTML.

html
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Page Title - Site Name</title>
  <meta name="description" content="A brief description for SEO">
  <meta name="author" content="John Doe">
  <link rel="stylesheet" href="style.css">
  <script src="app.js" defer></script>
</head>

Comentários & Comentários Condicionais

Comentários HTML começam com <!-- e terminam com -->. Eles não são exibidos no navegador mas são visíveis no código-fonte da página. Comentários são úteis para deixar notas, marcar seções (TODO, FIXME) e documentação. Comentários condicionais (apenas IE) estão obsoletos mas podem aparecer em código legado.

html
<!-- This is a single-line comment -->

<!--
  This is a
  multi-line comment
-->

<!-- TODO: Add form validation -->
<!-- FIXME: Fix layout on mobile -->

<!--[if lt IE 9]>
  <script src="html5shiv.js"></script>
<![endif]-->

Hierarquia de Headings

HTML fornece seis níveis de heading, h1 (mais alto) a h6 (mais baixo). Use-os em ordem hierárquica sem pular níveis. Motores de busca usam headings para entender a estrutura da página. Melhor prática: um h1 por página, seguido por h2 para seções principais, h3 para subseções, etc.

html
<h1>Main Page Title</h1>
<h2>Major Section</h2>
<h3>Subsection</h3>
<h4>Sub-subsection</h4>
<h5>Minor Heading</h5>
<h6>Lowest Level Heading</h6>

<!-- Use only one h1 per page for SEO -->
<h1>Blog Post Title</h1>
<h2>Introduction</h2>
<h3>Background</h3>

Contêineres Div & Span

<div> é um contêiner block-level usado para agrupar elementos e aplicar estilos. <span> é um contêiner inline para estilizar pequenas porções de texto. Ambos são elementos genéricos sem significado semântico — prefira tags semânticas (header, nav, main, article) quando apropriado para melhor acessibilidade e SEO.

html
<div class="container">
  <div id="header" class="header">
    <span class="logo">MySite</span>
    <span class="tagline">Best Content</span>
  </div>
  <div class="content">
    <p>Main <span class="highlight">content</span> here.</p>
  </div>
</div>
02

Formatação de Texto

Bold, Italic & Emphasis

<strong> indica texto importante (screen readers o enfatizam), enquanto <b> é puramente bold visual. Similarmente, <em> indica ênfase de estresse (semântico), enquanto <i> é itálico visual. Prefira <strong> e <em> para acessibilidade. <b> e <i> são aceitáveis para propósitos estilísticos sem importância semântica.

html
<p>This is <strong>important</strong> text.</p>
<p>This is <b>bold</b> text.</p>
<p>This is <em>emphasized</em> text.</p>
<p>This is <i>italic</i> text.</p>
<p><strong>Warning:</strong> Do not touch!</p>

Mark, Delete & Insert

<mark> destaca texto como relevante (como um highlight de busca). <del> marca texto excluído, <ins> marca texto inserido — útil para mostrar edições. <s> risca informações desatualizadas. <small> é para comentários laterais ou copyright. <u> deve ser usado com cuidado pois se parece com links.

html
<p>Please <mark>highlight this</mark> word.</p>
<p>The price is <del>$99</del> <ins>$79</ins> now.</p>
<p><s>Old information</s> is struck through.</p>
<p>Use <u>underline</u> sparingly.</p>
<p>Small <small>print</small> for side comments.</p>

Superscript & Subscript

<sub> cria texto subscript (abaixo da baseline) para fórmulas químicas (H2O) e variáveis matemáticas. <sup> cria texto superscript (acima da baseline) para expoentes (x²), números ordinais (1st) e notas de rodapé. Ambos são elementos inline que ajustam posição vertical e tamanho da fonte.

html
<p>H<sub>2</sub>O is water.</p>
<p>E = mc<sup>2</sup> is Einstein's equation.</p>
<p>1st<sup>st</sup> January 2024</p>
<p>CO<sub>2</sub> emissions are rising.</p>
<p>x<sup>2</sup> + y<sup>2</sup> = r<sup>2</sup></p>

Citações & References

<blockquote> é para citações block-level (indentadas, multi-linha). <q> é para citações inline curtas (adiciona aspas automaticamente). O atributo cite fornece a URL de origem. <cite> marca o título de uma obra ou nome do autor. Esses elementos melhoram a marcação semântica para conteúdo citado.

html
<blockquote cite="https://example.com/source">
  <p>The best way to predict the future is to invent it.</p>
  <footer>— <cite>Alan Kay</cite></footer>
</blockquote>

<p>As <q cite="https://example.com">someone once said</q>,
knowledge is power.</p>

Código & Texto Pré-formatado

<code> marca snippets de código inline (fonte monospace). <pre> preserva whitespace e quebras de linha para texto pré-formatado. Combinar <pre><code> exibe blocos de código com indentação adequada. <kbd> representa entrada de teclado. <samp> é para saída de programa, e <var> para variáveis em expressões matemáticas.

html
<p>Use the <code>console.log()</code> function.</p>
<p>Press <kbd>Ctrl</kbd> + <kbd>C</kbd> to copy.</p>

<pre><code>function hello() {
  console.log("Hello, World!");
  return true;
}</code></pre>

Quebras de Linha & Régua Horizontal

<br> cria uma quebra de linha dentro do texto (use com moderação, prefira CSS). <hr> cria uma régua horizontal representando uma quebra temática entre seções. <wbr> sugere uma oportunidade de quebra de linha para palavras longas ou URLs, permitindo que o navegador quebre em pontos ótimos. Evite usar <br> para espaçamento — use margens CSS em vez disso.

html
<p>First line<br>Second line<br>Third line</p>

<p>Paragraph one.</p>
<hr>
<p>Paragraph two after a thematic break.</p>

<wbr><!-- word break opportunity for long URLs -->
https://example.com/<wbr>very<wbr>long<wbr>url
04

Imagens & Multimídia

Imagens

Sempre inclua texto alt para acessibilidade e SEO — ele descreve a imagem para screen readers e quando a imagem falha ao carregar. loading='lazy' adia o carregamento de imagens offscreen, melhorando a velocidade da página. srcset e sizes habilitam imagens responsivas — o navegador seleciona a melhor imagem com base na resolução do dispositivo e viewport. Sempre especifique width e height para prevenir layout shift.

html
<!-- Basic image -->
<img src="photo.jpg" alt="A sunset over mountains" width="800" height="600">

<!-- Image with lazy loading -->
<img src="hero.jpg" alt="Hero banner" loading="lazy" decoding="async">

<!-- Responsive image with srcset -->
<img
  src="medium.jpg"
  srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
  sizes="(max-width: 600px) 480px, 800px"
  alt="Responsive photo"
>

Elemento Picture

<picture> fornece art direction e fallback de formato. Elementos <source> oferecem alternativas — o navegador pega o primeiro formato suportado (WebP/AVIF são menores). O atributo media habilita imagens diferentes para diferentes tamanhos de tela. O <img> final é o fallback e deve sempre estar presente. Isso é superior a srcset para servir imagens inteiramente diferentes.

html
<picture>
  <source srcset="webp-image.webp" type="image/webp">
  <source srcset="avif-image.avif" type="image/avif">
  <source srcset="wide.jpg" media="(min-width: 800px)">
  <img src="fallback.jpg" alt="Art-directed image">
</picture>

Áudio

<audio> embute conteúdo de som. controls adiciona controles play/pause/volume. Múltiplos elementos <source> fornecem fallbacks de formato (MP3 é o mais amplamente suportado). autoplay é restrito por navegadores — muted autoplay é geralmente permitido. loop repete o áudio. O texto dentro é exibido se áudio não for suportado. Sempre forneça controls para experiência do usuário.

html
<audio controls>
  <source src="song.mp3" type="audio/mpeg">
  <source src="song.ogg" type="audio/ogg">
  Your browser does not support the audio element.
</audio>

<!-- Autoplay (muted required in most browsers) -->
<audio autoplay muted loop>
  <source src="background.mp3" type="audio/mpeg">
</audio>

Vídeo

<video> embute vídeo com controles para play, pause, volume e fullscreen. poster define uma thumbnail antes da reprodução. Múltiplas sources fornecem fallback de formato (MP4/H.264 é o mais compatível). <track> adiciona legendas, captions ou descrições para acessibilidade. playsinline previne fullscreen forçado no iOS. Sempre inclua controls a menos que autoplayando muted.

html
<video controls width="640" height="360" poster="thumbnail.jpg">
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.webm" type="video/webm">
  <track kind="subtitles" src="subs.vtt" srclang="en" label="English">
  Your browser does not support video.
</video>

<!-- Autoplay muted loop (common for backgrounds) -->
<video autoplay muted loop playsinline>
  <source src="bg.mp4" type="video/mp4">
</video>

Figure & Figcaption

<figure> agrupa conteúdo self-contained como imagens, diagramas, listagens de código ou citações com sua legenda. <figcaption> fornece uma legenda ou título. Esse agrupamento semântico melhora acessibilidade — screen readers anunciam o relacionamento. Figures podem ser referenciados a partir do texto ('veja Figura 1') e movidos no layout sem perder contexto.

html
<figure>
  <img src="chart.png" alt="Quarterly sales chart showing 20% growth">
  <figcaption>Figure 1: Q4 2024 sales growth by region.</figcaption>
</figure>

<figure>
  <blockquote>
    <p>The best way to predict the future is to invent it.</p>
  </blockquote>
  <figcaption>— Alan Kay, 1971</figcaption>
</figure>

Embeds de Iframe

<iframe> embute conteúdo externo (vídeos, mapas, outras páginas). Sempre inclua um atributo title para acessibilidade. loading='lazy' melhora desempenho para iframes offscreen. O atributo allow especifica feature policies. O atributo sandbox restringe as capacidades do iframe para segurança. Tenha cautela — iframes podem impactar desempenho e segurança.

html
<!-- Embed a YouTube video -->
<iframe
  src="https://www.youtube.com/embed/dQw4w9WgXcQ"
  width="560" height="315"
  title="YouTube video"
  frameborder="0"
  allow="accelerometer; autoplay; encrypted-media"
  allowfullscreen>
</iframe>

<!-- Embed a map -->
<iframe
  src="https://maps.google.com/maps?q=Paris&output=embed"
  title="Map of Paris" loading="lazy">
</iframe>
05

Listas

Listas Não Ordenadas

<ul> cria uma lista não ordenada (com marcadores). Cada item é envolvido em <li>. A propriedade CSS list-style-type muda o estilo do marcador (disc, circle, square, none). Listas não ordenadas são para itens onde ordem não importa. Use list-style: none e estilização personalizada para menus de navegação e listas de recursos.

html
<ul>
  <li>Apple</li>
  <li>Banana</li>
  <li>Cherry</li>
</ul>

<!-- Custom bullet style via CSS -->
<ul style="list-style-type: square;">
  <li>First item</li>
  <li>Second item</li>
</ul>

Listas Ordenadas

<ol> cria uma lista ordenada (numerada) para itens sequenciais. O atributo start define o número inicial. reversed exibe itens em ordem descendente. O atributo type muda o estilo de numeração (1, A, a, I, i). Use <ol> para passos, rankings ou qualquer sequência onde ordem importa.

html
<ol>
  <li>First step</li>
  <li>Second step</li>
  <li>Third step</li>
</ol>

<!-- Start from a specific number -->
<ol start="5">
  <li>Fifth item</li>
  <li>Sixth item</li>
</ol>

<!-- Reverse order -->
<ol reversed>
  <li>Countdown 3</li>
  <li>Countdown 2</li>
  <li>Countdown 1</li>
</ol>

Listas de Descrição

<dl> cria uma lista de descrição emparelhando termos (<dt>) com descrições (<dd>). Isso é ideal para glossários, páginas de FAQ e pares termo-definição. Múltiplos <dd> podem descrever um <dt>, e vice-versa. Listas de descrição fornecem significado semântico que tabelas de definição não têm, melhorando acessibilidade.

html
<dl>
  <dt>HTML</dt>
  <dd>HyperText Markup Language</dd>

  <dt>CSS</dt>
  <dd>Cascading Style Sheets</dd>

  <dt>JavaScript</dt>
  <dd>A programming language for the web</dd>
</dl>

Listas Aninhadas

Listas podem ser aninhadas colocando um <ul> ou <ol> dentro de um <li>. Navegadores indentam automaticamente listas aninhadas e podem mudar estilos de marcador. Aninhamento cria estruturas hierárquicas como tabelas de conteúdo, árvores de arquivos ou menus multi-nível. Mantenha aninhamento razoável (2-3 níveis) para usabilidade. Listas profundamente aninhadas tornam-se difíceis de ler.

html
<ul>
  <li>Fruits
    <ul>
      <li>Apple</li>
      <li>Banana</li>
    </ul>
  </li>
  <li>Vegetables
    <ol>
      <li>Carrot</li>
      <li>Spinach</li>
    </ol>
  </li>
</ul>

Lista com Links (Navegação)

Listas de links dentro de <nav> criam menus de navegação semânticos. Elementos <ul> aninhados formam submenus dropdown. Essa estrutura é acessível a screen readers e facilmente estilizada com CSS. Use atributos aria (aria-expanded, aria-haspopup) para dropdowns interativos. Navegação baseada em lista é o padrão para menus acessíveis.

html
<nav>
  <ul class="menu">
    <li><a href="/">Home</a></li>
    <li><a href="/products">Products</a>
      <ul class="submenu">
        <li><a href="/products/a">Product A</a></li>
        <li><a href="/products/b">Product B</a></li>
      </ul>
    </li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>
06

Tabelas

Tabela Básica

<table> cria dados tabulares. <thead> agrupa linhas de header, <tbody> agrupa linhas de body, <tfoot> agrupa linhas de footer. <tr> é uma linha da tabela, <th> é uma célula de header (bold, centralizada), <td> é uma célula de dados. Usar thead/tbody/tfoot melhora acessibilidade e habilita melhor estilização. Tabelas devem ser usadas para dados, não layout.

html
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
      <th>City</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice</td>
      <td>30</td>
      <td>New York</td>
    </tr>
    <tr>
      <td>Bob</td>
      <td>25</td>
      <td>London</td>
    </tr>
  </tbody>
</table>

Células com Span

colspan faz uma célula abranger múltiplas colunas (mesclar horizontalmente). rowspan faz uma célula abranger múltiplas linhas (mesclar verticalmente). Esses atributos criam layouts de tabela complexos como headers que agrupam múltiplas colunas. Tenha cuidado com spanning — pode tornar tabelas mais difíceis de analisar para screen readers. Sempre teste acessibilidade.

html
<table border="1">
  <tr>
    <th colspan="2">Name</th>
    <th rowspan="2">Age</th>
  </tr>
  <tr>
    <th>First</th>
    <th>Last</th>
  </tr>
  <tr>
    <td>Alice</td>
    <td>Smith</td>
    <td>30</td>
  </tr>
</table>

Caption & Scope da Tabela

<caption> fornece um título para a tabela, melhorando acessibilidade. O atributo scope em <th> diz aos screen readers se um header se aplica a uma coluna (scope='col') ou linha (scope='row'). Isso é essencial para tabelas complexas. Para tabelas ainda mais complexas, use atributos id e headers para associar explicitamente células com seus headers.

html
<table>
  <caption>Employee Salary Report 2024</caption>
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Department</th>
      <th scope="col">Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Alice</th>
      <td>Engineering</td>
      <td>$95,000</td>
    </tr>
  </tbody>
</table>

Grupos de Colunas

<colgroup> agrupa colunas para estilização. Elementos <col> dentro dele aplicam estilos (especialmente width) a colunas específicas. Isso é mais eficiente que definir width em cada célula. Grupos de colunas também suportam o atributo span para estilizar múltiplas colunas de uma vez. Use isso para larguras de coluna consistentes em todas as linhas.

html
<table>
  <colgroup>
    <col style="width: 30%;">
    <col style="width: 50%;">
    <col style="width: 20%;">
  </colgroup>
  <tr>
    <th>Product</th>
    <th>Description</th>
    <th>Price</th>
  </tr>
  <tr>
    <td>Laptop</td>
    <td>15-inch laptop</td>
    <td>$999</td>
  </tr>
</table>

Estilizando Tabelas

border-collapse: collapse mescla bordas adjacentes em uma. Use :nth-child(even) para linhas com listras de zebra (melhora legibilidade). :hover destaca linhas no mouseover. Estilização de th diferencia headers. Mantenha a estilização da tabela limpa e legível — evite bordas excessivas. Tabelas responsivas podem precisar overflow-x: auto em um wrapper para telas pequenas.

html
<style>
  table { border-collapse: collapse; width: 100%; }
  th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
  th { background-color: #f4f4f4; }
  tr:nth-child(even) { background-color: #f9f9f9; }
  tr:hover { background-color: #e0e0e0; }
</style>
<table>
  <tr><th>Name</th><th>Score</th></tr>
  <tr><td>Alice</td><td>95</td></tr>
  <tr><td>Bob</td><td>87</td></tr>
</table>
07

Formulários & Input

Estrutura de Formulário

<form> envolve controles de input. action especifica a URL de submissão, method é GET (visível na URL) ou POST (oculto). enctype='multipart/form-data' é necessário para uploads de arquivo. <fieldset> agrupa campos relacionados, <legend> fornece uma legenda. Sempre associe <label> com inputs usando correspondência for/id para acessibilidade.

html
<form action="/submit" method="POST" enctype="multipart/form-data">
  <fieldset>
    <legend>Personal Information</legend>

    <label for="name">Name:</label>
    <input type="text" id="name" name="name" required>

    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required>
  </fieldset>

  <button type="submit">Submit</button>
</form>

Tipos de Input

HTML5 introduziu muitos tipos de input com validação integrada e teclados mobile-friendly. type='email' valida formato de email. type='number' fornece spinners. type='date' e 'time' mostram pickers nativos. type='color' abre um color picker. type='range' cria um slider. type='file' com accept restringe tipos de arquivo. type='hidden' armazena dados não mostrados aos usuários.

html
<input type="text" name="username" placeholder="Username">
<input type="email" name="email" required>
<input type="password" name="pwd" minlength="8">
<input type="number" name="age" min="0" max="120" step="1">
<input type="date" name="birthday">
<input type="time" name="appointment">
<input type="color" name="favcolor" value="#ff0000">
<input type="range" name="volume" min="0" max="100">
<input type="file" name="upload" accept="image/*">
<input type="hidden" name="token" value="abc123">

Select & Textarea

<select> cria um dropdown. <optgroup> agrupa opções relacionadas com um label. <option> define escolhas; o atributo selected pré-seleciona uma. <textarea> é para input de texto multi-linha. rows e cols definem o tamanho visível. maxlength limita a contagem de caracteres. placeholder fornece uma dica. Ambos suportam atributos required e disabled.

html
<label for="country">Country:</label>
<select id="country" name="country">
  <optgroup label="North America">
    <option value="us">United States</option>
    <option value="ca">Canada</option>
  </optgroup>
  <optgroup label="Europe">
    <option value="uk">United Kingdom</option>
    <option value="fr">France</option>
  </optgroup>
</select>

<label for="bio">Bio:</label>
<textarea id="bio" name="bio" rows="4" cols="40"
  maxlength="500" placeholder="Tell us about yourself"></textarea>

Checkboxes & Radio Buttons

Checkboxes permitem múltiplas seleções; radio buttons permitem apenas uma (quando compartilham o mesmo name). O atributo checked pré-seleciona uma opção. Sempre envolva inputs em <label> para texto clicável. Use <fieldset> e <legend> para agrupar escolhas relacionadas para acessibilidade. O valor é enviado ao servidor apenas se selecionado.

html
<fieldset>
  <legend>Select your interests:</legend>
  <label><input type="checkbox" name="interest" value="tech" checked> Tech</label>
  <label><input type="checkbox" name="interest" value="music"> Music</label>
  <label><input type="checkbox" name="interest" value="sports"> Sports</label>
</fieldset>

<fieldset>
  <legend>Choose a plan:</legend>
  <label><input type="radio" name="plan" value="free" checked> Free</label>
  <label><input type="radio" name="plan" value="pro"> Pro</label>
  <label><input type="radio" name="plan" value="enterprise"> Enterprise</label>
</fieldset>

Validação de Formulário

HTML5 fornece validação client-side integrada. required previne submissão se vazio. minlength/maxlength restringem comprimento de texto. pattern usa regex para validação personalizada (o atributo title orienta usuários). type='email' e type='url' validam formato. min/max funcionam com números e datas. Adicione novalidate ao formulário para desabilitar validação.

html
<form>
  <input type="text" name="username" required
         minlength="3" maxlength="20"
         pattern="[A-Za-z0-9_]+"
         title="3-20 alphanumeric characters">

  <input type="email" name="email" required>

  <input type="url" name="website"
         placeholder="https://example.com">

  <input type="number" name="age" min="18" max="99">

  <button type="submit">Submit</button>
</form>

Buttons & Datalist

type='submit' submete o formulário, type='reset' limpa todos os campos, type='button' é um botão personalizado. <datalist> fornece sugestões de autocomplete para elementos <input> — vincule-os com list/id. Ao contrário de <select>, usuários podem inserir valores personalizados. Isso combina a flexibilidade de input de texto com a conveniência de sugestões.

html
<!-- Button types -->
<button type="submit">Submit Form</button>
<button type="reset">Reset</button>
<button type="button" onclick="alert('Hi')">Click Me</button>

<!-- Datalist for autocomplete suggestions -->
<label for="browser">Choose a browser:</label>
<input list="browsers" name="browser" id="browser">
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
  <option value="Edge">
</datalist>
08

HTML Semântico

Header & Navegação

<header> representa conteúdo introdutório — tipicamente um logo, heading e navegação. Pode aparecer no topo de uma página ou dentro de um <article> ou <section>. <nav> identifica links de navegação, ajudando screen readers a pular para a navegação. Uma página pode ter múltiplos headers (ex.: um por seção). Header não é o mesmo que head — é conteúdo visível.

html
<header>
  <h1>My Website</h1>
  <nav>
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/blog">Blog</a></li>
      <li><a href="/contact">Contact</a></li>
    </ul>
  </nav>
</header>

Main & Article

<main> envolve o conteúdo dominante da página (apenas um por página). <article> representa conteúdo self-contained que poderia ser distribuído independentemente (post de blog, artigo de notícia, post de fórum). <time> com datetime fornece datas legíveis por máquina para SEO. <section> agrupa conteúdo tematicamente relacionado com um heading. Essas tags melhoram o outline do documento e acessibilidade.

html
<main>
  <article>
    <h1>Blog Post Title</h1>
    <p>Published on <time datetime="2024-01-15">January 15, 2024</time></p>
    <p>The main content of the article...</p>
    <section>
      <h2>Subsection</h2>
      <p>More content...</p>
    </section>
  </article>
</main>

Section & Aside

<section> agrupa conteúdo relacionado com um heading — use quando o conteúdo tem um heading natural. <aside> representa conteúdo tangencialmente relacionado ao conteúdo principal (sidebars, pull quotes, anúncios, links relacionados). Ambos melhoram a estrutura do documento. Seções podem ser aninhadas. Asides são tipicamente estilizados como sidebars mas são semânticos, não apresentacionais.

html
<section>
  <h2>Services</h2>
  <p>We offer the following services:</p>
  <article>
    <h3>Web Design</h3>
    <p>Custom website design...</p>
  </article>
</section>

<aside>
  <h3>Related Articles</h3>
  <ul>
    <li><a href="/post1">Related Post 1</a></li>
    <li><a href="/post2">Related Post 2</a></li>
  </ul>
</aside>

Footer

<footer> contém conteúdo de footer para uma página ou seção — copyright, links para documentos relacionados, info de contato, sitemap. Uma página pode ter múltiplos footers (ex.: um por seção de artigo). Footers não precisam estar visualmente no fundo, mas semanticamente representam conteúdo conclusivo. Use &copy; para o símbolo de copyright.

html
<footer>
  <div>
    <h3>About Us</h3>
    <p>Company information...</p>
  </div>
  <nav>
    <a href="/privacy">Privacy Policy</a>
    <a href="/terms">Terms of Service</a>
    <a href="/sitemap">Sitemap</a>
  </nav>
  <p>&copy; 2024 My Company. All rights reserved.</p>
</footer>

Details & Summary

<details> cria um widget de disclosure interativo — conteúdo está oculto até o usuário clicar em <summary>. O atributo open mostra expandido por padrão. Isso é HTML nativo, sem JavaScript necessário. Ótimo para FAQs, seções colapsáveis e progressive disclosure. Details aninhados criam acordeões multi-nível. Estilize com o seletor de atributo [open].

html
<details>
  <summary>Click to expand FAQ</summary>
  <p>This content is hidden by default and shown when the summary is clicked.</p>
</details>

<!-- Open by default -->
<details open>
  <summary>What is HTML?</summary>
  <p>HTML (HyperText Markup Language) is the standard language for creating web pages.</p>
</details>

<!-- Nested details -->
<details>
  <summary>Advanced Topics</summary>
  <details>
    <summary>Sub-topic</summary>
    <p>Nested content...</p>
  </details>
</details>
09

Meta Tags & SEO

Charset & Viewport

charset='UTF-8' declara codificação de caracteres — essencial para exibir todos os caracteres corretamente. A meta tag viewport é crítica para design responsivo: width=device-width corresponde à largura do dispositivo, initial-scale=1.0 define o nível de zoom. Sem ela, navegadores mobile renderizam páginas com largura de desktop. Essas duas meta tags devem estar em todo documento HTML.

html
<head>
  <!-- Character encoding -->
  <meta charset="UTF-8">

  <!-- Responsive viewport -->
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0">

  <!-- Internet Explorer compatibility -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>

Description & Keywords

A meta tag description é a mais importante para SEO — motores de busca a exibem sob seu título nos resultados (mantenha abaixo de 160 caracteres). keywords é amplamente ignorado por motores de busca modernos. robots controla indexação: index/noindex, follow/nofollow. author credita o criador do conteúdo. Escreva descriptions convincentes para melhorar taxas de click-through.

html
<meta name="description"
      content="Free HTML tutorials for beginners. Learn HTML tags, attributes, and semantic markup with examples.">

<meta name="keywords"
      content="HTML, tutorial, web development, markup">

<meta name="author" content="John Doe">
<meta name="robots" content="index, follow">

Open Graph (Facebook)

Meta tags Open Graph (og:) controlam como sua página aparece quando compartilhada no Facebook, LinkedIn e outras plataformas. og:title, og:description, og:image e og:url são os mais importantes. og:type pode ser article, website, product, etc. A imagem deve ter pelo menos 1200x630 pixels. Teste com o Sharing Debugger do Facebook antes de deployar.

html
<meta property="og:title" content="My Amazing Article">
<meta property="og:description" content="A brief description of the article.">
<meta property="og:image" content="https://example.com/image.jpg">
<meta property="og:url" content="https://example.com/article">
<meta property="og:type" content="article">
<meta property="og:site_name" content="My Website">
<meta property="og:locale" content="en_US">

Twitter Cards

Meta tags Twitter Card controlam como links aparecem no Twitter/X. twitter:card pode ser summary, summary_large_image ou player. O card de imagem grande é o mais engajador. twitter:site e twitter:creator linkam para contas Twitter. Se tags Open Graph estiverem presentes, o Twitter faz fallback para elas, mas tags Twitter explícitas dão mais controle. Teste com Twitter Card Validator.

html
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="My Amazing Article">
<meta name="twitter:description" content="A brief description.">
<meta name="twitter:image" content="https://example.com/image.jpg">
<meta name="twitter:site" content="@mywebsite">
<meta name="twitter:creator" content="@author">

Canonical & Structured Data

A link tag canonical diz aos motores de busca a URL preferida para uma página, prevenindo penalidades de conteúdo duplicado. Structured data JSON-LD ajuda motores de busca a entender seu conteúdo e habilita rich snippets (star ratings, breadcrumbs, FAQ accordions nos resultados de busca). Use tipos schema.org como Article, Product, Event ou FAQPage. Valide com o Rich Results Test do Google.

html
<!-- Canonical URL (prevents duplicate content issues) -->
<link rel="canonical" href="https://example.com/article">

<!-- Structured data (JSON-LD) -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "My Article Title",
  "author": "John Doe",
  "datePublished": "2024-01-15",
  "image": "https://example.com/image.jpg"
}
</script>
10

SVG & Canvas

Básico de SVG

SVG (Scalable Vector Graphics) cria gráficos resolution-independent que escalam sem perda de qualidade. SVG inline pode ser estilizado com CSS e manipulado com JavaScript. Formas comuns: <circle>, <rect>, <line>, <ellipse>, <polygon>, <path>. SVG é ideal para ícones, logos e diagramas. Ao contrário de imagens raster, SVGs são nítidos em qualquer tamanho.

html
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="blue" stroke="black" stroke-width="2"/>
  <text x="100" y="105" text-anchor="middle" fill="white">Circle</text>
</svg>

<!-- Inline SVG (can be styled with CSS) -->
<svg width="100" height="100">
  <rect x="10" y="10" width="80" height="80" fill="red" rx="10"/>
</svg>

Formas SVG

Formas SVG usam atributos baseados em coordenadas. <rect> precisa de x, y, width, height; rx/ry criam cantos arredondados. <circle> precisa de cx, cy (centro) e r (raio). <ellipse> usa rx e ry para diferentes raios x/y. <line> conecta x1,y1 a x2,y2. <polygon> recebe uma lista de points. fill define cor interior, stroke define contorno.

html
<svg width="300" height="200">
  <!-- Rectangle -->
  <rect x="10" y="10" width="80" height="50" fill="orange" rx="10" ry="10"/>

  <!-- Circle -->
  <circle cx="200" cy="50" r="40" fill="green"/>

  <!-- Ellipse -->
  <ellipse cx="100" cy="150" rx="60" ry="30" fill="purple"/>

  <!-- Line -->
  <line x1="10" y1="180" x2="290" y2="180" stroke="black" stroke-width="2"/>

  <!-- Polygon -->
  <polygon points="250,10 290,80 210,80" fill="pink"/>
</svg>

Paths SVG

<path> é o elemento SVG mais poderoso, usando um atributo d com comandos: M (moveto), L (lineto), H/V (linha horizontal/vertical), C (Bezier cúbica), Q (Bezier quadrática), A (arco), Z (fechar path). Maiúsculas = coordenadas absolutas, minúsculas = relativas. viewBox define o sistema de coordenadas. Ícones SVG usam paths para ícones escaláveis, estilizáveis.

html
<svg width="200" height="200">
  <!-- M=move, L=line, C=curve, Z=close -->
  <path d="M 10 10 L 100 10 L 100 100 Z" fill="none" stroke="black"/>

  <!-- Bezier curve -->
  <path d="M 10 100 C 50 10, 150 10, 190 100" fill="none" stroke="red"/>

  <!-- Arc -->
  <path d="M 10 100 A 90 90 0 0 1 190 100" fill="none" stroke="blue"/>
</svg>

<!-- SVG icon example -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
  <path d="M12 2L2 7v10l10 5 10-5V7z"/>
</svg>

Básico de Canvas

<canvas> é uma superfície de desenho bitmap manipulada via JavaScript. Obtenha o contexto 2D com getContext('2d'). Ao contrário de SVG, canvas é pixel-based (não escalável) e não faz parte do DOM. Canvas é melhor para animações complexas, jogos e processamento de imagem. SVG é melhor para gráficos estáticos, ícones e charts interativos. Escolha com base em suas necessidades.

html
<canvas id="myCanvas" width="300" height="200"></canvas>

<script>
  const canvas = document.getElementById('myCanvas');
  const ctx = canvas.getContext('2d');

  // Draw a rectangle
  ctx.fillStyle = 'blue';
  ctx.fillRect(10, 10, 100, 80);

  // Draw a circle
  ctx.beginPath();
  ctx.arc(200, 50, 30, 0, Math.PI * 2);
  ctx.fillStyle = 'red';
  ctx.fill();

  // Draw text
  ctx.font = '20px Arial';
  ctx.fillText('Hello Canvas', 50, 150);
</script>

Ícones SVG Inline

SVG <symbol> define ícones reutilizáveis que são referenciados com <use href='#id'>. Esta é a técnica de sprite SVG — defina ícones uma vez, use-os em qualquer lugar. O symbol fica oculto (display:none) e é instanciado via <use>. Os ícones herdam a cor do 'color' do CSS via fill='currentColor'. Esta abordagem é eficiente (uma definição, muitos usos) e totalmente estilizável.

html
<!-- Reusable SVG symbol -->
<svg style="display:none">
  <symbol id="icon-home" viewBox="0 0 24 24">
    <path d="M12 2L2 12h3v8h6v-6h2v6h6v-8h3z"/>
  </symbol>
</svg>

<!-- Use the icon -->
<svg width="24" height="24" fill="currentColor">
  <use href="#icon-home"/>
</svg>

<!-- Styled icon -->
<svg width="32" height="32" class="icon" style="color: blue;">
  <use href="#icon-home"/>
</svg>
11

Acessibilidade (ARIA)

Papéis ARIA

Os papéis ARIA definem o que um elemento faz para leitores de tela. Papéis de marco (banner, navigation, main, complementary, contentinfo) permitem que usuários de leitores de tela saltem entre regiões da página. Elementos semânticos do HTML5 (<header>, <nav>, <main>) têm papéis ARIA implícitos, então adicionar atributos role é frequentemente redundante — mas útil para navegadores antigos. Sempre prefira HTML semântico em vez de ARIA quando possível.

html
<!-- Landmark roles for page structure -->
<header role="banner">Site Header</header>
<nav role="navigation">Main Menu</nav>
<main role="main">Primary Content</main>
<aside role="complementary">Sidebar</aside>
<footer role="contentinfo">Footer</footer>
<form role="search">Search Form</form>

<!-- Document structure roles -->
<article role="article">Blog Post</article>
<section role="region" aria-label="Comments">Comments</section>

aria-label & aria-labelledby

aria-label define um nome acessível quando não existe um rótulo visível (ex.: botões apenas com ícone). aria-labelledby referencia o ID de elemento(s) de texto visível que rotulam o controle — útil quando um rótulo visível já está na tela. Quando múltiplos IDs são listados, seus textos são concatenados em ordem. Prefira aria-labelledby quando existe texto visível, pois mantém os rótulos sincronizados.

html
<!-- aria-label provides accessible name directly -->
<button aria-label="Close menu" onclick="closeMenu()">✕</button>
<input type="search" aria-label="Search products" />

<!-- aria-labelledby references visible text -->
<div id="billing-label">Billing Address</div>
<input type="text" aria-labelledby="billing-label" />

<!-- Multiple labels combined -->
<span id="city">City</span>
<span id="required">required</span>
<input aria-labelledby="city required" />

aria-describedby & Tooltips

aria-describedby vincula um elemento a texto descritivo adicional via ID do elemento. Leitores de tela anunciam esta descrição após o rótulo. É ideal para texto de ajuda, dicas e mensagens de erro. Use role='alert' em mensagens de erro para que sejam anunciadas imediatamente quando aparecerem. Defina aria-invalid='true' em campos com erros para que leitores de tela indiquem o estado inválido.

html
<label for="password">Password</label>
<input type="password" id="password"
       aria-describedby="pwd-help pwd-rules" />
<p id="pwd-help">Must be at least 8 characters</p>
<p id="pwd-rules">Include uppercase, number, and symbol</p>

<!-- Error messaging -->
<input type="email" id="email" aria-describedby="email-error" aria-invalid="true" />
<p id="email-error" role="alert">Please enter a valid email address</p>

Regiões Dinâmicas (aria-live)

Regiões dinâmicas anunciam mudanças de conteúdo para usuários de leitores de tela. aria-live='polite' aguarda uma pausa antes de anunciar (bom para atualizações de status). aria-live='assertive' interrompe imediatamente (para erros críticos). aria-atomic='true' lê todo o conteúdo da região em vez de apenas a porção alterada. aria-relevant especifica quais tipos de mudança (adições, remoções, texto) disparam anúncios. Essencial para SPAs, apps de chat e conteúdo auto-atualizável.

html
<!-- Polite: announces when user is idle -->
<div aria-live="polite" id="status">Saving...</div>

<!-- Assertive: announces immediately, interrupts -->
<div aria-live="assertive" role="alert" id="errors">
  Connection lost!
</div>

<!-- aria-atomic reads entire region, not just changes -->
<div aria-live="polite" aria-atomic="true" id="cart">
  3 items in cart
</div>

<!-- aria-relevant controls what changes are announced -->
<div aria-live="polite" aria-relevant="additions text">
  Chat messages appear here
</div>

Gerenciamento de Foco & tabindex

tabindex controla o comportamento do foco do teclado. tabindex='0' torna elementos não interativos (divs, spans) focáveis na ordem natural do DOM — use para widgets personalizados. tabindex='-1' torna elementos focáveis apenas programaticamente via JS .focus() — útil para modais e alvos de salto. Nunca use valores positivos de tabindex pois eles sobrescrevem a ordem natural de tabulação e criam confusão. Sempre forneça links de salto como o primeiro elemento focável em uma página.

html
<!-- tabindex="0": element is focusable in natural order -->
<div tabindex="0" role="button" onkeypress="handleKey()">
  Custom clickable div
</div>

<!-- tabindex="-1": focusable only via JS, removed from tab order -->
<div tabindex="-1" id="modal">Modal content</div>
<script>
  document.getElementById('modal').focus();
</script>

<!-- tabindex="1+": DO NOT USE — breaks natural tab order -->
<!-- Avoid: <div tabindex="2"> -->

<!-- Skip link for keyboard users -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<main id="main-content">...</main>

Conteúdo Oculto & Apenas para Leitor de Tela

aria-hidden='true' remove elementos da árvore de acessibilidade enquanto os mantém visíveis — use para ícones decorativos, texto redundante ou conteúdo fora da tela. O padrão .sr-only oculta o texto visualmente, mas o mantém legível por leitores de tela — essencial para botões apenas com ícone. Nunca use aria-hidden em elementos focáveis, pois isso cria uma desconexão entre a navegação por teclado e por leitor de tela. A técnica clip é o método visualmente oculto mais robusto.

html
<!-- aria-hidden: visible but hidden from screen readers -->
<div aria-hidden="true">
  <i class="icon-decoration"></i> Decorative only
</div>

<!-- visually hidden but available to screen readers -->
<style>
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}
</style>
<button>
  <span class="sr-only">Delete item</span>
  <i class="icon-trash" aria-hidden="true"></i>
</button>
12

APIs HTML5 (Geolocalização, Armazenamento, Arrastar e Soltar)

API de Geolocalização

A API de Geolocalização permite solicitar a localização física do usuário. Navegadores sempre solicitam permissão — o usuário deve conceder acesso explicitamente. getCurrentPosition recebe callbacks de sucesso e erro mais um objeto de opções (enableHighAccuracy, timeout, maximumAge). Para rastreamento contínuo, use watchPosition() que retorna um ID que você pode passar para clearWatch(). Sempre trate erros adequadamente (permissão negada, posição indisponível, timeout). A geolocalização requer HTTPS em navegadores modernos.

html
<!-- Request user location -->
<button onclick="getLocation()">Get My Location</button>
<p id="demo"></p>

<script>
function getLocation() {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        document.getElementById("demo").innerHTML =
          "Lat: " + pos.coords.latitude +
          "<br>Lon: " + pos.coords.longitude;
      },
      (err) => {
        alert("Error: " + err.message);
      },
      { enableHighAccuracy: true, timeout: 5000 }
    );
  } else {
    alert("Geolocation not supported.");
  }
}
</script>

Web Storage (localStorage & sessionStorage)

O Web Storage fornece armazenamento chave-valor no cliente. localStorage persiste indefinidamente; sessionStorage é limpo quando a aba é fechada. Ambos armazenam apenas strings — use JSON.stringify/parse para objetos. O limite de armazenamento é ~5-10MB por origem. Diferente dos cookies, os dados de armazenamento não são enviados a cada requisição HTTP. Esteja ciente: o armazenamento é síncrono e bloqueia a thread principal, e é acessível por qualquer script na mesma origem (não adequado para dados sensíveis).

html
<!-- localStorage: persists until cleared -->
<script>
// Store data
localStorage.setItem("username", "alice");
localStorage.setItem("prefs", JSON.stringify({theme: "dark", lang: "en"}));

// Retrieve data
const user = localStorage.getItem("username");
const prefs = JSON.parse(localStorage.getItem("prefs") || "{}");

// Remove single item
localStorage.removeItem("username");

// Clear all items
localStorage.clear();

// sessionStorage: cleared when tab closes
sessionStorage.setItem("tempToken", "abc123");
</script>

API de Arrastar e Soltar

A API de Arrastar e Soltar do HTML5 permite interações de arrasto nativas. Defina draggable='true' no elemento de origem. ondragstart dispara quando o arrasto começa — use dataTransfer.setData() para armazenar os dados arrastados. ondragover no alvo de soltura DEVE chamar preventDefault() para permitir o soltar. ondrop trata o soltar real — recupere dados com dataTransfer.getData(). Você pode arrastar arquivos do SO para o navegador usando event.dataTransfer.files. Para apps complexos, considere bibliotecas como SortableJS para melhor suporte cross-browser.

html
<div id="drag1" draggable="true" ondragstart="drag(event)">
  Drag me!
</div>
<div id="dropzone" ondrop="drop(event)" ondragover="allowDrop(event)">
  Drop here
</div>

<script>
function allowDrop(ev) {
  ev.preventDefault(); // necessary to allow dropping
}

function drag(ev) {
  ev.dataTransfer.setData("text", ev.target.id);
}

function drop(ev) {
  ev.preventDefault();
  const data = ev.dataTransfer.getData("text");
  ev.target.appendChild(document.getElementById(data));
}
</script>

API de Visibilidade de Página

A API de Visibilidade de Página informa se a página está visível para o usuário (não minimizada, não em uma aba em segundo plano). Use-a para pausar animações pesadas, reprodução de vídeo ou polling quando o usuário não está olhando — economizando bateria e CPU. document.hidden é um booleano; document.visibilityState retorna 'visible', 'hidden' ou 'prerender'. O evento visibilitychange dispara em transições. Isso é mais confiável que blur/focus para detectar visibilidade real.

html
<script>
document.addEventListener("visibilitychange", () => {
  if (document.hidden) {
    console.log("Tab is hidden — pause video/animation");
    video.pause();
  } else {
    console.log("Tab is visible — resume");
    video.play();
  }
});

// Check current state
if (document.visibilityState === "visible") {
  console.log("Page is visible");
}
</script>

API de Tela Cheia

A API de Tela Cheia permite exibir qualquer elemento em modo tela cheia. requestFullscreen() deve ser acionada por um gesto do usuário (clique/tecla). Diferentes navegadores podem precisar de prefixos de fornecedor (webkit, moz, ms). O evento fullscreenchange dispara ao entrar ou sair da tela cheia. document.fullscreenElement referencia o elemento atual em tela cheia (null se não estiver em tela cheia). Use a pseudo-classe CSS :fullscreen para estilizar elementos em tela cheia de forma diferente.

html
<button onclick="openFullscreen()">Fullscreen</button>
<button onclick="closeFullscreen()">Exit</button>
<div id="container">Content to fullscreen</div>

<script>
function openFullscreen() {
  const elem = document.getElementById("container");
  if (elem.requestFullscreen) {
    elem.requestFullscreen();
  } else if (elem.webkitRequestFullscreen) {
    elem.webkitRequestFullscreen();
  }
}

function closeFullscreen() {
  if (document.exitFullscreen) {
    document.exitFullscreen();
  }
}

document.addEventListener("fullscreenchange", () => {
  console.log("Fullscreen:", !!document.fullscreenElement);
});
</script>
13

Web Components

Custom Elements

Custom Elements permitem criar tags HTML reutilizáveis com comportamento encapsulado. A classe estende HTMLElement (ou subclasses de HTMLElement). connectedCallback dispara quando o elemento é adicionado ao DOM — use-o para renderização. attributeChangedCallback reage a mudanças de atributos, mas apenas para atributos listados em observedAttributes. Os nomes devem conter um hífen (ex.: 'my-greeting') para evitar conflitos com HTML nativo. customElements.define() registra o elemento. Evite usar Shadow DOM a menos que precise de encapsulamento de estilo.

html
<my-greeting name="World"></my-greeting>

<script>
class MyGreeting extends HTMLElement {
  constructor() {
    super();
    this.name = this.getAttribute("name") || "Guest";
  }
  connectedCallback() {
    this.innerHTML = `<h2>Hello, ${this.name}!</h2>`;
  }
  // Observe attribute changes
  static get observedAttributes() {
    return ["name"];
  }
  attributeChangedCallback(name, oldVal, newVal) {
    if (name === "name") {
      this.name = newVal;
      this.connectedCallback();
    }
  }
}
customElements.define("my-greeting", MyGreeting);
</script>

Shadow DOM

Shadow DOM fornece encapsulamento de estilo e DOM — estilos dentro da shadow tree não vazam para fora, e estilos da página não vazam para dentro. attachShadow({mode:'open'}) cria uma shadow root acessível via element.shadowRoot. mode:'closed' nega acesso externo (raramente usado). Elementos <slot> são espaços reservados onde filhos do light DOM são projetados. Named slots (<slot name='title'>) correspondem a filhos com atributos slot correspondentes. ::slotted() estiliza conteúdo projetado. Shadow DOM é chave para construir componentes reutilizáveis e autocontidos.

html
<my-card>
  <span slot="title">Card Title</span>
  <p slot="body">Card content here.</p>
</my-card>

<script>
class MyCard extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: "open" });
    shadow.innerHTML = `
      <style>
        .card { border: 1px solid #ccc; padding: 16px; border-radius: 8px; }
        ::slotted([slot="title"]) { font-size: 1.5em; font-weight: bold; }
      </style>
      <div class="card">
        <slot name="title"></slot>
        <slot name="body"></slot>
      </div>
    `;
  }
}
customElements.define("my-card", MyCard);
</script>

HTML Templates

O elemento <template> contém HTML que não é renderizado quando a página carrega — seu conteúdo é inerte (scripts não executam, imagens não carregam, estilos não se aplicam). Acesse o conteúdo via .content (um DocumentFragment) e clone-o com cloneNode(true) para instanciar. Templates são ideais para estruturas repetitivas geradas por JavaScript. Diferente do innerHTML, templates são analisados uma vez e podem ser clonados repetidamente sem reanálise. Combinados com Custom Elements e Shadow DOM, eles formam o padrão Web Components.

html
<template id="row-template">
  <tr>
    <td class="name"></td>
    <td class="email"></td>
  </tr>
</template>

<script>
function addRow(name, email) {
  const template = document.getElementById("row-template");
  const clone = template.content.cloneNode(true);
  clone.querySelector(".name").textContent = name;
  clone.querySelector(".email").textContent = email;
  document.querySelector("tbody").appendChild(clone);
}

addRow("Alice", "[email protected]");
addRow("Bob", "[email protected]");
</script>

Callbacks de Ciclo de Vida

Custom Elements têm quatro callbacks de ciclo de vida. constructor() executa quando o elemento é criado (evite trabalho pesado aqui). connectedCallback() dispara quando adicionado ao DOM — ideal para setup e renderização. disconnectedCallback() dispara na remoção — use para limpeza (event listeners, timers). adoptedCallback() dispara quando movido para um novo documento via adoptNode() (raro). attributeChangedCallback() dispara apenas para atributos observados. A ordem de upgrade é sempre: constructor → connectedCallback. Mudanças de atributos podem disparar antes de connectedCallback.

html
<script>
class LifecycleDemo extends HTMLElement {
  constructor() {
    super();
    console.log("1. constructor: element created");
  }
  connectedCallback() {
    console.log("2. connected: added to DOM");
  }
  disconnectedCallback() {
    console.log("3. disconnected: removed from DOM");
  }
  adoptedCallback() {
    console.log("4. adopted: moved to new document");
  }
  attributeChangedCallback(attr, oldVal, newVal) {
    console.log(`5. attribute '${attr}' changed: ${oldVal} -> ${newVal}`);
  }
  static get observedAttributes() {
    return ["data-status"];
  }
}
customElements.define("lifecycle-demo", LifecycleDemo);
</script>

Customized Built-in Elements

Customized built-in elements estendem elementos HTML nativos (como button, input, div) para herdar seu comportamento embutido. Use o atributo 'is' em vez de um nome de tag personalizado. O terceiro argumento para customElements.define() especifica qual elemento nativo está sendo estendido. Isso é útil quando você quer aprimorar elementos existentes (ex.: adicionar validação a <input>) em vez de criar inteiramente novos. Nota: Safari não suporta customized built-in elements — considere autonomous custom elements para compatibilidade cross-browser.

html
<!-- Extend a native button -->
<button is="my-button">Click me</button>

<script>
class MyButton extends HTMLButtonElement {
  constructor() {
    super();
    this.addEventListener("click", () => {
      this.textContent = "Clicked!";
      this.style.background = "lightgreen";
    });
  }
  connectedCallback() {
    this.style.fontWeight = "bold";
  }
}
customElements.define("my-button", MyButton,
  { extends: "button" });
</script>
14

Elementos de Mídia (Áudio e Vídeo)

Elemento Video

O elemento <video> incorpora vídeo sem plugins. O atributo controls mostra controles nativos de play/pause/volume. poster especifica uma imagem de pré-visualização antes da reprodução. Múltiplas tags <source> fornecem fallbacks de formato — o navegador usa o primeiro que suporta (MP4/H.264 é o mais amplamente suportado, WebM é aberto e eficiente). Elementos <track> adicionam legendas, closed captions ou descrições via arquivos WebVTT. Sempre inclua texto de fallback para navegadores muito antigos. Para autoplay, adicione o atributo muted — a maioria dos navegadores bloqueia autoplay com som.

html
<video width="640" height="360" controls poster="preview.jpg">
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.webm" type="video/webm">
  <track kind="subtitles" src="subs_en.vtt"
         srclang="en" label="English" default>
  <track kind="captions" src="caps_en.vtt"
         srclang="en" label="English Captions">
  Your browser does not support the video tag.
</video>

Elemento Audio

O elemento <audio> incorpora som. controls mostra a UI nativa do player. Sem controls, o elemento é invisível — controle a reprodução via JavaScript (play(), pause(), volume, currentTime). preload='auto' sugere que o navegador deve armazenar o arquivo em buffer; 'metadata' carrega apenas duração/info; 'none' não carrega nada até o play. MP3 tem suporte universal; OGG Vorbis é aberto mas não suportado no Safari. Para jogos ou timing preciso, use a Web Audio API em vez de <audio> para menor latência e efeitos.

html
<!-- Basic audio player -->
<audio controls>
  <source src="song.mp3" type="audio/mpeg">
  <source src="song.ogg" type="audio/ogg">
  Your browser does not support audio.
</audio>

<!-- Audio controlled by JavaScript -->
<audio id="player" src="song.mp3" preload="auto"></audio>
<button onclick="document.getElementById('player').play()">Play</button>
<button onclick="document.getElementById('player').pause()">Pause</button>
<button onclick="document.getElementById('player').volume += 0.1">Vol+</button>

Picture & srcset (Imagens Responsivas)

Imagens responsivas melhoram o desempenho servindo imagens de tamanho apropriado. srcset com descritores de largura (480w, 800w) mais dicas de sizes permitem ao navegador escolher a melhor imagem — isso é preferido para troca de resolução. <picture> com media queries permite direção de arte (cortes diferentes para telas diferentes). <source> com atributos type fornece fallbacks de formato moderno (WebP, AVIF) com fallback JPG/PNG. Sempre inclua um <img> regular como último filho de <picture> para fallback e acessibilidade.

html
<!-- srcset: let browser choose resolution -->
<img src="small.jpg"
     srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
     sizes="(max-width: 600px) 480px, 800px"
     alt="Responsive image">

<!-- picture: art direction with different images -->
<picture>
  <source media="(max-width: 600px)" srcset="mobile.jpg">
  <source media="(max-width: 1200px)" srcset="tablet.jpg">
  <img src="desktop.jpg" alt="Art-directed image">
</picture>

<!-- Modern format with fallback -->
<picture>
  <source type="image/webp" srcset="photo.webp">
  <source type="image/avif" srcset="photo.avif">
  <img src="photo.jpg" alt="With format fallback">
</picture>

Incorporação com iframe

iframes incorporam outro documento dentro da página atual. O atributo title é essencial para acessibilidade — leitores de tela o anunciam. O atributo sandbox restringe as capacidades do iframe para segurança: valor vazio bloqueia tudo; adicione tokens (allow-scripts, allow-forms, allow-same-origin) para reabilitar recursos específicos. loading='lazy' adia o carregamento até próximo do viewport. allow especifica políticas de recursos (camera, microphone, autoplay). Tenha cuidado ao incorporar conteúdo não confiável — faça sandbox. iframes cross-origin não podem ser acessados via JavaScript.

html
<!-- Basic iframe -->
<iframe src="https://example.com"
        width="600" height="400"
        title="Embedded Content">
</iframe>

<!-- Sandboxed iframe for security -->
<iframe src="untrusted.html"
        sandbox="allow-scripts allow-same-origin"
        loading="lazy">
</iframe>

<!-- YouTube embed -->
<iframe src="https://www.youtube.com/embed/VIDEO_ID"
        allow="accelerometer; autoplay; encrypted-media"
        allowfullscreen
        title="YouTube video">
</iframe>

Embed & Object

<embed> e <object> são métodos de incorporação antigos, amplamente substituídos por <iframe> e <video>. <embed> é self-closing e simples, mas não oferece conteúdo de fallback. <object> é mais flexível — o conteúdo dentro das tags serve como fallback se o recurso incorporado não puder ser exibido. Use <object> para PDFs e SVGs onde você precisa de fallback. Para desenvolvimento web moderno, prefira <iframe> para páginas externas, <video>/<audio> para mídia e <svg> inline para gráficos vetoriais. <embed> é usado principalmente para conteúdo de plugin (Flash, agora obsoleto).

html
<!-- embed: simple, self-closing -->
<embed src="animation.svg" type="image/svg+xml"
       width="300" height="200">

<!-- object: more flexible with fallback -->
<object data="document.pdf" type="application/pdf"
        width="100%" height="600px">
  <p>Unable to display PDF.
     <a href="document.pdf">Download it instead.</a>
  </p>
</object>

<!-- embed YouTube without iframe -->
<embed src="https://www.youtube.com/v/VIDEO_ID"
       type="application/x-shockwave-flash"
       width="560" height="315">
15

Aprofundamento em Input Types

Inputs de Data e Hora

Os tipos de input de data/hora do HTML5 fornecem pickers nativos sem bibliotecas JavaScript. type='date' fornece um calendário; type='time' fornece um seletor de hora; type='datetime-local' combina ambos. type='month' e type='week' selecionam meses e semanas. min/max limitam o intervalo selecionável. step define a granularidade (ex.: step='1800' para intervalos de 30 minutos em segundos). O formato exibido varia por navegador/locale, mas o valor enviado é sempre no formato ISO 8601 (YYYY-MM-DD). Nem todos os navegadores suportam todos os tipos igualmente — teste cross-browser.

html
<label for="birthday">Birthday:</label>
<input type="date" id="birthday" min="1900-01-01" max="2025-12-31">

<label for="appt">Appointment:</label>
<input type="time" id="appt" min="09:00" max="17:00" step="1800">

<label for="meeting">Meeting:</label>
<input type="datetime-local" id="meeting">

<label for="month">Pick a month:</label>
<input type="month" id="month">

<label for="week">Pick a week:</label>
<input type="week" id="week">

Inputs de Número e Range

type='number' fornece um controle spinner com setas para cima/para baixo. min, max e step limitam os valores. Para moeda, use step='0.01'. type='range' renderiza um slider — sempre o acompanhe com um <output> ou rótulo visível mostrando o valor atual, pois o valor não é exibido por padrão. Inputs numéricos filtram entrada não numérica, mas ainda permitem alguns caracteres inválidos; valide no servidor. Para quantidades que não precisam de spinner, considere type='text' com inputmode='numeric' e validação de pattern.

html
<label for="qty">Quantity (1-100):</label>
<input type="number" id="qty" min="1" max="100"
       step="1" value="10">

<label for="price">Price ($):</label>
<input type="number" id="price" min="0" step="0.01"
       placeholder="0.00">

<label for="volume">Volume:</label>
<input type="range" id="volume" min="0" max="100"
       value="50" oninput="out.value=this.value">
<output id="out">50</output>

Inputs de Cor e Arquivo

type='color' abre um seletor de cores nativo e retorna um valor hex (#rrggbb). type='file' permite selecionar arquivos. O atributo accept filtra por tipo MIME ou extensão (image/*, .pdf, image/png). O atributo multiple permite selecionar múltiplos arquivos. Acesse arquivos selecionados via propriedade files (uma FileList) em JavaScript. Use URL.createObjectURL() para criar uma URL de pré-visualização local para imagens. Para uploads de arquivos grandes, considere uploads em partes ou a File API para rastreamento de progresso. Sempre valide tipos e tamanhos de arquivo no servidor.

html
<label for="color">Pick a color:</label>
<input type="color" id="color" value="#ff0000">

<label for="avatar">Upload avatar:</label>
<input type="file" id="avatar" accept="image/*">

<label for="docs">Upload documents:</label>
<input type="file" id="docs" accept=".pdf,.doc,.docx" multiple>

<!-- File input with image preview -->
<input type="file" accept="image/*" onchange="preview(this)">
<img id="preview-img" hidden>
<script>
function preview(input) {
  const file = input.files[0];
  if (file) {
    document.getElementById("preview-img").src =
      URL.createObjectURL(file);
    document.getElementById("preview-img").hidden = false;
  }
}
</script>

datalist (Sugestões de Input)

<datalist> fornece sugestões de autocomplete para campos de input. Vincule-o a um input via atributo list correspondente ao id do datalist. Diferente de <select>, usuários ainda podem digitar qualquer valor — as sugestões são opcionais. Funciona com inputs text, number, date, color e range. O navegador mostra sugestões correspondentes conforme o usuário digita. Esta é uma alternativa leve a bibliotecas de autocomplete JavaScript para casos de uso simples. Nota: estilizar opções dentro de datalist não é suportado — elas renderizam com padrões do navegador.

html
<label for="browser">Favorite browser:</label>
<input list="browsers" id="browser" name="browser">
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
  <option value="Edge">
  <option value="Opera">
</datalist>

<!-- Works with various input types -->
<label for="color">Choose color:</label>
<input type="color" list="preset-colors" id="color">
<datalist id="preset-colors">
  <option value="#ff0000">
  <option value="#00ff00">
  <option value="#0000ff">
</datalist>

Atributos de Validação de Formulário

O HTML5 fornece validação client-side embutida via atributos. required impede o envio se vazio. type='email'/'url' validam formato automaticamente. minlength/maxlength limitam o comprimento do texto. min/max limitam números e datas. pattern usa regex para validação personalizada. O navegador mostra bolhas de erro padrão. Personalize mensagens com setCustomValidity() — mas sempre limpe-a no input (setCustomValidity('')) para evitar erros persistentes. A validação client-side melhora a UX, mas deve ser combinada com validação server-side para segurança, pois pode ser ignorada.

html
<form>
  <label>Email: <input type="email" required></label>
  <label>Username:
    <input type="text" required minlength="3" maxlength="20"
           pattern="[a-zA-Z0-9_]+">
  </label>
  <label>Age:
    <input type="number" min="18" max="120" required>
  </label>
  <label>Website:
    <input type="url" placeholder="https://example.com">
  </label>
  <button type="submit">Submit</button>
</form>

<!-- Custom validation message -->
<input type="text" required
  oninvalid="this.setCustomValidity('Please enter your name')"
  oninput="this.setCustomValidity('')">
16

Service Worker & PWA

Registro de Service Worker

Um service worker é um arquivo JavaScript que executa em segundo plano, separado da página web, permitindo suporte offline, notificações push e sincronização em segundo plano. Registre-o a partir da página principal — ele deve ser servido via HTTPS. A localização do arquivo do service worker determina seu escopo (ele controla páginas em seu diretório e subdiretórios). O registro é assíncrono e acontece apenas uma vez por escopo. Após a primeira visita, o SW ativa nos carregamentos subsequentes. Use o evento load para adiar o registro até depois que a página esteja interativa.

html
<!-- Register a service worker in main page -->
<script>
if ("serviceWorker" in navigator) {
  window.addEventListener("load", () => {
    navigator.serviceWorker
      .register("/sw.js")
      .then((reg) => {
        console.log("SW registered:", reg.scope);
      })
      .catch((err) => {
        console.log("SW registration failed:", err);
      });
  });
}
</script>

Service Worker: Caching

O ciclo de vida do service worker tem três fases: install (armazenar em cache assets principais), activate (limpar caches antigos) e fetch (interceptar requisições de rede). A estratégia cache-first mostrada aqui serve respostas em cache imediatamente, com fallback para rede. Outras estratégias incluem network-first (tentar rede, fallback para cache) e stale-while-revalidate (servir cache, atualizar em segundo plano). Incremente CACHE_NAME para disparar atualizações de cache. A Cache API armazena pares Request/Response. Service workers executam apenas quando necessário e podem ser terminados pelo navegador para economizar memória.

html
// sw.js - Cache assets for offline use
const CACHE_NAME = "my-app-v1";
const ASSETS = ["/", "/index.html", "/style.css", "/app.js"];

// Install: cache core assets
self.addEventListener("install", (e) => {
  e.waitUntil(
    caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS))
  );
});

// Fetch: serve from cache, fall back to network
self.addEventListener("fetch", (e) => {
  e.respondWith(
    caches.match(e.request).then((cached) => {
      return cached || fetch(e.request);
    })
  );
});

// Activate: clean old caches
self.addEventListener("activate", (e) => {
  e.waitUntil(
    caches.keys().then((keys) =>
      Promise.all(
        keys.filter((k) => k !== CACHE_NAME)
            .map((k) => caches.delete(k))
      )
    )
  );
});

Web App Manifest

O Web App Manifest é um arquivo JSON que torna uma web app instalável (Adicionar à Tela Inicial). name é o nome completo; short_name aparece no ícone da tela inicial. display:'standalone' oculta a UI do navegador, fazendo parecer um app nativo. theme_color afeta a cor do chrome do navegador. icons deve incluir pelo menos os tamanhos 192px e 512px. 'purpose':'maskable' permite ao Android adaptar o ícone a formas diferentes. Um manifest válido mais um service worker registrado são os requisitos mínimos para um PWA. Teste com Lighthouse para conformidade PWA.

html
<!-- Link the manifest in HTML -->
<link rel="manifest" href="manifest.json">

<!-- manifest.json -->
{
  "name": "My PWA App",
  "short_name": "MyApp",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#1976d2",
  "orientation": "portrait",
  "icons": [
    {
      "src": "/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icon-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

Notificações Push

Notificações push permitem reengajar usuários mesmo quando a aba está fechada. Primeiro solicite permissão com Notification.requestPermission(). Então inscreva via PushManager — o objeto de inscrição contém uma URL de endpoint e chaves. Envie esta inscrição ao seu servidor, que a usa para enviar mensagens push via Web Push API (com chaves VAPID para autenticação). O handler de evento push do service worker exibe a notificação. userVisibleOnly:true significa que todo push deve mostrar uma notificação (sem pushes silenciosos). Requer HTTPS e um service worker.

html
<!-- Request notification permission -->
<button onclick="subscribe()">Enable Notifications</button>

<script>
async function subscribe() {
  const permission = await Notification.requestPermission();
  if (permission !== "granted") return;

  const reg = await navigator.serviceWorker.ready;
  const subscription = await reg.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(VAPID_KEY)
  });
  // Send subscription to your server
  await fetch("/api/subscribe", {
    method: "POST",
    body: JSON.stringify(subscription)
  });
}
</script>

<!-- In sw.js: handle push events -->
self.addEventListener("push", (e) => {
  const data = e.data.json();
  e.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: "/icon-192.png",
      badge: "/badge.png"
    })
  );
});

Background Sync

Background Sync permite adiar ações até que o usuário tenha conectividade estável. Quando você registra um evento de sync, o navegador o dispara quando a conectividade é restaurada — mesmo se o usuário fechou a aba. O handler do evento sync (no service worker) realiza o trabalho adiado. Se o trabalho lançar um erro, o navegador tenta novamente automaticamente com backoff exponencial. e.tag identifica o tipo de sync — apenas um sync por tag é enfileirado. Use IndexedDB para armazenar dados pendentes. Isso é ideal para apps de mensagens, envio de formulários e sincronização de dados. Periodic Sync (para atualizações regulares) está disponível no Chrome, mas não em todos os navegadores.

html
// Register a sync event from the page
navigator.serviceWorker.ready.then((reg) => {
  return reg.sync.register("send-messages");
});

// Handle sync in sw.js
self.addEventListener("sync", (e) => {
  if (e.tag === "send-messages") {
    e.waitUntil(sendPendingMessages());
  }
});

async function sendPendingMessages() {
  const messages = await getMessagesFromIndexedDB();
  for (const msg of messages) {
    try {
      await fetch("/api/messages", {
        method: "POST",
        body: JSON.stringify(msg)
      });
      await deleteMessageFromIndexedDB(msg.id);
    } catch (err) {
      throw err; // triggers retry
    }
  }
}
17

Aprofundamento em Meta Tags (Open Graph & Twitter)

Tags Open Graph (Facebook)

As tags Open Graph (OG) controlam como sua página aparece quando compartilhada no Facebook, LinkedIn e na maioria das plataformas sociais. og:title é o título; og:description é o resumo; og:image é a imagem de pré-visualização (recomendado 1200x630px). og:type (website, article, video.movie) afeta a renderização. Para artigos, adicione article:published_time, article:author e article:section para pré-visualizações mais ricas. Sempre especifique dimensões de og:image para renderização mais rápida. Teste com o Sharing Debugger do Facebook. Tags OG são essenciais para marketing em mídias sociais e taxas de cliques.

html
<head>
  <meta property="og:title" content="My Awesome Article">
  <meta property="og:description" content="A deep dive into modern web development.">
  <meta property="og:type" content="article">
  <meta property="og:url" content="https://example.com/article">
  <meta property="og:image" content="https://example.com/img/og.jpg">
  <meta property="og:image:width" content="1200">
  <meta property="og:image:height" content="630">
  <meta property="og:site_name" content="My Website">
  <meta property="og:locale" content="en_US">
  <meta property="article:published_time" content="2025-01-15T08:00:00Z">
  <meta property="article:author" content="Jane Doe">
</head>

Tags Twitter Card

As tags Twitter Card controlam como os links aparecem no X (Twitter). O tipo twitter:card pode ser 'summary' (imagem pequena), 'summary_large_image' (imagem grande acima do texto), 'player' (vídeo/áudio) ou 'app'. twitter:site é o @handle do site; twitter:creator é o @handle do autor. A imagem deve ter pelo menos 300x157px (summary) ou 600x314px (large image). twitter:image:alt melhora a acessibilidade. Teste com o Card Validator do Twitter. Mesmo que você tenha tags OG, adicionar tags específicas do Twitter dá mais controle sobre as pré-visualizações no Twitter.

html
<head>
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:site" content="@mywebsite">
  <meta name="twitter:creator" content="@janedoe">
  <meta name="twitter:title" content="My Awesome Article">
  <meta name="twitter:description" content="A deep dive into modern web dev.">
  <meta name="twitter:image" content="https://example.com/img/twitter.jpg">
  <meta name="twitter:image:alt" content="Article cover image">
</head>

Viewport & Meta Mobile

A meta tag viewport é crítica para design responsivo — sem ela, navegadores móveis renderizam páginas na largura de desktop e diminuem o zoom. width=device-width corresponde à largura do dispositivo; initial-scale=1 define o nível de zoom. Evite desabilitar o zoom do usuário (user-scalable=no) pois viola as diretrizes de acessibilidade WCAG. apple-mobile-web-app-capable torna o app em tela cheia quando adicionado à tela inicial do iOS. theme-color afeta a cor da barra de endereços do navegador no Chrome e Safari móvel. Essas tags específicas para mobile melhoram significativamente a experiência PWA e móvel.

html
<head>
  <!-- Responsive viewport -->
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0">

  <!-- Disable zoom (accessibility concern — avoid) -->
  <meta name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

  <!-- iOS Safari: full-screen web app -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style"
        content="black-translucent">
  <meta name="apple-mobile-web-app-title" content="MyApp">

  <!-- Android Chrome theme color -->
  <meta name="theme-color" content="#1976d2">
</head>

HTTP-Equiv & Charset

Meta tags http-equiv simulam cabeçalhos HTTP diretamente no HTML. charset deve ser o primeiro elemento em <head> e dentro dos primeiros 1024 bytes para evitar ataques XSS baseados em codificação. http-equiv='refresh' redireciona após um atraso — prefira redirecionamentos server-side para SEO. Content-Security-Policy via meta é limitado (sem report-uri, sem frame-ancestors) — prefira cabeçalhos HTTP. Cache-Control via meta é não confiável — use cabeçalhos HTTP. X-UA-Compatible força o IE a usar seu motor de renderização mais recente. Sempre prefira cabeçalhos HTTP reais em vez de http-equiv quando possível.

html
<head>
  <!-- Character encoding (must be first in head) -->
  <meta charset="UTF-8">

  <!-- Refresh/redirect after 5 seconds -->
  <meta http-equiv="refresh" content="5; url=https://example.com">

  <!-- Set content security policy -->
  <meta http-equiv="Content-Security-Policy"
        content="default-src 'self'; script-src 'self'">

  <!-- X-UA-Compatible for IE -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">

  <!-- Cache control -->
  <meta http-equiv="Cache-Control"
        content="no-cache, no-store, must-revalidate">
</head>

Dados Estruturados (JSON-LD)

JSON-LD (JavaScript Object Notation for Linked Data) é o formato recomendado pelo Google para dados estruturados. Ajuda os motores de busca a entender seu conteúdo, permitindo rich snippets (avaliações com estrelas, datas de eventos, breadcrumbs, accordions de FAQ) nos resultados de busca. Tipos comuns incluem Article, Product, Recipe, Event, LocalBusiness e FAQPage. Coloque o script no <head> com type='application/ld+json'. Valide com o Rich Results Test do Google. Dados estruturados não garantem rich snippets, mas tornam você elegível. É uma poderosa ferramenta de SEO para aumentar taxas de cliques nos resultados de busca.

html
<head>
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "My Awesome Article",
    "author": {
      "@type": "Person",
      "name": "Jane Doe"
    },
    "datePublished": "2025-01-15",
    "image": "https://example.com/img/article.jpg",
    "publisher": {
      "@type": "Organization",
      "name": "My Website",
      "logo": {
        "@type": "ImageObject",
        "url": "https://example.com/logo.png"
      }
    }
  }
  </script>
</head>
18

Aprofundamento em HTML Semântico

Article vs Section vs Div

Escolher o elemento contêiner certo importa para acessibilidade e SEO. <article> é para conteúdo que poderia ser distribuído independentemente (posts de blog, notícias, comentários, cards de produto). <section> agrupa conteúdo tematicamente relacionado — deve sempre ter um título. <div> é o último recurso para layout/estilização quando nenhum elemento semântico se encaixa. Elementos <article> aninhados (como comentários dentro de um post) são válidos. A regra prática: se o conteúdo poderia ser sindicado via RSS, use <article>; se é um capítulo temático, use <section>; se é puramente para layout, use <div>.

html
<!-- <article>: self-contained, syndicable content -->
<article>
  <h2>Blog Post Title</h2>
  <p>Content that makes sense on its own...</p>
  <article><h3>Comment 1</h3><p>...</p></article>
</article>

<!-- <section>: thematic grouping with a heading -->
<section>
  <h2>Chapter 1: Introduction</h2>
  <p>Related content...</p>
</section>

<!-- <div>: generic container, no semantic meaning -->
<div class="layout-wrapper">
  <div class="grid-item">Styling hook only</div>
</div>

Figure & Figcaption

<figure> representa conteúdo autocontido referenciado a partir do texto principal — imagens, diagramas, listagens de código ou citações. <figcaption> fornece uma legenda/título. Diferente de um <img> simples, figure/figcaption vincula semanticamente o visual à sua descrição. Leitores de tela anunciam figuras com suas legendas. Figuras podem ser posicionadas em qualquer lugar relativo ao texto que as referencia. Use <figure> para qualquer conteúdo que tenha uma legenda e seja referenciado por número (Figura 1, Listagem 1). Para imagens puramente decorativas, use um <img> simples com alt vazio.

html
<figure>
  <img src="chart.png" alt="Sales growth chart showing 40% increase">
  <figcaption>
    Figure 1: Quarterly sales growth from Q1 to Q4 2025.
    Data source: Internal sales database.
  </figcaption>
</figure>

<!-- Figure can contain code blocks too -->
<figure>
  <pre><code>const x = 42;</code></pre>
  <figcaption>Listing 1: Variable declaration example</figcaption>
</figure>

Details & Summary (Disclosure)

<details> e <summary> criam seções colapsáveis (accordion) nativas sem qualquer JavaScript. Clicar no <summary> alterna o conteúdo. O atributo open o torna expandido por padrão. O evento toggle dispara quando expandido/colapsado. Isso é excelente para FAQs, painéis de configurações e disclosure progressivo. Leitores de tela o anunciam como um widget de disclosure. Você pode estilizar o marcador triangular padrão com CSS (summary::-webkit-details-marker ou list-style). Para interações complexas, você ainda pode precisar de JavaScript, mas para toggles simples, esta solução nativa é ideal.

html
<!-- Native collapsible without JavaScript -->
<details>
  <summary>Click to expand FAQ</summary>
  <p>Here is the hidden answer that appears when expanded.</p>
</details>

<!-- Open by default -->
<details open>
  <summary>Already expanded</summary>
  <p>This content is visible on page load.</p>
</details>

<!-- Nested disclosures -->
<details>
  <summary>Level 1</summary>
  <details>
    <summary>Level 2</summary>
    <p>Deeply nested content</p>
  </details>
</details>

Elementos Time & Mark

<time> envolve datas/horas legíveis por humanos com um atributo datetime legível por máquina no formato ISO 8601. Isso ajuda motores de busca, calendários e tecnologias assistivas a analisar datas corretamente. datetime suporta datas (YYYY-MM-DD), horas (HH:MM), datetimes com fuso horário e durações (PT2H30M). <mark> representa texto destacado por relevância, como correspondências de termos de busca. Diferente de <strong> ou <em> (que indicam importância/ênfase), <mark> indica relevância contextual. Ambos os elementos melhoram o significado semântico e SEO.

html
<!-- <time>: machine-readable dates/times -->
<p>Published on
  <time datetime="2025-01-15">January 15, 2025</time>
</p>
<p>Event at
  <time datetime="2025-03-20T14:30-05:00">2:30 PM EST</time>
</p>
<p>Duration:
  <time datetime="PT2H30M">2 hours 30 minutes</time>
</p>

<!-- <mark>: highlighted/relevant text -->
<p>Search results: the keyword
  <mark>HTML5</mark> appears in 3 documents.
</p>

Elemento Dialog

O elemento <dialog> fornece diálogos modais e não-modais nativos sem bibliotecas. showModal() o abre como modal (com backdrop, bloqueia interação com a página); show() o abre não-modalmente. close() o fecha. form method='dialog' fecha o diálogo no envio, com o valor do botão como returnValue. O pseudo-elemento ::backdrop estiliza a sobreposição modal. A tecla ESC fecha diálogos modais automaticamente. A renderização na top layer significa que o diálogo aparece acima de todo o outro conteúdo, independentemente do z-index. O evento close dispara após o fechamento. Isso é agora bem suportado e substitui muitas bibliotecas de modal JavaScript.

html
<!-- Native modal dialog -->
<dialog id="myDialog">
  <h2>Confirm Action</h2>
  <p>Are you sure you want to proceed?</p>
  <form method="dialog">
    <button value="cancel">Cancel</button>
    <button value="confirm">Confirm</button>
  </form>
</dialog>

<button onclick="document.getElementById('myDialog').showModal()">
  Open Modal
</button>

<script>
const dialog = document.getElementById("myDialog");
dialog.addEventListener("close", () => {
  console.log("Dialog closed with:", dialog.returnValue);
});
// Close on backdrop click
dialog.addEventListener("click", (e) => {
  if (e.target === dialog) dialog.close();
});
</script>
19

Formulários e Inputs Avançados

Fieldset & Legend

<fieldset> agrupa controles de formulário relacionados, e <legend> fornece uma legenda para o grupo. Isso é crucial para acessibilidade — leitores de tela anunciam a legenda antes de cada controle no grupo, fornecendo contexto. O atributo disabled em um fieldset desabilita todos os controles dentro dele. Fieldsets também melhoram a organização visual com uma borda padrão. Para radio buttons, fieldset/legend é a maneira recomendada de rotular o grupo. Evite aninhar fieldsets muito profundamente, pois pode confundir usuários de leitores de tela.

html
<form>
  <fieldset>
    <legend>Shipping Address</legend>
    <label>Street: <input type="text" name="street" required></label>
    <label>City: <input type="text" name="city" required></label>
    <label>ZIP: <input type="text" name="zip" pattern="[0-9]{5}"></label>
  </fieldset>

  <fieldset disabled>
    <legend>Billing (same as shipping)</legend>
    <label>Card: <input type="text" name="card"></label>
  </fieldset>

  <fieldset>
    <legend>Subscription Plan</legend>
    <label><input type="radio" name="plan" value="free"> Free</label>
    <label><input type="radio" name="plan" value="pro" checked> Pro</label>
  </fieldset>
</form>

Elementos Output & Progress

<output> exibe o resultado de um cálculo — tem uma relação dinâmica com inputs de formulário (via atributo for). É semanticamente mais significativo que um span para valores calculados. <progress> representa a conclusão de uma tarefa (value/max); sem um valor, mostra um spinner indeterminado. <meter> representa um valor escalar dentro de um intervalo conhecido (como espaço em disco ou pontuações de teste) — os atributos low, high e optimum definem limiares que afetam a cor (verde/amarelo/vermelho). Tanto progress quanto meter têm estilização embutida que varia por navegador, mas pode ser personalizada com CSS.

html
<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
  <input type="number" id="a" value="10"> +
  <input type="number" id="b" value="20"> =
  <output name="result" for="a b">30</output>
</form>

<!-- Progress bar -->
<label>Downloading: <progress id="prog" value="70" max="100">70%</progress></label>

<!-- Meter (gauge within a range) -->
<label>Disk usage: <meter value="0.6" min="0" max="1" low="0.5" high="0.8" optimum="0.2">60%</meter></label>
<label>Score: <meter value="85" min="0" max="100" low="40" high="70" optimum="90">85</meter></label>

Autocomplete de Formulário

O atributo autocomplete ajuda os navegadores a preencher formulários usando dados armazenados do usuário. Use tokens padronizados: 'name', 'email', 'tel', 'street-address', 'address-level2' (cidade), 'postal-code', 'country'. Para cartões de crédito: 'cc-name', 'cc-number', 'cc-exp'. autocomplete='off' desabilita o autopreenchimento (embora navegadores possam ignorar isso para campos não sensíveis). autocomplete='one-time-code' aciona o autopreenchimento de código SMS no mobile. Tokens de autocomplete adequados melhoram drasticamente as taxas de conclusão de formulário e a experiência do usuário. Eles também ajudam gerenciadores de senhas a identificar campos corretamente.

html
<form autocomplete="on">
  <!-- Browser can autofill name -->
  <label>Name: <input type="text" name="name" autocomplete="name"></label>

  <!-- Email autofill -->
  <label>Email: <input type="email" name="email" autocomplete="email"></label>

  <!-- Address autofill tokens -->
  <fieldset>
    <legend>Address</legend>
    <input autocomplete="street-address">
    <input autocomplete="address-level2"> <!-- City -->
    <input autocomplete="postal-code">
    <input autocomplete="country">
  </fieldset>

  <!-- Disable autocomplete for sensitive field -->
  <label>SSN: <input type="text" autocomplete="off"></label>

  <!-- One-time code (SMS) -->
  <label>Code: <input type="text" autocomplete="one-time-code"></label>
</form>

Métodos de Envio de Formulário

GET anexa dados do formulário à URL (visível, bookmarkável, comprimento limitado) — use para buscas e filtros. POST envia dados no corpo da requisição (não visível, sem limite de comprimento) — use para criar/atualizar dados. enctype='multipart/form-data' é necessário para uploads de arquivos. O par nome/valor do botão é incluído no envio — múltiplos botões de envio podem acionar diferentes ações via mesmo nome com valores diferentes. Para envio via AJAX, use o objeto FormData e fetch(). Sempre use POST para dados sensíveis, pois dados GET aparecem no histórico do navegador e logs do servidor.

html
<!-- GET: data in URL query string -->
<form method="GET" action="/search">
  <input name="q" value="html5">
  <!-- URL: /search?q=html5 -->
</form>

<!-- POST: data in request body -->
<form method="POST" action="/submit" enctype="application/x-www-form-urlencoded">
  <input name="name" value="Alice">
</form>

<!-- File upload: multipart -->
<form method="POST" action="/upload" enctype="multipart/form-data">
  <input type="file" name="document">
</form>

<!-- Form with custom submit button -->
<form method="POST" action="/save">
  <button type="submit" name="action" value="save">Save</button>
  <button type="submit" name="action" value="publish">Publish</button>
</form>

Contenteditable & Spellcheck

contenteditable='true' torna qualquer elemento diretamente editável no navegador — a base de editores de rich text. spellcheck='true' habilita a verificação ortográfica do navegador (sublinhado vermelho para erros). Para snippets de código, defina spellcheck='false' para evitar falsos positivos. O atributo contenteditable pode ser herdado — elementos filhos são editáveis a menos que definidos como 'false'. Salvar conteúdo editável requer JavaScript (ex.: armazenar em localStorage no input). Construir um editor de rich text completo com contenteditable é complexo (tratamento de paste, formatação, posição do cursor) — considere bibliotecas como Quill, TipTap ou ProseMirror para uso em produção.

html
<!-- Editable div -->
<div contenteditable="true">
  Click to edit this text directly in the browser.
</div>

<!-- Editable with spellcheck -->
<p contenteditable="true" spellcheck="true">
  Typoos will be underlined in red.
</p>

<!-- Turn off spellcheck for code -->
<pre contenteditable="true" spellcheck="false">
  const varible = "code"; // no spellcheck
</pre>

<!-- Entire document editable -->
<body contenteditable="true">

<!-- Save editable content -->
<div id="note" contenteditable="true"
     oninput="localStorage.setItem('note', this.innerHTML)">
  <script>document.getElementById('note').innerHTML =
    localStorage.getItem('note') || '';</script>
</div>
20

Meta Tags SEO

Tags Open Graph

As tags Open Graph (criadas pelo Facebook) controlam como sua página aparece quando compartilhada em mídias sociais. og:image deve ter 1200x630px. Sem essas tags, as plataformas inventam pré-visualizações a partir do conteúdo da página, frequentemente de forma ruim.

html
<meta property="og:title" content="My Awesome Article">
<meta property="og:description" content="A deep dive into modern web design.">
<meta property="og:image" content="https://example.com/cover.jpg">
<meta property="og:url" content="https://example.com/article">
<meta property="og:type" content="article">
<meta property="og:site_name" content="Example Site">

Twitter Cards

As tags Twitter Card controlam como os links são renderizados no X/Twitter. summary_large_image mostra uma imagem proeminente acima do título; summary mostra uma miniatura quadrada menor. A tag twitter:site vincula o card à sua conta.

html
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@yoursite">
<meta name="twitter:title" content="My Article">
<meta name="twitter:description" content="A deep dive into web design.">
<meta name="twitter:image" content="https://example.com/cover.jpg">

Canonical & Robots

rel="canonical" evita penalidades por conteúdo duplicado apontando para a URL master. A meta tag robots direciona crawlers: noindex remove a página dos resultados, nofollow bloqueia o seguimento de links.

html
<!-- Canonical: tells search engines the preferred URL -->
<link rel="canonical" href="https://example.com/article">

<!-- Robots: control indexing -->
<meta name="robots" content="index, follow">
<meta name="robots" content="noindex, nofollow">
<meta name="robots" content="noindex, follow">

Dados Estruturados (JSON-LD)

Dados estruturados JSON-LD ajudam motores de busca a entender o conteúdo e habilitam rich results (avaliações com estrelas, breadcrumbs, informações de eventos). Schema.org define o vocabulário. Coloque a tag script dentro do head ou body.

html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Modern Web Design",
  "author": { "@type": "Person", "name": "Jane Doe" },
  "datePublished": "2025-01-15",
  "image": "https://example.com/cover.jpg"
}
</script>

Meta Description & Viewport

A meta tag description influencia a taxa de cliques — mantenha-a abaixo de 160 caracteres. A tag viewport é obrigatória para design responsivo em mobile. theme-color estiliza a barra de UI do navegador. charset deve ser o primeiro elemento no head.

html
<meta name="description" content="A concise 150-160 character summary that appears in search results.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#4285f4">
<meta charset="UTF-8">
21

SVG Básico

Formas Básicas

SVG desenha com elementos XML. As formas incluem rect, circle, ellipse, line, polyline e polygon. Diferente de imagens raster, SVGs escalam sem perda de qualidade e podem ser estilizados com CSS. fill define a cor do interior, stroke define o contorno.

html
<svg width="200" height="150" xmlns="http://www.w3.org/2000/svg">
  <rect x="10" y="10" width="80" height="50" fill="steelblue"/>
  <circle cx="140" cy="40" r="30" fill="tomato"/>
  <line x1="10" y1="100" x2="180" y2="100" stroke="black" stroke-width="2"/>
  <ellipse cx="100" cy="120" rx="60" ry="20" fill="none" stroke="green"/>
</svg>

Paths

O elemento path é a primitiva SVG mais poderosa. Comandos: M (mover), L (linha), H/V (horizontal/vertical), C (cúbica bezier), Q (quadrática), A (arco), Z (fechar). Maiúsculas = coordenadas absolutas, minúsculas = relativas.

html
<svg width="200" height="200">
  <!-- M=move, L=line, C=cubic bezier, Z=close -->
  <path d="M 10 10 L 100 10 L 100 100 Z" fill="none" stroke="black"/>
  <path d="M 10 150 C 50 50, 150 50, 190 150" stroke="red" fill="none"/>
  <path d="M 10 180 Q 100 120 190 180" stroke="blue" fill="none"/>
</svg>

Grupos & Reutilização

Agrupe elementos com g para aplicar atributos compartilhados ou transformá-los juntos. Defina formas reutilizáveis dentro de defs e referencie-as com use href="#id". Isso mantém os SVGs DRY e menores.

html
<svg width="200" height="200">
  <defs>
    <g id="star">
      <polygon points="50,5 61,39 98,39 68,61 79,95 50,75 21,95 32,61 2,39 39,39"/>
    </g>
  </defs>
  <use href="#star" x="0" y="0" fill="gold"/>
  <use href="#star" x="100" y="100" fill="orange"/>
</svg>

Texto & Estilização

Texto SVG é texto real — selecionável, pesquisável e nítido em qualquer escala. font-family, font-size, font-weight espelham o CSS. text-anchor controla o alinhamento horizontal (start/middle/end).

html
<svg width="300" height="100">
  <text x="10" y="50" font-family="Arial" font-size="24" fill="navy">
    Hello SVG
  </text>
  <text x="150" y="80" font-size="16" font-weight="bold" text-anchor="middle">
    Centered Bold Text
  </text>
</svg>

Gradientes & Padrões

Gradientes são definidos em defs e referenciados via fill="url(#id)". linearGradient transita ao longo de uma linha; radialGradient irradia a partir de um ponto central. Cada stop define uma cor em um offset percentual.

html
<svg width="200" height="100">
  <defs>
    <linearGradient id="lg" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" stop-color="red"/>
      <stop offset="100%" stop-color="blue"/>
    </linearGradient>
    <radialGradient id="rg">
      <stop offset="0%" stop-color="yellow"/>
      <stop offset="100%" stop-color="green"/>
    </radialGradient>
  </defs>
  <rect width="100" height="100" fill="url(#lg)"/>
  <rect x="100" width="100" height="100" fill="url(#rg)"/>
</svg>
22

Canvas

Desenhando Formas

A Canvas API desenha pixels em um elemento canvas via um contexto de renderização 2D. fillRect/strokeRect desenham retângulos; paths (beginPath, arc, lineTo) constroem formas complexas antes de fill() ou stroke(). Canvas é raster — escalar desfoca o desenho.

html
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');

ctx.fillStyle = 'tomato';
ctx.fillRect(10, 10, 100, 50);

ctx.strokeStyle = 'navy';
ctx.lineWidth = 3;
ctx.strokeRect(130, 10, 80, 80);

ctx.beginPath();
ctx.arc(200, 150, 40, 0, Math.PI * 2);
ctx.fill();

Paths & Linhas

Paths constroem formas ponto a ponto. moveTo inicia um novo sub-path; lineTo adiciona segmentos retos; closePath conecta ao início. bezierCurveTo e quadraticCurveTo desenham curvas com pontos de controle.

html
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(150, 50);
ctx.lineTo(100, 150);
ctx.closePath();
ctx.fillStyle = 'gold';
ctx.fill();
ctx.stroke();

// Bezier curves
ctx.beginPath();
ctx.moveTo(0, 200);
ctx.bezierCurveTo(100, 100, 200, 300, 300, 200);
ctx.stroke();

Desenhando Imagens

drawImage pinta uma imagem, vídeo ou outro canvas. A forma de 9 argumentos recorta um retângulo de origem e o pinta em um retângulo de destino — útil para sprite sheets. Aguarde o onload antes de desenhar.

html
const img = new Image();
img.src = 'photo.jpg';
img.onload = () => {
  ctx.drawImage(img, 0, 0);                    // full image
  ctx.drawImage(img, 0, 0, 200, 150);          // scaled
  ctx.drawImage(img, 50, 50, 100, 100, 300, 0, 100, 100); // cropped
};

Loop de Animação

requestAnimationFrame agenda draw() uma vez por repaint do navegador (~60fps), pausando quando a aba está oculta. clearRect limpa o canvas a cada quadro para evitar rastros. Para física, multiplique o movimento pelo delta time para velocidade consistente.

html
let x = 0;
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = 'steelblue';
  ctx.fillRect(x, 50, 40, 40);
  x += 2;
  if (x > canvas.width) x = -40;
  requestAnimationFrame(draw);
}
requestAnimationFrame(draw);

Manipulação de Pixels

getImageData retorna um Uint8ClampedArray de valores de pixel RGBA brutos (0-255 por canal). Acesso direto a pixels habilita filtros e efeitos. putImageData grava o buffer modificado de volta. Isso é lento para canvases grandes.

html
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data; // RGBA bytes

for (let i = 0; i < data.length; i += 4) {
  const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
  data[i] = data[i + 1] = data[i + 2] = avg; // grayscale
}

ctx.putImageData(imageData, 0, 0);
23

Iframes & Embeds

Básico de Iframe

Um iframe incorpora outro documento dentro da página atual. O atributo title é obrigatório para acessibilidade. loading="lazy" adia o carregamento até próximo do viewport. Sempre defina width e height para evitar layout shift.

html
<iframe
  src="https://example.com/widget"
  width="600"
  height="400"
  title="Example Widget"
  loading="lazy"
  referrerpolicy="no-referrer">
</iframe>

Atributo Sandbox

O atributo sandbox restringe as capacidades de um iframe. Um valor vazio bloqueia tudo. Adicione tokens para reabilitar recursos: allow-scripts, allow-forms, allow-same-origin, allow-popups. Nunca combine allow-scripts com allow-same-origin para conteúdo não confiável.

html
<!-- Locks down the iframe completely -->
<iframe src="untrusted.html" sandbox></iframe>

<!-- Selectively re-enable features -->
<iframe
  src="widget.html"
  sandbox="allow-scripts allow-same-origin allow-forms">
</iframe>

Embed & Object

embed e object são elementos legados. object suporta conteúdo de fallback exibido quando o recurso falha. Elementos HTML5 modernos (video, audio, picture) são preferidos. Use iframe para conteúdo HTML, video para vídeo.

html
<!-- Embed for plugins/media -->
<embed src="video.mp4" type="video/mp4" width="400" height="300">

<!-- Object with fallback content -->
<object data="report.pdf" type="application/pdf" width="100%" height="600">
  <p>Your browser cannot display PDFs. <a href="report.pdf">Download</a></p>
</object>

<!-- Video with multiple sources -->
<video controls>
  <source src="movie.webm" type="video/webm">
  <source src="movie.mp4" type="video/mp4">
  Your browser does not support video.
</video>

Comunicação postMessage

postMessage é a única maneira de comunicar através de fronteiras de iframe (origens diferentes). Sempre especifique a origem de destino no terceiro argumento. No lado receptor, verifique e.origin antes de confiar na mensagem.

html
<!-- Parent page -->
<iframe id="f" src="child.html"></iframe>
<script>
  const frame = document.getElementById('f');
  frame.contentWindow.postMessage({ type: 'greet', text: 'Hi' }, 'https://example.com');

  window.addEventListener('message', (e) => {
    if (e.origin !== 'https://example.com') return;
    console.log('From child:', e.data);
  });
</script>

Iframes Responsivos

Para tornar iframes responsivos (ex.: vídeo 16:9), envolva-os em um contêiner com padding-bottom igual à porcentagem da proporção (56,25% para 16:9). Posicione o iframe absolutamente para preencher o contêiner.

html
<div style="position:relative; padding-bottom:56.25%; height:0; overflow:hidden;">
  <iframe
    src="https://youtube.com/embed/abc"
    style="position:absolute; top:0; left:0; width:100%; height:100%; border:0;"
    title="Video"
    allowfullscreen>
  </iframe>
</div>
24

Otimização de Performance

Resource Hints

Resource hints dizem ao navegador para preparar conexões ou buscar assets antes que sejam necessários. preconnect aquece DNS/TCP/TLS. preload busca assets críticos da página atual antecipadamente. prefetch busca recursos da próxima página durante o tempo ocioso.

html
<!-- Preconnect to a third-party origin -->
<link rel="preconnect" href="https://fonts.googleapis.com">

<!-- DNS prefetch for lower-priority origins -->
<link rel="dns-prefetch" href="https://analytics.example.com">

<!-- Preload critical assets -->
<link rel="preload" href="hero.webp" as="image">
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

<!-- Prefetch next page -->
<link rel="prefetch" href="/next-page.html">

Lazy Loading de Imagens

loading="lazy" adia o carregamento de imagens fora da tela até o usuário rolar próximo a elas. Sempre defina width e height para evitar layout shift. O elemento picture serve formatos modernos (WebP/AVIF) com fallback JPG.

html
<!-- Native lazy loading -->
<img src="photo.jpg" loading="lazy" width="800" height="600" alt="...">

<!-- Picture with responsive sources -->
<picture>
  <source srcset="small.webp" media="(max-width: 600px)" type="image/webp">
  <source srcset="large.webp" type="image/webp">
  <img src="large.jpg" loading="lazy" width="1200" height="800" alt="...">
</picture>

Estratégias de Carregamento de Script

Sem atributos, um script bloqueia a análise do HTML. async baixa em paralelo, mas executa imediatamente quando pronto — ordem não garantida. defer baixa em paralelo e executa em ordem após o DOM ser analisado — melhor para scripts principais.

html
<!-- Normal: blocks HTML parsing -->
<script src="app.js"></script>

<!-- Async: downloads in parallel, runs ASAP -->
<script src="analytics.js" async></script>

<!-- Defer: downloads in parallel, runs after HTML parse -->
<script src="app.js" defer></script>

<!-- Module scripts defer by default -->
<script type="module" src="app.mjs"></script>

CSS Crítico

Inserir CSS crítico (estilos necessários para conteúdo above-the-fold) elimina requisições CSS de bloqueio de renderização, acelerando o first paint. O CSS restante carrega assincronamente via truque preload. Ferramentas como Critical extraem CSS crítico automaticamente.

html
<!-- Inline above-the-fold CSS in head -->
<head>
  <style>
    body { margin: 0; font-family: sans-serif; }
    .hero { height: 100vh; background: #f0f0f0; }
  </style>
  <!-- Load the rest asynchronously -->
  <link rel="preload" href="full.css" as="style" onload="this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="full.css"></noscript>
</head>

Medindo Performance

A Performance API mede o timing real do usuário. Métricas chave: FCP (First Contentful Paint), LCP (Largest Contentful Paint), CLS (Cumulative Layout Shift), INP (Interaction to Next Paint). Use Lighthouse para dados de laboratório.

html
// PerformanceObserver for Core Web Vitals
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(entry.name, entry.startTime);
  }
}).observe({ entryTypes: ['paint', 'largest-contentful-paint'] });

// Navigation timing
const [nav] = performance.getEntriesByType('navigation');
console.log('DOM Content Loaded:', nav.domContentLoadedEventEnd);
console.log('Load:', nav.loadEventEnd);
25

Formulários Avançados

Input Types

Os input types do HTML5 fornecem validação e UI embutidas. email/url validam formato. number/date fornecem pickers. color/range têm UI especializada. accept filtra tipos de arquivo. Navegadores tratam a validação automaticamente.

html
<input type="email" required>
<input type="url" placeholder="https://">
<input type="number" min="0" max="100" step="5">
<input type="date" min="2024-01-01">
<input type="color" value="#ff0000">
<input type="range" min="0" max="10">
<input type="file" accept="image/*">

Validação de Formulário

required impede o envio se vazio. minlength/maxlength limitam o comprimento. pattern usa validação regex. O navegador impede o envio e mostra erros. Personalize com setCustomValidity e o evento invalid.

html
<form>
  <input type="text" required minlength="3" maxlength="20" pattern="[A-Za-z]+">
  <input type="email" required>
  <input type="submit" value="Submit">
</form>

Fieldset & Legend

fieldset agrupa campos relacionados do formulário. legend fornece uma legenda. disabled em fieldset desabilita todos os campos. Melhora a acessibilidade agrupando inputs relacionados. Leitores de tela anunciam a legenda para cada campo.

html
<fieldset>
  <legend>Shipping Address</legend>
  <label>Street: <input type="text" name="street"></label>
  <label>City: <input type="text" name="city"></label>
</fieldset>
<fieldset disabled>
  <legend>Billing (disabled)</legend>
  <input type="text" name="billing">
</fieldset>

Datalist

datalist fornece sugestões de autocomplete para input. Usuários podem selecionar ou digitar livremente. Diferente de select, permite valores personalizados. O atributo list vincula o input ao datalist por id. Útil para busca e tags.

html
<label>Choose browser:
  <input list="browsers" name="browser">
</label>
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
</datalist>

Elemento Output

output exibe resultados calculados. O atributo for vincula aos IDs de input. Atualiza dinamicamente com mudanças no formulário. Sem JavaScript necessário para cálculos simples. Acessível a leitores de tela como uma região dinâmica.

html
<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
  <input type="number" id="a" value="0"> +
  <input type="number" id="b" value="0"> =
  <output name="result" for="a b">0</output>
</form>
26

Acessibilidade (a11y)

Rótulos ARIA

aria-label fornece nomes acessíveis para elementos sem texto visível. aria-expanded indica estado de toggle. aria-controls vincula ao elemento controlado. Use ARIA apenas quando a semântica do HTML for insuficiente.

html
<button aria-label="Close menu" onclick="closeMenu()">
  <svg>...</svg>
</button>
<nav aria-label="Main navigation">...</nav>
<button aria-expanded="false" aria-controls="menu">Menu</button>

Papéis de Marco

Papéis de marco ajudam usuários de leitores de tela a navegar. A maioria dos elementos semânticos tem papéis implícitos. Adicione papéis explícitos apenas quando necessário. role="search" em um formulário cria um marco de busca. Evite redundância de role com elementos semânticos.

html
<header role="banner">...</header>
<nav role="navigation">...</nav>
<main role="main">...</main>
<aside role="complementary">...</aside>
<footer role="contentinfo">...</footer>
<form role="search">...</form>

Gerenciamento de Foco

Gerencie o foco para usuários de teclado. Ao abrir modais, mova o foco para dentro. Ao fechar, retorne o foco ao gatilho. Use tabindex="-1" para tornar elementos focáveis programaticamente. Nunca remova contornos de foco sem substituição.

html
<button id="open">Open</button>
<div id="modal" hidden>
  <button id="close">Close</button>
</div>
<script>
document.getElementById('open').onclick = () => {
  modal.hidden = false;
  document.getElementById('close').focus();
};
</script>

Links de Salto

Links de salto permitem que usuários de teclado ignorem navegação repetitiva. Ocultos visualmente até receberem foco. O href aponta para o ID do conteúdo principal. Essencial para conformidade de acessibilidade (WCAG). Melhora a eficiência de navegação.

html
<body>
  <a href="#main" class="skip-link">Skip to main content</a>
  <nav>...long navigation...</nav>
  <main id="main">...</main>
</body>
<style>
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: 0; }
</style>

Texto Alt

O texto alt descreve imagens para leitores de tela. Alt vazio="" marca imagens decorativas (ignoradas). Descreva o conteúdo e propósito, não aparência. Para imagens complexas, forneça uma descrição mais longa em outro lugar. Nunca use alt para tooltips (use title).

html
<!-- Informative image -->
<img src="chart.png" alt="Bar chart showing 30% increase in sales">
<!-- Decorative image -->
<img src="spacer.gif" alt="">
<!-- Complex image -->
<img src="diagram.png" alt="Network topology" longdesc="diagram-desc.html">
27

Armadilhas Comuns

Texto Alt Ausente

Texto alt ausente quebra a acessibilidade. Leitores de tela leem o nome do arquivo. "imagem" ou "foto" não ajudam. Descreva o conteúdo e propósito. Alt vazio="" marca imagens decorativas. Nunca pule o atributo alt inteiramente.

html
<!-- BAD: no alt -->
<img src="photo.jpg">
<!-- BAD: unhelpful alt -->
<img src="photo.jpg" alt="image">
<!-- GOOD: descriptive alt -->
<img src="photo.jpg" alt="Team meeting in conference room">
<!-- Decorative: empty alt -->
<img src="border.png" alt="">

Sopa de Divs

Usar divs para tudo remove o significado semântico. Leitores de tela não conseguem navegar. SEO não consegue entender a estrutura do conteúdo. Use elementos semânticos: header, nav, main, article, section, aside, footer. Reserve div para agrupamento sem intenção semântica.

html
<!-- BAD: div for everything -->
<div class="header">...</div>
<div class="nav">...</div>
<div class="article">...</div>
<!-- GOOD: semantic elements -->
<header>...</header>
<nav>...</nav>
<article>...</article>

Estilos Inline

Estilos inline misturam conteúdo e apresentação, dificultando a manutenção. Eles têm alta especificidade, sobrescrevendo stylesheets. Não podem ser armazenados em cache ou reutilizados. Use classes e stylesheets externas. Reserve estilos inline para valores dinâmicos.

html
<!-- BAD: inline styles -->
<div style="color: red; font-size: 16px;">Text</div>
<!-- GOOD: external CSS -->
<div class="error">Text</div>
<link rel="stylesheet" href="styles.css">

Botão vs Link

Botões acionam ações (salvar, excluir, alternar). Links navegam para URLs. Usar links para ações quebra a navegação por teclado (Space vs Enter) e semântica. Leitores de tela os anunciam de forma diferente. Use type="button" para evitar envio de formulário.

html
<!-- BAD: link for actions -->
<a href="#" onclick="save()">Save</a>
<!-- GOOD: button for actions -->
<button type="button" onclick="save()">Save</button>
<!-- Link for navigation -->
<a href="/about">About</a>

Hierarquia de Títulos

Títulos criam um esboço do documento. Não pule níveis (h1 para h3). Use um h1 por página (título principal). Usuários de leitores de tela navegam por títulos. Mantenha hierarquia lógica. Use CSS para estilização visual, não níveis de título.

html
<!-- BAD: skip levels -->
<h1>Title</h1>
<h3>Subtitle</h3>  <!-- Skipped h2 -->
<!-- BAD: multiple h1 -->
<h1>Title</h1>
<h1>Another</h1>
<!-- GOOD: hierarchical -->
<h1>Main Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>

Was this helpful?

Learning path

Learn from scratch

Learn this language from the ground up with structured lessons.