Entender o caminho crítico

O caminho de renderização crítico se refere às etapas envolvidas até que a página da Web comece a ser renderizada no navegador. Para renderizar páginas, os navegadores precisam do próprio documento HTML, bem como de todos os recursos essenciais necessários para renderizar esse documento.

A transferência do documento HTML para o navegador foi abordada no módulo anterior de considerações gerais sobre o desempenho do HTML. Neste módulo, vamos analisar o que o navegador faz depois de fazer o download do documento HTML para renderizar a página.

Renderização progressiva

A Web é distribuída por natureza. Ao contrário dos aplicativos nativos que são instalados antes do uso, os navegadores não podem depender de sites que tenham todos os recursos necessários para renderizar a página. Portanto, os navegadores são muito bons em renderizar páginas progressivamente. Os apps nativos geralmente têm uma fase de instalação e uma de execução. No entanto, para páginas da Web e apps da Web, as linhas entre essas duas fases são muito menos distintas, e os navegadores foram projetados especificamente com isso em mente.

Quando o navegador tem recursos para renderizar uma página, ele normalmente começa a fazer isso. Portanto, a escolha é sobre quando renderizar: quando é muito cedo?

Se o navegador renderizar o mais rápido possível quando tiver apenas HTML, mas antes de ter qualquer CSS ou JavaScript necessário, a página vai parecer temporariamente quebrada e mudar consideravelmente para a renderização final. Essa é uma experiência pior do que apresentar inicialmente uma tela em branco por um tempo até que o navegador tenha mais desses recursos necessários para uma renderização inicial que ofereça uma melhor experiência do usuário.

Por outro lado, se o navegador esperar que todos os recursos estejam disponíveis em vez de fazer renderização sequencial, o usuário vai ficar esperando por muito tempo. Isso pode ser desnecessário se a página estiver utilizável em um momento anterior.

O navegador precisa saber qual é o número mínimo de recursos que ele precisa esperar para evitar apresentar uma experiência obviamente corrompida. Por outro lado, o navegador também não deve esperar mais do que o necessário antes de apresentar algum conteúdo ao usuário. A sequência de etapas que o navegador executa antes de realizar a renderização inicial é conhecida como caminho de renderização crítico.

Entender o caminho de renderização crítico pode ajudar a melhorar a performance da Web, garantindo que você não bloqueie a renderização inicial da página mais do que o necessário. No entanto, também é importante não permitir que a renderização aconteça muito cedo, removendo os recursos necessários para essa renderização inicial do caminho de renderização crítico.

O caminho de renderização (crítico)

O caminho de renderização envolve as seguintes etapas:

  • Criar o modelo de objeto de documento (DOM) a partir do HTML.
  • Criar o modelo de objeto CSS (CSSOM) a partir do CSS.
  • Aplicar qualquer JavaScript que altere o DOM ou o CSSOM.
  • Construção da árvore de renderização a partir do DOM e do CSSOM.
  • Realize operações de estilo e layout na página para ver quais elementos se encaixam onde.
  • Pintar os pixels dos elementos na memória.
  • Compõe os pixels se algum deles se sobrepor.
  • Desenha fisicamente todos os pixels resultantes na tela.
O processo de renderização de HTML e CSS para a exibição de pixels.
O processo de renderização, conforme detalhado na lista anterior.

Só depois que todas essas etapas forem concluídas, o usuário vai ver o conteúdo na tela.

Esse processo de renderização acontece várias vezes. A renderização inicial invoca esse processo, mas, à medida que mais recursos que afetam a renderização da página ficam disponíveis, o navegador executa esse processo novamente, ou apenas partes dele, para atualizar o que o usuário vê. O caminho de renderização crítico se concentra no processo delineado anteriormente para a renderização inicial e depende dos recursos críticos necessários para isso.

Quais recursos estão no caminho de renderização crítico?

O navegador precisa aguardar o download de alguns recursos essenciais antes de concluir a renderização inicial. Esses recursos incluem:

  • Parte do HTML.
  • CSS que bloqueia a renderização no elemento <head>.
  • JavaScript que bloqueia a renderização no elemento <head>.

Um ponto importante é que o navegador processa HTML de forma contínua. Assim que o navegador recebe qualquer parte do HTML de uma página, ele começa a processá-la. O navegador pode renderizar o conteúdo antes de receber o restante do HTML de uma página.

É importante saber que, para a renderização inicial, o navegador não espera por:

  • Todo o HTML.
  • Fontes.
  • imagens
  • JavaScript que não bloqueia a renderização fora do elemento <head> (por exemplo, elementos <script> colocados no final do HTML).
  • CSS que não bloqueia a renderização fora do elemento <head> ou CSS com um valor do atributo media que não se aplica à viewport atual.

Muitas vezes, as fontes e imagens são consideradas pelo navegador como conteúdo a ser preenchido durante renderizações subsequentes da página. Por isso, elas não precisam atrasar a renderização inicial. No entanto, isso pode significar que áreas de espaço em branco são deixadas na renderização inicial enquanto o texto fica oculto aguardando fontes ou até que as imagens fiquem disponíveis. Pior ainda é quando o espaço suficiente não é reservado para determinados tipos de conteúdo, principalmente quando as dimensões da imagem não são fornecidas no HTML. O layout da página pode mudar quando esse conteúdo é carregado mais tarde. Esse aspecto da experiência do usuário é medido pela métrica Cumulative Layout Shift (CLS).

O elemento <head> é fundamental para processar o caminho de renderização crítico. Tanto que a próxima seção aborda isso em detalhes. Otimizar o conteúdo do elemento <head> é um aspecto importante do desempenho da Web. Para entender o caminho de renderização crítico por enquanto, você só precisa saber que o elemento <head> contém metadados sobre a página e os recursos dela, mas nenhum conteúdo que o usuário possa ver. O conteúdo visível está contido no elemento <body> que segue o elemento <head>. Antes que o navegador possa renderizar qualquer conteúdo, ele precisa tanto do conteúdo a ser renderizado quanto dos metadados sobre como renderizá-lo.

No entanto, nem todos os recursos referenciados no elemento <head> são estritamente necessários para a renderização inicial da página. Portanto, o navegador aguarda apenas aqueles que são. Para identificar quais recursos estão no caminho de renderização crítico, você precisa entender o CSS e o JavaScript de bloqueio de renderização e de parser.

Recursos que bloqueiam a renderização

Alguns recursos são considerados tão críticos que o navegador pausa a renderização da página até que eles sejam processados. O CSS se enquadra nessa categoria por padrão.

Quando um navegador detecta CSS, seja um CSS inline em um elemento <style> ou um recurso referenciado externamente especificado por um elemento <link rel=stylesheet href="...">, ele evita renderizar mais conteúdo até que o download e o processamento desse CSS sejam concluídos.

Só porque um recurso bloqueia a renderização não significa necessariamente que ele impede o navegador de fazer qualquer outra coisa. Os navegadores tentam ser o mais eficientes possível. Portanto, quando um navegador percebe que precisa fazer o download de um recurso CSS, ele o solicita e pausa a renderização, mas continua processando o restante do HTML e procura outro trabalho para fazer enquanto isso.

Recursos de bloqueio de renderização, como CSS, usados para bloquear toda a renderização da página quando são descobertos. Isso significa que se um CSS está bloqueando a renderização ou não depende se o navegador o descobriu. Alguns navegadores (Firefox inicialmente e agora também o Chrome) bloqueiam apenas a renderização de conteúdo abaixo do recurso de bloqueio de renderização. Isso significa que, para o caminho crítico de bloqueio de renderização, geralmente estamos interessados em recursos de bloqueio de renderização no <head>, porque eles bloqueiam efetivamente a renderização de toda a página.

Uma inovação mais recente é o atributo blocking=render, adicionado ao Chrome 105. Isso permite que os desenvolvedores marquem explicitamente um elemento <link>, <script> ou <style> como bloqueador de renderização até que o elemento seja processado, mas permitindo que o analisador continue processando o documento nesse meio tempo.

Recursos de bloqueio do analisador

Os recursos de bloqueio de analisador são aqueles que impedem o navegador de procurar outro trabalho para fazer, continuando a analisar o HTML. Por padrão, o JavaScript bloqueia o parser, a menos que seja marcado especificamente como assíncrono ou adiado, já que ele pode mudar o DOM ou o CSSOM durante a execução. Portanto, não é possível que o navegador continue processando outros recursos até que conheça o impacto total do JavaScript solicitado no HTML de uma página. O JavaScript síncrono bloqueia o analisador.

Os recursos que bloqueiam o analisador também bloqueiam a renderização. Como o parser não pode continuar após um recurso de bloqueio de análise até que ele seja totalmente processado, ele não pode acessar e renderizar o conteúdo depois disso. O navegador pode renderizar qualquer HTML recebido até o momento enquanto aguarda, mas, no que diz respeito ao caminho de renderização crítico, qualquer recurso de bloqueio de parser no <head> significa que todo o conteúdo da página é bloqueado para renderização.

Bloquear o analisador pode ter um custo de desempenho enorme, muito maior do que bloquear a renderização. Por esse motivo, os navegadores tentam reduzir esse custo usando um analisador de HTML secundário conhecido como scanner de pré-carregamento para fazer o download de recursos futuros enquanto o analisador de HTML principal está bloqueado. Embora não seja tão bom quanto analisar o HTML, ele pelo menos permite que as funções de rede no navegador funcionem antes do analisador bloqueado, o que significa que é menos provável que ele seja bloqueado novamente no futuro.

Identificar recursos de bloqueio

Muitas ferramentas de auditoria de performance identificam recursos de renderização e de bloqueio do analisador. O WebPageTest (link em inglês) marca os recursos de bloqueio de renderização com um círculo laranja à esquerda do URL do recurso:

Diagrama de cascata de rede gerado pelo WebPageTest. Os recursos que bloqueiam o analisador são indicados por um círculo laranja à esquerda do URL do recurso, e o tempo de início da renderização é identificado por uma linha verde escura sólida.
Diagrama em cascata de rede gerado pelo WebPageTest.

Todos os recursos de bloqueio de renderização precisam ser transferidos por download e processados antes que a renderização possa começar, o que é indicado pela linha verde escura sólida na cascata.

O Lighthouse também destaca recursos que bloqueiam a renderização, mas de maneira mais sutil, e somente se o recurso realmente atrasar a renderização da página. Isso pode ser útil para evitar falsos positivos, em que você minimiza o bloqueio de renderização. A execução do mesmo URL da página do WebPageTest anterior pelo Lighthouse identifica apenas uma das folhas de estilo como um recurso de bloqueio de renderização.

Auditoria do Lighthouse para eliminar recursos que impedem a renderização. A auditoria mostra os recursos que bloqueiam a renderização e o tempo de bloqueio.
Auditoria do Lighthouse para eliminar recursos que impedem a renderização.

Otimizar o caminho crítico de renderização

Otimizar o caminho de renderização crítico envolve reduzir o tempo para receber o HTML (representado pela métrica Tempo para o primeiro byte (TTFB)), conforme detalhado no módulo anterior, e reduzir o impacto dos recursos de bloqueio de renderização. Esses conceitos serão investigados nos próximos módulos.

O caminho de renderização de conteúdo crítico

Por muito tempo, o caminho de renderização crítico se preocupou com a renderização inicial. No entanto, surgiram mais métricas centradas no usuário para a performance da Web, o que levanta algumas dúvidas sobre se o ponto final do caminho de renderização crítico deve ser a primeira pintura ou uma das pinturas mais contidas que se seguem.

Uma perspectiva alternativa é se concentrar no tempo até a maior exibição de conteúdo (LCP) ou até a primeira exibição de conteúdo (FCP) como parte de um caminho de renderização de conteúdo (ou o caminho de chave, como outros podem chamar). Nesse caso, talvez seja necessário incluir recursos que não são necessariamente de bloqueio, como a definição típica do caminho de renderização crítico, mas que são necessários para renderizar pinturas com conteúdo.

Independentemente da sua definição exata do que é "crítico", é importante entender o que impede a renderização inicial e o conteúdo principal. O primeiro paint mede a primeira oportunidade possível de renderizar qualquer coisa para o usuário. O ideal é que seja algo significativo, não como uma cor de plano de fundo, por exemplo. No entanto, mesmo que não tenha conteúdo, apresentar algo ao usuário ainda é importante, o que é um argumento para medir o caminho de renderização crítico, conforme definido tradicionalmente. Ao mesmo tempo, também é importante medir quando o conteúdo principal é apresentado ao usuário.

Identificar o caminho de renderização com conteúdo

Muitas ferramentas podem identificar elementos de LCP e quando eles são renderizados. Além do elemento LCP, o Lighthouse também ajuda a identificar as fases da LCP e o tempo gasto em cada uma para entender onde concentrar seus esforços de otimização:

A auditoria de LCP do Lighthouse, que mostra o elemento LCP de uma página e o tempo gasto em fases, como TTFB, atraso de carregamento, tempo de carregamento e atraso de renderização.
Auditoria de LCP do Lighthouse.

Para sites mais complexos, o Lighthouse também destaca cadeias de solicitações críticas em uma auditoria separada:

Diagrama da cadeia de solicitações críticas do Lighthouse, que mostra quais recursos críticos estão aninhados abaixo de outros recursos críticos, além da latência total envolvida na cadeia de solicitações críticas.
Diagrama da cadeia de solicitações críticas do Lighthouse.

Essa auditoria do Lighthouse observa todos os recursos carregados com alta prioridade, portanto, inclui fontes da Web e outros conteúdos que o Chrome define como um recurso de alta prioridade, mesmo que não seja um bloqueio de renderização.

Teste seus conhecimentos

A que o caminho de renderização crítico se refere?

A quantidade mínima de recursos necessários para renderizar totalmente uma página.
Tente novamente.
A quantidade mínima de recursos necessária para renderizar uma página inicial.
Correto!

Quais recursos estão envolvidos no caminho de renderização crítico?

Parte do HTML.
Correto!
CSS que bloqueia a renderização no elemento <head>.
Correto!
JavaScript que bloqueia a renderização no elemento <head>.
Correto!

Por que o bloqueio de renderização é uma parte necessária da renderização da página?

Para impedir que uma página seja renderizada inicialmente em um estado inutilizável ou aparentemente corrompido.
Correto!
Para impedir que os usuários vejam uma página até que ela seja renderizada completamente.
Tente novamente.

Por que o JavaScript bloqueia o analisador de HTML (assumindo que os atributos defer, async ou module não sejam especificados em um elemento <script>)?

Sem pelo menos um desses atributos, um <script> bloqueia o analisador e a renderização.
Correto!
Todo JavaScript bloqueia o analisador, independentemente desses atributos.
Tente novamente.
O JavaScript síncrono precisa ser executado quando o analisador o alcança, porque ele pode mudar o DOM.
Correto!

Próximo passo: otimizar o carregamento de recursos

Este módulo abordou parte da teoria por trás da renderização de uma página da Web e, em particular, o que é necessário para concluir a renderização inicial de uma página. O próximo módulo analisa como esse caminho de renderização pode ser otimizado aprendendo como otimizar o carregamento de recursos.