HTML · PARSER · DOM · CSSOM · PIXELS

Como o navegador transforma HTML em uma página

O navegador não desenha as tags diretamente. Ele interpreta caracteres, produz tokens, constrói uma árvore de objetos, calcula estilos e geometria e só então produz pixels.

Imagem: Guoyunhe / Wikimedia Commons, CC BY-SA 3.0

DO TEXTO À ESTRUTURA

O HTML chega como caracteres; o parser produz e conecta nós.

Depois de receber e decodificar os bytes da resposta, o navegador entrega um fluxo de caracteres ao parser HTML. O tokenizer reconhece construções como tag inicial, tag final, comentário e texto. O tree builder interpreta esses tokens segundo as regras do HTML e modifica progressivamente um objeto Document.

Laboratório visual · Construindo a árvore DOM

Avance pelo documento e observe quais linhas originam elementos, textos e atributos.

árvore incremental
Seu navegador não suporta canvas.
Etapa 1 de 7

Documento e raiz: o parser cria o Document, registra o doctype e insere o elemento html. O atributo lang pertence ao elemento; ele não se torna um filho separado.

  1. Bytes são decodificados. O charset determina como os bytes viram caracteres. Em HTML moderno, declare <meta charset="UTF-8"> cedo no documento.
  2. O tokenizer reconhece unidades sintáticas. <main> gera um token de tag inicial; “Livros” gera caracteres; </main> gera uma tag final.
  3. O tree builder mantém contexto. Uma pilha de elementos abertos ajuda a decidir de quem cada novo nó será filho.
  4. A árvore cresce durante o download. O navegador não precisa esperar o último byte para começar a interpretar, descobrir recursos e preparar uma primeira renderização.
DOM significa Document Object Model. É um modelo de objetos e relações — pai, filho e irmão — acessível por APIs. A indentação ajuda humanos, mas não cria a hierarquia; são as tags, os contextos do parser e as regras da linguagem que determinam a árvore.

O HTML É SÓ A PRIMEIRA RESPOSTA

Ao encontrar referências, o navegador abre novas buscas por CSS, JavaScript, imagens e fontes.

Enquanto a resposta HTML ainda está chegando, diferentes partes do navegador podem descobrir subrecursos. Cada referência é resolvida como uma URL, recebe um tipo e um iniciador e entra no sistema de fetch. A partir daí, o navegador verifica política de segurança e cache, escolhe uma conexão compatível e agenda a transferência.

documento recebido de https://app.exemplo.com/loja/referências encontradas
<link rel="stylesheet" href="/assets/app.css">
<script defer src="/assets/app.js"></script>
<img src="https://cdn.exemplo.com/capa.webp" alt="Capa">

/* app.css também pode descobrir outro recurso */
@font-face { src: url("/fonts/interface.woff2"); }

// app.js pode iniciar uma busca em tempo de execução
fetch("https://api.exemplo.net/livros");

HTML

Parser e scanner antecipado

link, script, img, picture, mídia e outros elementos revelam URLs. Navegadores também podem usar um scanner antecipado para localizar recursos enquanto o parser principal está ocupado.

CSS

Recursos dentro das regras

url(), @font-face e @import podem revelar imagens, fontes e outras folhas. Esses endereços só ficam conhecidos depois que o CSS correspondente chega e é analisado.

JAVASCRIPT

Buscas decididas pelo programa

fetch(), módulos importados e elementos criados por script podem iniciar requisições mais tarde, de acordo com o estado da aplicação e as ações do usuário.

PRIORIDADE

Nem tudo entra na mesma fila

Tipo, posição, visibilidade, preload, loading="lazy" e fetchpriority ajudam o navegador a priorizar. Os detalhes do agendamento variam entre motores.

Laboratório visual · Da referência à origem correta

Avance pelas etapas para ver descoberta, resolução de URL, agrupamento lógico por origem e reutilização de conexões.

subrecursos
Seu navegador não suporta canvas.

Descoberta: o parser encontra CSS, script e imagem no HTML. Depois, o CSS pode revelar uma fonte e o JavaScript pode iniciar uma chamada de API.

“Pasta por domínio” é uma boa imagem mental, mas não é uma pasta literal. O navegador associa cada requisição à sua URL e origem — combinação de esquema, host e porta. https://app.exemplo.com e http://app.exemplo.com são origens diferentes; já /assets/app.css e /img/capa.webp pertencem à mesma origem quando usam o mesmo esquema, host e porta. Internamente também contam o contexto de segurança, a partição de rede, a prioridade e as conexões disponíveis.

A URL relativa ganha contexto

Recebido de https://app.exemplo.com/loja/, o caminho /assets/app.css vira https://app.exemplo.com/assets/app.css. A URL base do documento — que pode ser alterada por <base> — participa dessa resolução.

Uma conexão pode transportar vários recursos

Quando possível, conexões são mantidas e reutilizadas. HTTP/2 e HTTP/3 permitem vários fluxos concorrentes na mesma conexão; isso não significa que todos os recursos tenham a mesma prioridade ou terminem na ordem em que apareceram.

Outra origem exige verificações

Uma imagem pode ser exibida de outra origem, mas ler uma resposta com JavaScript normalmente depende de CORS. CSP, integridade, credenciais, referrer policy e tipo de destino também podem alterar ou bloquear a busca.

CACHE ANTES DE TRANSFERIR NOVAMENTE

A mesma URL não significa automaticamente uma nova descarga completa.

Antes de buscar o corpo pela rede, o processo de fetch procura uma resposta reutilizável. A chave não é apenas “o nome do arquivo”: método, URL, campos indicados por Vary, credenciais e o contexto de particionamento também podem participar da decisão. Depois, frescor e validadores determinam o próximo passo.

Laboratório visual · Qual caminho esta requisição percorre?

Alterne o cenário. As setas e os pacotes mostram quando o corpo vem do cache, quando apenas a validade é consultada e quando a rede fornece uma nova resposta.

cache e rede
Seu navegador não suporta canvas.

Cache fresco: a resposta ainda está dentro do período permitido por Cache-Control. O corpo armazenado pode ser entregue sem consultar o servidor de origem.

Cache-Control: max-age=3600

Fresco por um período

Enquanto a resposta estiver fresca e for reutilizável, o navegador pode atender a requisição localmente. Em arquivos versionados, immutable evita revalidações desnecessárias.

Cache-Control: no-cache

Pode guardar, mas precisa validar

O nome engana: no-cache não significa necessariamente “não armazenar”. Ele exige validação antes de reutilizar a resposta sem nova confirmação.

Cache-Control: no-store

Não armazenar neste cache

Instrui caches a não guardarem a resposta. É diferente de uma resposta guardada que ficou velha e precisa ser revalidada.

ETag: "build-a91"

Validador da representação

Na próxima consulta, o cliente pode enviar If-None-Match. Um 304 Not Modified atualiza os metadados e reutiliza o corpo já salvo; um 200 traz uma representação nova.

Last-Modified

Validador por data

Permite uma requisição condicional com If-Modified-Since. Em geral, ETag expressa mudanças da representação com mais precisão.

Vary: Accept-Encoding

Mais de uma variante

A resposta comprimida com Brotli não deve ser confundida com outra variante. Vary informa quais campos da requisição precisam corresponder.

Cache HTTP do navegador

É usado automaticamente pelo algoritmo de fetch conforme os cabeçalhos HTTP. Rótulos como “memory cache” e “disk cache” são detalhes de implementação e podem variar.

Cache API do Service Worker

É um armazenamento separado, controlado pela aplicação. O Service Worker intercepta o evento fetch e decide responder do Cache Storage, consultar a rede ou combinar estratégias.

Cache da CDN

Fica fora do dispositivo, próximo aos usuários. Mesmo quando o navegador precisa ir à rede, uma CDN pode responder sem consultar o servidor de origem da aplicação.

Arquivos estáticos costumam usar nome versionado. Em vez de manter app.js e torcer para todos perceberem a mudança, o processo de build pode gerar app.a91f2c.js. O conteúdo novo produz outra URL; a versão antiga pode receber cache longo sem servir código desatualizado para a página nova.

NEM TODO NÓ É UMA TAG

Document, elementos e textos ocupam papéis diferentes na árvore.

DOCUMENT

A raiz do documento

document representa o documento carregado. O elemento html é seu document element, não o próprio Document.

DOCUMENTTYPE

O modo do documento

<!doctype html> cria um nó de tipo DocumentType e ajuda o navegador a usar o modo de padrões.

ELEMENT

A estrutura semântica

main, h1 e button viram objetos Element, com propriedades, atributos, filhos e métodos.

TEXT

O conteúdo também é nó

O texto “Livros” não fica dentro do objeto h1 como uma string comum: ele é representado por um nó Text filho.

Atributos não aparecem como filhos em childNodes. id="abrir" e lang="pt-BR" pertencem à lista de atributos do elemento. DevTools costuma mostrá-los na mesma linha visual da tag para refletir essa relação.

FONTE ≠ ÁRVORE ATUAL

“Exibir código-fonte” e “Inspecionar elemento” podem mostrar coisas diferentes.

O código-fonte é a sequência recebida. O painel Elements mostra uma representação serializada do DOM atual: já interpretado, possivelmente corrigido pelo parser e talvez modificado por JavaScript.

HTML recebidotexto da resposta
<!-- html, head e body foram omitidos -->
<title>Loja</title>
<h1>Produtos</h1>
<p>Confira as ofertas

O autor omitiu tags que o HTML permite inferir e não escreveu o fechamento de p.

DOM construídoestrutura interpretada
<html>
  <head>
    <title>Loja</title>
  </head>
  <body>
    <h1>Produtos</h1>
    <p>Confira as ofertas</p>
  </body>
</html>

O parser cria os elementos implícitos e fecha o parágrafo conforme as regras da linguagem.

“O navegador consertou” não significa que o HTML está correto. A recuperação de erros é padronizada para páginas interoperáveis, mas validar a marcação continua importante. Estrutura inválida pode produzir uma árvore diferente da imaginada e prejudicar CSS, JavaScript e acessibilidade.

A ÁRVORE DOM AINDA NÃO É A TELA

Estrutura e estilo precisam virar caixas, desenhos e camadas.

O DOM descreve conteúdo e relações. O CSS é analisado em estruturas próprias, suas regras são combinadas pela cascata e estilos computados são associados aos elementos. Em seguida, o mecanismo determina quais caixas existem, onde ficam e como devem ser desenhadas.

Laboratório visual · Do DOM aos pixels

Selecione uma fase para separar responsabilidades que costumam ser confundidas.

pipeline visual
Seu navegador não suporta canvas.

DOM: registra elementos, textos e relações. Ele diz que existe um botão dentro de main, mas ainda não determina seus pixels finais.

Estrutura ou fasePergunta respondidaResultado simplificado
DOMQuais nós existem e como se relacionam?Document, elementos, textos e comentários.
CSSOM e estiloQuais regras se aplicam e qual é o valor computado?Seletores, cascata, herança e estilos computados.
Estrutura de renderizaçãoQuais caixas e fragmentos visuais precisam existir?display: none não gera caixa; pseudoelementos podem gerar conteúdo visual.
LayoutQual é o tamanho e a posição de cada fragmento?Geometria considerando viewport, fluxo, flex, grid, fontes e conteúdo.
Paint e rasterO que desenhar e como converter em pixels?Ordens de desenho, fundos, bordas, texto, sombras e imagens rasterizadas.
ComposiçãoComo combinar superfícies e apresentar o quadro?Camadas ou tiles são posicionados e combinados para chegar à tela.
“Render tree” é uma simplificação didática útil, não uma API padronizada única. Motores reais mantêm estruturas internas diferentes — árvores de fragmentos, listas de exibição, property trees, camadas e tiles. O modelo DOM + CSSOM → layout → paint → composição ajuda a raciocinar, mas não descreve todos os detalhes de todos os navegadores.

JAVASCRIPT PARTICIPA DA CONSTRUÇÃO

Um script pode esperar o parser, interrompê-lo ou alterar a árvore pronta.

Quando um script executa, ele pode consultar e modificar o DOM que existe naquele instante. A forma de carregar o script muda a relação entre download, parsing e execução.

SCRIPT CLÁSSICO

Sem async ou defer

Encontrado durante o parsing, normalmente interrompe o parser enquanto é buscado, quando externo, e executado. O conteúdo abaixo ainda pode não existir no DOM.

<script src="app.js"></script>

DEFER

Baixa em paralelo, executa depois

O download ocorre sem parar o parser. Scripts defer clássicos executam depois que o documento terminou de ser analisado e preservam sua ordem.

<script defer src="app.js"></script>

ASYNC

Executa assim que estiver pronto

Baixa em paralelo, mas pode interromper o parsing para executar quando chegar. A ordem entre vários scripts async não é garantida.

<script async src="metricas.js"></script>

MODULE

Comportamento adiado por padrão

O módulo e suas dependências são buscados em paralelo e, sem async, avaliados depois do parsing. Módulos também possuem escopo próprio.

<script type="module" src="app.js"></script>
1
Parsing em andamentoDOM cresce e recursos são descobertos.
2
DOMContentLoadedParsing concluído e scripts adiados executados.
3
loadO documento e recursos dependentes que bloqueiam esse evento terminaram.

A primeira pintura não precisa esperar o evento load. O navegador pode apresentar conteúdo progressivamente. Também não confunda “DOM pronto” com “todas as fontes, imagens e dados assíncronos prontos”. Cada marco responde a uma pergunta diferente.

CSS normalmente não interrompe a construção do DOM por si só, mas pode bloquear a renderização. Além disso, um script clássico encontrado depois de uma folha de estilo pode precisar esperar esse CSS, porque o script pode consultar estilos computados. Na prática, HTML, CSS e JavaScript possuem dependências que se cruzam.

DOM É MUTÁVEL

JavaScript pode trocar a árvore depois que o HTML terminou de chegar.

Neste laboratório, os botões usam APIs do DOM para criar elementos, alterar atributos e remover filhos. Um MutationObserver descreve a última mudança percebida.

OPERAÇÕES

Modifique a lista

Aguardando uma mutação.Experimente adicionar, destacar ou remover.
Prévia renderizada

Biblioteca

    DOM atual serializadoouterHTML
    innerHTML aciona o parser de fragmentos HTML. Não injete conteúdo não confiável dessa maneira. Para texto, prefira textContent; para estruturas, crie elementos e atributos com APIs apropriadas ou use uma política de sanitização adequada ao contexto.

    MUDAR O DOM PODE INVALIDAR TRABALHO VISUAL

    Nem toda alteração percorre todas as fases novamente.

    AlteraçãoTrabalho provávelComo interpretar
    Adicionar um parágrafoStyle, layout, paint e composição.A nova caixa pode deslocar conteúdo e precisa ser desenhada.
    Trocar apenas uma corStyle e paint; layout pode ser evitado.A geometria não precisa mudar, mas os pixels sim.
    Animar transformPode ficar principalmente na composição.Se o elemento estiver promovido adequadamente, é possível reutilizar pixels já rasterizados.
    Ler geometria após escrever estiloPode forçar layout síncrono.Intercalar repetidamente escrita e leitura de medidas causa layout thrashing.
    display: nonePode reconstruir caixas e refazer layout.O elemento continua no DOM, mas deixa de gerar caixa visual.
    “Alterar o DOM é lento” é uma generalização ruim. O custo depende da quantidade de nós afetados, das propriedades alteradas, da geometria, da área repintada e das otimizações do motor. Meça no Performance panel antes de escolher uma solução.

    PARE E PENSE

    Um elemento aparece no painel Elements, mas não é visível na página. Isso prova que o parser falhou?

    Separe existência no DOM, geração de caixa, posição, recorte, transparência e ordem de pintura.

    Não. O nó pode existir corretamente no DOM e ainda não produzir pixels perceptíveis: display: none, ancestral oculto, visibility: hidden, opacidade zero, tamanho zero, posição fora da viewport, recorte ou sobreposição são algumas possibilidades. Inspecione estilos computados, box model, layout e camadas.

    CONTINUE EXPLORANDO

    Referências e itens adicionais de estudo

    Referências técnicas

    Padrões e documentação de implementação usados nesta aula.

    Itens adicionais de estudo

    Experimentos para consolidar o modelo mental.

    • Abra View Source e Elements na mesma página e encontre uma diferença causada pelo parser ou por JavaScript.
    • No console, compare children, que seleciona elementos, com childNodes, que também pode incluir textos e comentários.
    • Use breakpoints de subtree modifications no DevTools para descobrir qual código muda um componente.
    • Teste scripts normal, defer, async e módulo, registrando document.readyState e a ordem de execução.
    • Abra o painel Network e observe Domain, Initiator, Priority, Protocol, Size e a cascata temporal de cada subrecurso.
    • Recarregue uma página três vezes: normalmente, com cache desativado e após limpar o cache. Compare transferências completas, respostas 304 e indicações de cache.
    • No console, execute performance.getEntriesByType('resource') e compare name, initiatorType, duração e tamanhos transferidos.
    • Grave uma interação no Performance panel e localize style recalculation, layout, paint e composite.
    • Pesquise Shadow DOM e compare light tree, shadow tree e árvore composta.