Como tamanhos grandes de DOM afetam a interatividade e o que você pode fazer a respeito

Tamanho de DOM grande tem mais efeito na interatividade do que você imagina. Neste guia, explicamos o motivo e o que você pode fazer.

Não tem jeito: quando você cria uma página da Web, ela tem um Modelo de Objeto de Documento (DOM). O DOM representa a estrutura do HTML da página e dá acesso a JavaScript e CSS à estrutura e ao conteúdo da página.

O problema, no entanto, é que o tamanho do DOM afeta a capacidade de um navegador renderizar uma página de forma rápida e eficiente. Em geral, quanto maior o DOM, mais caro é renderizar a página inicialmente e atualizar a renderização mais tarde no ciclo de vida da página.

Isso se torna problemático em páginas com DOMs muito grandes quando as interações que modificam ou atualizam o DOM acionam um trabalho de layout caro que afeta a capacidade da página de responder rapidamente. O trabalho de layout caro pode afetar a Interação com a próxima pintura (INP) de uma página. Se você quiser que uma página responda rapidamente às interações do usuário, é importante garantir que os tamanhos do DOM sejam apenas os necessários.

Quando o DOM de uma página é muito grande?

De acordo com o Lighthouse, o tamanho do DOM de uma página é excessivo quando excede 1.400 nós. O Lighthouse vai começar a gerar avisos quando o DOM de uma página exceder 800 nós. Confira o exemplo de HTML abaixo:

<ul>
  <li>List item one.</li>
  <li>List item two.</li>
  <li>List item three.</li>
</ul>

No código acima, há quatro elementos DOM: o elemento <ul> e os três elementos filhos <li>. Sua página da Web provavelmente terá muitos mais nós do que este. Portanto, é importante entender o que você pode fazer para manter os tamanhos do DOM sob controle, bem como outras estratégias para otimizar o trabalho de renderização depois de deixar o DOM de uma página o menor possível.

Como os DOMs grandes afetam a performance da página?

DOMs grandes afetam a performance da página de algumas maneiras:

  1. Durante a renderização inicial da página. Quando o CSS é aplicado a uma página, uma estrutura semelhante ao DOM, conhecida como CSS Object Model (CSSOM), é criada. À medida que os seletores de CSS aumentam a especificidade, o CSSOM se torna mais complexo, e mais tempo é necessário para executar o layout, o estilo, a composição e a pintura necessários para exibir a página da Web na tela. Esse trabalho extra aumenta a latência de interações que ocorrem no início do carregamento da página.
  2. Quando as interações modificam o DOM, seja pela inserção ou exclusão de elementos ou pela modificação de conteúdos e estilos do DOM, o trabalho necessário para renderizar essa atualização pode resultar em trabalhos de layout, estilização, composição e pintura muito caros. Assim como no caso da renderização inicial da página, um aumento na especificidade do seletor de CSS pode aumentar o trabalho de renderização quando os elementos HTML são inseridos no DOM como resultado de uma interação.
  3. Quando o JavaScript consulta o DOM, as referências aos elementos do DOM são armazenadas na memória. Por exemplo, se você chamar document.querySelectorAll para selecionar todos os elementos <div> em uma página, o custo de memória poderá ser considerável se o resultado retornar um grande número de elementos DOM.
Uma captura de tela de uma tarefa demorada causada por trabalho excessivo de renderização no painel de desempenho do Chrome DevTools. A pilha de chamadas da tarefa longa mostra um tempo significativo gasto na recalculação dos estilos de página, além da pré-pintura.
Uma tarefa demorada, conforme mostrado no perfilador de desempenho no Chrome DevTools. A longa tarefa mostrada é causada pela inserção de elementos do DOM em um DOM grande usando JavaScript.

Todos esses fatores podem afetar a interatividade, mas o segundo item da lista acima é particularmente importante. Se uma interação resultar em uma mudança no DOM, ela poderá iniciar muito trabalho que pode contribuir para uma INP ruim em uma página.

Como medir o tamanho do DOM?

É possível medir o tamanho do DOM de algumas maneiras. O primeiro método usa o Lighthouse. Quando você executa uma auditoria, as estatísticas sobre o DOM da página atual ficam na auditoria "Evite um tamanho excessivo de DOM", no cabeçalho "Diagnóstico". Nesta seção, você pode conferir o número total de elementos DOM, o elemento DOM que contém a maioria dos elementos filhos e o elemento DOM mais profundo.

Um método mais simples envolve o uso do console JavaScript nas ferramentas para desenvolvedores em qualquer navegador importante. Para conferir o número total de elementos HTML no DOM, use o seguinte código no console depois que a página carregar:

document.querySelectorAll('*').length;

Se você quiser conferir a atualização do tamanho do DOM em tempo real, também poderá usar a ferramenta de monitoramento de desempenho. Com essa ferramenta, é possível correlacionar operações de layout e estilo (e outros aspectos de desempenho) com o tamanho atual do DOM.

Uma captura de tela do monitor de desempenho no Chrome DevTools. À esquerda, há vários aspectos da performance da página que podem ser monitorados continuamente durante a vida útil dela. Na captura de tela, o número de nós DOM, layouts por segundo e recálculos de estilo por seção estão sendo monitorados ativamente.
O monitor de desempenho no Chrome DevTools. Nessa visualização, o número atual de nós DOM da página é mostrado em um gráfico, junto com as operações de layout e os recálculos de estilo realizados por segundo.

Se o tamanho do DOM estiver se aproximando do limite de aviso do tamanho do DOM do Lighthouse ou falhar completamente, a próxima etapa é descobrir como reduzir o tamanho do DOM para melhorar a capacidade da página de responder às interações do usuário e melhorar o INP do site.

Como posso medir o número de elementos DOM afetados por uma interação?

Se você estiver criando um perfil de uma interação lenta no laboratório que pode estar relacionada ao tamanho do DOM da página, é possível descobrir quantos elementos do DOM foram afetados selecionando qualquer atividade no perfilador com a opção "Recalculate Style" e observando os dados contextuais no painel inferior.

Uma captura de tela da atividade de recalculo de estilo selecionada no painel de desempenho do Chrome DevTools. Na parte de cima, a faixa de interações mostra uma interação de clique, e a maior parte do trabalho é gasto com recalculo de estilo e trabalho de pré-pintura. Na parte de baixo, um painel mostra mais detalhes sobre a atividade selecionada, que informa que 2.547 elementos do DOM foram afetados.
Observar o número de elementos afetados no DOM como resultado do trabalho de recálculo de estilo. A parte sombreada da interação na faixa de interações representa a parte da duração da interação que foi superior a 200 milissegundos, que é o limite "bom" designado para a INP.

Na captura de tela acima, observe que o recálculo do estilo do trabalho, quando selecionado, mostra o número de elementos afetados. Embora a captura de tela acima mostre um caso extremo do efeito do tamanho do DOM na renderização de trabalho em uma página com muitos elementos do DOM, essas informações de diagnóstico são úteis em qualquer caso para determinar se o tamanho do DOM é um fator limitante no tempo que leva para o próximo frame ser renderizado em resposta a uma interação.

Como posso reduzir o tamanho do DOM?

Além de auditar o HTML do seu site em busca de marcações desnecessárias, a principal maneira de reduzir o tamanho do DOM é diminuir a profundidade dele. Um sinal de que o DOM pode estar desnecessáriamente profundo é se você encontrar uma marcação semelhante a esta na guia Elements das ferramentas para desenvolvedores do navegador:

<div>
  <div>
    <div>
      <div>
        <!-- Contents -->
      </div>
    </div>
  </div>
</div>

Quando você encontrar padrões como esse, provavelmente poderá simplificá-los simplificando a estrutura do DOM. Isso reduz o número de elementos DOM e provavelmente oferece a oportunidade de simplificar os estilos da página.

A profundidade do DOM também pode ser um sintoma dos frameworks que você usa. Especificamente, frameworks baseados em componentes, como aqueles que dependem do JSX, exigem que você aninhe vários componentes em um contêiner pai.

No entanto, muitos frameworks permitem evitar o aninhamento de componentes usando o que são conhecidos como fragmentos. Os frameworks baseados em componentes que oferecem fragmentos como um recurso incluem (entre outros):

Ao usar fragmentos no framework escolhido, você pode reduzir a profundidade do DOM. Se você está preocupado com o impacto do achatamento da estrutura DOM no estilo, use modos de layout mais modernos (e mais rápidos), como flexbox ou grid.

Outras estratégias a serem consideradas

Mesmo que você se esforce para achatar a árvore DOM e remover elementos HTML desnecessários para manter o DOM o menor possível, ele ainda pode ser muito grande e iniciar muito trabalho de renderização à medida que muda em resposta às interações do usuário. Se você estiver nessa situação, há outras estratégias que podem ser consideradas para limitar o trabalho de renderização.

Considere uma abordagem aditiva

Talvez você esteja em uma posição em que grandes partes da página não estejam visíveis para o usuário quando ela for renderizada pela primeira vez. Essa pode ser uma oportunidade para carregar o HTML com atraso omitindo essas partes do DOM na inicialização, mas adicionando-as quando o usuário interage com as partes da página que exigem os aspectos inicialmente ocultos da página.

Essa abordagem é útil durante o carregamento inicial e talvez até depois. No carregamento inicial da página, você precisa de menos trabalho de renderização antecipado, o que significa que seu payload inicial de HTML será mais leve e renderizado mais rapidamente. Isso vai dar às interações durante esse período crucial mais oportunidades de execução com menos competição pela atenção da linha de execução principal.

Se muitas partes da página estiverem inicialmente ocultas no carregamento, isso também poderá acelerar outras interações que acionam o trabalho de renderização. No entanto, à medida que outras interações adicionam mais ao DOM, o trabalho de renderização aumenta à medida que o DOM cresce ao longo do ciclo de vida da página.

Adicionar ao DOM ao longo do tempo pode ser complicado e tem suas próprias compensações. Se você estiver seguindo esse caminho, provavelmente está fazendo solicitações de rede para receber dados e preencher o HTML que pretende adicionar à página em resposta a uma interação do usuário. Embora as solicitações de rede em andamento não sejam contadas para a INP, elas podem aumentar a latência percebida. Se possível, mostre um ícone de carregamento ou outro indicador de que os dados estão sendo buscados para que os usuários entendam que algo está acontecendo.

Limitar a complexidade do seletor de CSS

Quando o navegador analisa os seletores no CSS, ele precisa percorrer a árvore DOM para entender como e se esses seletores se aplicam ao layout atual. Quanto mais complexos esses seletores forem, mais trabalho o navegador terá para realizar a renderização inicial da página, além de aumentar os recalculos de estilo e o trabalho de layout se a página mudar como resultado de uma interação.

Usar a propriedade content-visibility

O CSS oferece a propriedade content-visibility, que é uma maneira de renderizar de forma lenta os elementos DOM fora da tela. À medida que os elementos se aproximam da viewport, eles são renderizados sob demanda. Os benefícios de content-visibility não apenas eliminam uma quantidade significativa de trabalho de renderização na renderização inicial da página, mas também pulam o trabalho de renderização para elementos fora da tela quando o DOM da página é alterado como resultado de uma interação do usuário.

Conclusão

Reduzir o tamanho do DOM apenas ao que é estritamente necessário é uma boa maneira de otimizar o INP do seu site. Ao fazer isso, você pode reduzir o tempo que o navegador leva para realizar o layout e a renderização quando o DOM é atualizado. Mesmo que você não consiga reduzir significativamente o tamanho do DOM, há algumas técnicas que podem ser usadas para isolar o trabalho de renderização em um subárvore do DOM, como a contenção de CSS e a propriedade CSS content-visibility.

Seja qual for a abordagem, criar um ambiente em que o trabalho de renderização seja minimizado, além de reduzir a quantidade de trabalho de renderização que sua página faz em resposta às interações, vai resultar em um site mais responsivo para os usuários. Isso significa que você terá um INP menor para seu site, o que se traduz em uma melhor experiência do usuário.