Renderizar HTML com JavaScript é diferente de renderizar HTML enviado pelo servidor, e isso pode afetar o desempenho. Saiba a diferença neste guia e o que você pode fazer para preservar o desempenho de renderização do seu site, principalmente em relação às interações.
A análise e a renderização de HTML são feitas muito bem por padrão pelos navegadores em sites que usam a lógica de navegação integrada do navegador, às vezes chamada de "carregamentos de página tradicionais" ou "navegações completas". Esses sites às vezes são chamados de aplicativos de várias páginas (MPAs, na sigla em inglês).
No entanto, os desenvolvedores podem contornar os padrões do navegador para atender às necessidades do aplicativo. Esse é o caso de sites que usam o padrão de aplicativo de página única (SPA), que cria dinamicamente grandes partes do HTML/DOM no cliente com JavaScript. A renderização do lado do cliente é o nome desse padrão de design, e ela pode afetar a Interação com a próxima renderização (INP) do seu site se o trabalho envolvido for excessivo.
Este guia vai ajudar você a avaliar a diferença entre usar o HTML enviado pelo servidor ao navegador e criar no cliente com JavaScript, além de mostrar como a segunda opção pode resultar em alta latência de interação em momentos cruciais.
Como o navegador renderiza o HTML fornecido pelo servidor
O padrão de navegação usado em carregamentos de página tradicionais envolve o recebimento de HTML do servidor em todas as navegações. Se você inserir um URL na barra de endereço do navegador ou clicar em um link em uma MPA, a seguinte série de eventos vai ocorrer:
- O navegador envia uma solicitação de navegação para o URL fornecido.
- O servidor responde com HTML em partes.
A última etapa é fundamental. Também é uma das otimizações de desempenho mais fundamentais na troca entre servidor e navegador, conhecida como streaming. Se o servidor puder começar a enviar HTML assim que possível, e o navegador não esperar que toda a resposta chegue, ele poderá processar o HTML em partes à medida que ele chega.

Assim como a maioria das coisas que acontecem no navegador, a análise de HTML ocorre em tarefas. Quando o HTML é transmitido do servidor para o navegador, o navegador otimiza a análise desse HTML fazendo isso um pouco por vez à medida que os bits desse fluxo chegam em partes. A consequência é que o navegador cede à linha de execução principal periodicamente após processar cada parte, o que evita tarefas longas. Isso significa que outros trabalhos podem ocorrer enquanto o HTML está sendo analisado, incluindo o trabalho de renderização incremental necessário para apresentar uma página ao usuário, bem como o processamento de interações do usuário que podem ocorrer durante o período crucial de inicialização da página. Essa abordagem resulta em uma pontuação melhor de Interaction to Next Paint (INP) para a página.
Que lição podemos tirar disso? Ao transmitir HTML do servidor, você recebe análise e renderização incrementais de HTML e geração automática para a linha de execução principal sem custo financeiro. Isso não acontece com a renderização do lado do cliente.
Como o navegador renderiza o HTML fornecido pelo JavaScript
Embora toda solicitação de navegação para uma página exija que o servidor forneça uma quantidade de HTML, alguns sites usam o padrão SPA. Essa abordagem geralmente envolve um payload inicial mínimo de HTML fornecido pelo servidor, mas o cliente preenche a área de conteúdo principal de uma página com HTML montado com dados buscados do servidor. As navegações subsequentes, às vezes chamadas de "navegações leves" nesse caso, são processadas inteiramente pelo JavaScript para preencher a página com um novo HTML.
A renderização do lado do cliente também pode ocorrer em não SPAs em casos mais limitados em que o HTML é adicionado dinamicamente ao DOM por JavaScript.
Há algumas maneiras comuns de criar HTML ou adicionar ao DOM usando JavaScript:
- A propriedade
innerHTML
permite definir o conteúdo em um elemento existente usando uma string, que o navegador analisa em DOM. - O método
document.createElement
permite criar novos elementos para serem adicionados ao DOM sem usar a análise HTML do navegador. - O método
document.write
permite escrever HTML no documento, e o navegador o analisa, assim como na abordagem 1. No entanto, devido a vários motivos, o uso dedocument.write
é altamente desencorajado.

As consequências da criação de HTML/DOM usando JavaScript do lado do cliente podem ser significativas:
- Ao contrário do HTML transmitido pelo servidor em resposta a uma solicitação de navegação, as tarefas do JavaScript no cliente não são divididas automaticamente, o que pode resultar em tarefas longas que bloqueiam a linha de execução principal. Isso significa que o INP da sua página pode ser afetado negativamente se você estiver criando muito HTML/DOM de uma vez no cliente.
- Se o HTML for criado no cliente durante a inicialização, os recursos referenciados nele não serão descobertos pelo scanner de pré-carregamento do navegador. Isso certamente terá um efeito negativo na Maior exibição de conteúdo (LCP) de uma página. Embora esse não seja um problema de desempenho de tempo de execução (em vez disso, é um problema de atraso de rede ao buscar recursos importantes), você não quer que o LCP do seu site seja afetado ao ignorar essa otimização fundamental de desempenho do navegador.
O que você pode fazer sobre o impacto da renderização do lado do cliente na performance
Se o site depender muito da renderização do lado do cliente e você tiver observado valores de INP ruins nos dados de campo, talvez esteja se perguntando se a renderização do lado do cliente tem algo a ver com o problema. Por exemplo, se o site for um SPA, os dados de campo poderão revelar interações responsáveis por um trabalho de renderização considerável.
Seja qual for o motivo, confira algumas possíveis causas para ajudar a resolver o problema.
Forneça o máximo de HTML possível do servidor
Como mencionado anteriormente, o navegador processa o HTML do servidor de maneira muito eficiente por padrão. Ele vai dividir a análise e a renderização de HTML de uma forma que evite tarefas longas e otimize a quantidade total de tempo da linha de execução principal. Isso leva a um Tempo total de bloqueio (TBT) menor, e o TBT tem uma forte correlação com o INP.
Talvez você esteja usando um framework de front-end para criar seu site. Se for o caso, verifique se você está renderizando o HTML do componente no servidor. Isso limita a quantidade de renderização inicial do lado do cliente que seu site vai exigir e resulta em uma experiência melhor.
- No React, use a API DOM do servidor para renderizar HTML no servidor. No entanto, o método tradicional de renderização do lado do servidor usa uma abordagem síncrona, o que pode levar a um tempo até o primeiro byte (TTFB) mais longo, bem como métricas subsequentes, como First Contentful Paint (FCP) e LCP. Sempre que possível, use as APIs de streaming para Node.js ou outros tempos de execução JavaScript para que o servidor possa começar a transmitir HTML para o navegador assim que possível. O Next.js, um framework baseado em React, oferece muitas práticas recomendadas por padrão. Além de renderizar automaticamente o HTML no servidor, ele também pode gerar HTML estático para páginas que não mudam com base no contexto do usuário, como autenticação.
- O Vue também faz a renderização do lado do cliente por padrão. No entanto, assim como o React, o Vue também pode renderizar o HTML do componente no servidor. Aproveite essas APIs do lado do servidor sempre que possível ou considere uma abstração de nível superior para seu projeto Vue e facilite a implementação das práticas recomendadas.
- O Svelte renderiza HTML no servidor por padrão. No entanto, se o código do componente precisar acessar namespaces exclusivos do navegador (
window
, por exemplo), talvez não seja possível renderizar o HTML desse componente no servidor. Sempre que possível, use abordagens alternativas para não causar renderização desnecessária do lado do cliente. O SvelteKit, que é para o Svelte o que o Next.js é para o React, incorpora muitas práticas recomendadas aos seus projetos Svelte, evitando possíveis problemas em projetos que usam apenas o Svelte.
Limitar a quantidade de nós DOM criados no cliente
Quando os DOMs são grandes, o processamento necessário para renderizá-los tende a aumentar. Se o site for um SPA completo ou estiver injetando novos nós em um DOM existente como resultado de uma interação para um MPA, mantenha esses DOMs o menor possível. Isso ajuda a reduzir o trabalho necessário durante a renderização do lado do cliente para mostrar o HTML, o que pode ajudar a manter o INP do seu site mais baixo.
Considere uma arquitetura de service worker de streaming
Essa é uma técnica avançada, que pode não funcionar facilmente com todos os casos de uso, mas pode transformar sua MPA em um site que parece carregar instantaneamente quando os usuários navegam de uma página para outra. É possível usar um service worker para pré-armazenar em cache as partes estáticas do seu site em CacheStorage
e usar a API ReadableStream
para buscar o restante do HTML de uma página no servidor.
Quando você usa essa técnica com sucesso, não está criando HTML no cliente, mas o carregamento instantâneo de partes do conteúdo do cache dá a impressão de que seu site está carregando rapidamente. Sites que usam essa abordagem podem parecer quase um SPA, mas sem as desvantagens da renderização do lado do cliente. Ele também reduz a quantidade de HTML que você está solicitando do servidor.
Em resumo, uma arquitetura de service worker de streaming não substitui a lógica de navegação integrada do navegador, ela adiciona a ela. Para mais informações sobre como fazer isso com o Workbox, leia Aplicativos de várias páginas mais rápidos com streams.
Conclusão
A forma como seu site recebe e renderiza HTML tem um impacto na performance. Quando você depende do servidor para enviar todo (ou a maior parte) o HTML necessário para o funcionamento do site, você recebe muito sem custo financeiro: análise e renderização incrementais e concessão automática à linha de execução principal para evitar tarefas longas.
A renderização HTML do lado do cliente apresenta vários problemas de desempenho em potencial que podem ser evitados em muitos casos. No entanto, devido aos requisitos de cada site, isso não é totalmente evitável 100% do tempo. Para reduzir as possíveis tarefas longas que podem resultar da renderização excessiva do lado do cliente, envie o máximo possível do HTML do seu site do servidor sempre que possível, mantenha os tamanhos do DOM o menor possível para o HTML que precisa ser renderizado no cliente e considere arquiteturas alternativas para acelerar a entrega de HTML ao cliente, aproveitando também a análise e a renderização incrementais que o navegador oferece para o HTML carregado do servidor.
Se você conseguir minimizar a renderização do lado do cliente do seu site, vai melhorar não apenas o INP, mas também outras métricas, como LCP, TBT e, possivelmente, até o TTFB em alguns casos.
Imagem principal do Unsplash, de Maik Jonietz.