Renderizar HTML com JavaScript é diferente de renderizar HTML enviado pelo servidor, e isso pode afetar a performance. Saiba a diferença neste guia e o que você pode fazer para preservar a performance de renderização do seu site, especialmente em relação às interações.
A análise e a renderização de HTML são algo que os navegadores fazem muito bem por padrão em sites que usam a lógica de navegação integrada do navegador, às vezes chamada de "carregamentos de página tradicionais" ou "navegação difícil". Esses sites 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. Isso certamente acontece com sites que usam o padrão de app de página única (SPA, na sigla em inglês), 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 pode afetar a Interaction to Next Paint (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 para o navegador e criar o código no cliente com JavaScript, além de como o último 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 nos carregamentos de página tradicionais envolve receber HTML do servidor em cada navegação. Se você digitar um URL na barra de endereço do navegador ou clicar em um link em um 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. Ela também é uma das otimizações de desempenho mais importantes na troca entre servidor e navegador e é conhecida como streaming. Se o servidor puder começar a enviar HTML assim que possível e o navegador não esperar a resposta completa chegar, ele poderá processar o HTML em partes à medida que elas chegam.

Como a maioria das coisas que acontecem no navegador, a análise de HTML ocorre dentro de tarefas. Quando o HTML é transmitido do servidor para o navegador, o navegador otimiza a análise desse HTML fazendo isso um pouco de cada vez, à medida que os bits do stream chegam em blocos. Como consequência, 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 de inicialização crucial da página. Essa abordagem resulta em uma pontuação de Interaction to Next Paint (INP) melhor para a página.
Que lição podemos tirar disso? Quando você transmite HTML do servidor, a renderização e a análise incremental de HTML e a rendição automática para a linha de execução principal são 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 cada solicitação de navegação para uma página exija que uma certa quantidade de HTML seja fornecida pelo servidor, 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 a partir dos dados buscados do servidor. As navegações subsequentes, às vezes chamadas de "navegações suaves", 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 usando uma string, que o navegador analisa no DOM. - O método
document.createElement
permite criar novos elementos para serem adicionados ao DOM sem usar nenhuma análise HTML do navegador. - O método
document.write
permite gravar HTML no documento, e o navegador o analisa, assim como na abordagem 1. No entanto, por vários motivos, não recomendamos o uso dedocument.write
.

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 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 a INP da sua página pode ser afetada negativamente se você estiver criando muito HTML/DOM por 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 Largest Contentful Paint (LCP) de uma página. Embora esse não seja um problema de desempenho de execução (é um problema de atraso de rede na busca de recursos importantes), você não quer que o LCP do seu site seja afetado por ignorar essa otimização fundamental de desempenho do navegador.
O que fazer em relação ao impacto na performance da renderização do lado do cliente
Se o site depende muito da renderização do lado do cliente e você observou valores de INP ruins nos dados de campo, talvez se pergunte se a renderização do lado do cliente tem alguma relação com o problema. Por exemplo, se o site for um SPA, os dados de campo podem revelar interações responsáveis por um trabalho de renderização considerável.
Seja qual for o motivo, confira algumas causas possíveis para você resolver o problema.
Forneça o máximo possível de HTML do servidor
Como mencionado anteriormente, o navegador processa o HTML do servidor com muita eficiência por padrão. Ele vai dividir a análise e renderização do HTML de uma maneira que evite tarefas longas e otimize o tempo total da linha de execução principal. Isso leva a um Tempo total de bloqueio (TBT) menor, e o TBT está fortemente correlacionado com o INP.
Você pode estar usando um framework de front-end para criar seu site. Nesse caso, renderize o componente HTML no servidor. Isso vai limitar a quantidade de renderização inicial do lado do cliente que seu site vai exigir e resultar em uma experiência melhor.
- No React, use a API DOM do servidor para renderizar HTML no servidor. Mas atenção: o método tradicional de renderização do lado do servidor usa uma abordagem síncrona, o que pode levar a um tempo de início até o primeiro byte (TTFB) mais longo, bem como a métricas subsequentes, como First Contentful Paint (FCP) e LCP. Sempre que possível, use as APIs de streaming para Node.js ou outros runtimes do JavaScript para que o servidor possa começar a transmitir HTML para o navegador o mais rápido possível. O Next.js, um framework baseado em React, oferece muitas práticas recomendadas por padrão. Além de renderizar HTML automaticamente no servidor, ele também pode gerar HTML estaticamente para páginas que não mudam com base no contexto do usuário (como autenticação).
- O Vue também executa 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 mais alto para seu projeto do Vue e facilitar 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 de acesso a namespaces exclusivos do navegador (
window
, por exemplo), talvez não seja possível renderizar o HTML do componente no servidor. Sempre que possível, use abordagens alternativas para não causar renderizações desnecessárias do lado do cliente. O SvelteKit, que é para o Svelte o que o Next.js é para o React, incorpora o máximo possível de práticas recomendadas nos seus projetos do Svelte para que você possa evitar possíveis armadilhas 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 injetar novos nós em um DOM como resultado de uma interação com um MPA, mantenha esses DOMs o menor possível. Isso vai ajudar a reduzir o trabalho necessário durante a renderização do lado do cliente para exibir esse HTML, o que ajuda a manter o INP do seu site mais baixo.
Considere uma arquitetura de worker de serviço de streaming
Essa é uma técnica avançada que pode não funcionar facilmente em todos os casos de uso, mas que pode transformar seu 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é-cachear as partes estáticas do site em CacheStorage
enquanto usa a API ReadableStream
para buscar o restante do HTML de uma página do servidor.
Quando você usa essa técnica, não cria HTML no cliente, mas o carregamento instantâneo de partes do conteúdo do cache dá a impressão de que o site está carregando rapidamente. Os sites que usam essa abordagem podem parecer quase como um SPA, mas sem as desvantagens da renderização do lado do cliente. Isso também reduz a quantidade de HTML que você solicita do servidor.
Em resumo, a arquitetura de worker de serviço de streaming não substitui a lógica de navegação integrada do navegador, mas a 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 o site recebe e renderiza HTML afeta a performance. Quando você depende do servidor para enviar todo (ou a maior parte) do HTML necessário para que seu site funcione, você recebe muito por nada: análise e renderização incrementais e rendimento automático para a linha de execução principal para evitar tarefas longas.
A renderização de HTML do lado do cliente apresenta vários problemas de desempenho 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 tarefas demoradas que podem resultar de renderizações excessivas no site do cliente, envie o máximo possível de HTML do seu site do servidor sempre que possível, mantenha os tamanhos do DOM o menor possível para HTML que precisa ser renderizado no cliente e considere arquiteturas alternativas para acelerar a entrega de HTML ao cliente, aproveitando a análise incremental e a renderização que o navegador oferece para 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é mesmo o TTFB em alguns casos.
Imagem principal do Unsplash, por Maik Jonietz.