CRITICAL

Rendering Path

Hugo Deiró

hugodeiro.com

/hugodeiro

/hdeiro

/hdeiro

hugodeiro@gmail.com

/hdeiro

O que é Critical Rendering Path?

Uma série de recomendações pautadas em como o navegador funciona  visando entregar páginas mais rápidas e/ou otimizadas

O Critical Rendering Path influencia em diversos aspectos, desde a User Experience (UX) até Search Engine Optimization (SEO)

Representação da atuação do

Critical Rendering Path

Já que o Critical Rendering Path atua sobre o processo de renderização, é bom entendermos sobre como ele se dá

Como se dá o processo de renderização?

Pipeline de Renderização

HTML Parsing / Construção do DOM

DOM ⇔ Document Object Model

CSS Parsing / Construção do CSSOM

CSSOM ⇔ Cascade Style Sheet Object Model

DOM + CSSOM

DOM + CSSOM

Após a "fusão" do DOM e CSSOM, a Render Tree conterá todos os nós necessários para a renderização

Após a construção da Render Tree, é feito o processo de Layout, também chamado de Reflow Processing

 

Durante esta etapa são calculados o tamanho e a posição de cada elemento da Render Tree

Após o Reflow, acontece o Painting Process, no qual os pixels são efetivamente renderizados em tela

Redimensionamentos e outras mudanças bruscas tendem a degradar a performance da aplicação

 

Isso acontece porque este tipo de mudança desencadeia a re-execução de todo processo de Reflow e Paint

Existem várias medidas que o desenvolvedor pode tomar para tornar sua aplicação web o mais próxima possível do caminho crítico de renderização

Shall we begin?

LISPECTOR, Daenerys

HTML

O HTML é um recurso bloqueador de renderização

 

Isso implica que o browser não irá renderizar nada até o DOM estar pronto. 

Documente seu código

(mas cuidado)

 

Por questões de manutenção, é sempre bom você manter seu código comentado. Porém, se você não utilizar uma ferramenta de build automatizado com uma task para removê-los, eles gerarão uma carga extra para o browser que precisará interpretar os comentários

 Minifique seu código

 

A minificação é um processo de remoção de quebras de linhas, espaços em brancos e name-mangling (troca de nomes) de possíveis elementos

 Especifique o DTD

 

O Document Type Declaration (DTD), também conhecido como DOCTYPE. Essa declaração é utilizada para informar ao interpretador do browser que tipo de código está sendo apresentado (HTML, xHTML, SVG etc)

<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>

<body>
The content of the document......
</body>

</html>

Cuidado com o alt="..."

 

O atributo alt="..." é (ou pelo menos deveria ser) amplamente utilizado em imagens. Este atributo não só torna seu site mais acessível para pessoas com deficiência visual, mas também otimiza aspectos de SEO

 

O grande problema está em como estas descrições são aplicadas. Descrições longas podem degradar a performance e rastreabilidade da sua página web por deixarem sua página mais pesada do que deveria 

Feche suas tags

 

Pode até parecer uma recomendação trivial. Porém tags não fechadas podem implicar em erros de interpretação.

 

Um erro destes pode fazer com que seu código fique mais complexo de ser interpretado, por forçar ao browser inferir mais decisões do que deveria. Isso acaba deixando o site mais lento podendo, na verdade, não carregar todo seu código HTML

Evite estruturas complexas

 

Na maioria das vezes o que fazemos pode ser simplificado com um simples refactoring. Pedir opiniões de colegas tende a ajudar nessa simplificação

 

As estruturas complexas tendem a deixar seu dom com mais nós do que deveria, tornando sua interpretação mais lenta do que deveria

Incorpore código

 

É possível incorporar códigos SVG, JavaScripts e CSS direto no HTML a fim de reduzir o número de requests e forçar a leitura/interpretaçao desse código mais rapidamente

CSS

O CSS é um recurso bloqueador de renderização

 

Isso implica que o browser não irá renderizar nada até o CSSOM estar pronto. Por causa disso, é importante entregar o CSS para o cliente o mais rápido possível

 

Isso pode ser feito através de incorporação de código crítico e/ou carregamento assíncrono (trazendo o que deve ser interpretado de cara síncronamente e os códigos não críticos assíncronamente)

O Critical Rendering Path sugere incorporar códigos críticos no HTML e trazer os demais de forma assíncrona

Use pré-processadores

 

A utilização de pré-processadores traz uma série de vantagens por viabilizar capabilities que o CSS não tem por padrão ou que ainda não é amplamente suportada (como variáveis, funções, herança etc)

 

A implementação correta dessas capabilities em um pré-processador como SASS, Less, Stylus ou qualuqer outro tende a tornar o código muito mais manutenível e otimizado (visto que estas ferramentas acabam por otimizar o código-fonte compilado)

Minifique seu código

 

Menos é mais, neste caso

Concatene seu código (!)

 

É um assunto meio polêmico. Pois a concatenação de código CSS acaba deixando o arquivo maior, porém, reduz a quantidade de folhas de estilo que serão requisitadas pelo browser

 

Deve-se ponderar sobre o que deve ser concatenado ou não

Evite seletores descendentes

 

Seletores descendentes tornam o processo de captura dos nós para estilização muito mais complexo para o browser, visto que regras do CSS são interpretadas da direita para a esquerda.

<ul>
    <li>
        <a href="#">Meu Link 1</a>
        <a href="#">Meu Link 2</a>
    </li>
</ul>

<style>
    ul li a {
        color: #F2AB09;
        font-size: 10px;
    }
</style>
<ul>
    <li>
        <a href="#" class="link-boladao">Meu Link 1</a>
        <a href="#" class="link-boladao">Meu Link 2</a>
    </li>
</ul>

<style>
    .link-boladao {
        color: #F2AB09;
        font-size: 10px;
    }
</style>

Bom

Ruim

Evite seletores universais

 

Seletores como *, [disabled], [type="text"], por exemplo, são bastante custosos para o browser por forçar a checagem de cada um dos elementos do DOM

 

Use, mas não abuse. Isso aqui não é C&A

Utilize propriedades custosas com moderação

 

Propriedades como border-radius, box-shadow, transform, filter e position:fixed são úteis, porém relativamente custosas para o browser. Pode utilizar, mas cuidado para não exagerar

Force renderização em GPU

 

Existe um "hack" que força a utilização da GPU ao invés da CPU para a renderização do CSS/HTML por implicar na utilização de três dimensões (3D). Isso acaba desonerando a CPU, tornando a renderização um pouco mais rápida

body {
    transform: translateZ(0);
}

CSS carregado sob condições

 

Podem surgir situações em que você precise de uma folha de estilo para impressões, ou para telas de celulares (não por redimensionamento, mas realmente de um dispositivo móvel)

 

É possível condicionar a chamada destes CSS para quando ele realmente for necessário

<link href="style.css" rel="stylesheet">
<link href="print.css" rel="stylesheet" media="print">
<link href="print.css" rel="stylesheet" media=“handhelds">

<!-- Browser Specific for IE6 -->

<!–[if IE 6]>
	<link rel=“stylesheet” type=“text/css” href=“ie6.css”>
<![endif]–>

Use shorthands

 

O processo de renderização pode ser bastante simplificado a partir da utilização de shorthands do CSS

.minha-classe {
    margin-top: 10px;
    margin-right: 8px;
    margin-bottom: 6px;
    margin-left: 10px;
}
.minha-classe {
   margin: 10px 5px 6px 8px;
}

==

KISS

 

Keep It Simple, Stupid!

 

Mantenha seu código simples, utilize pré-processadores, utilize alguma metodologia de desenvolvimento como o BEM, OOCSS, SMACSS, DRY CSS etc

CUIDADO com CSS-Reset

 

A utilização de CSS-Reset é uma prática bastante comum para limpar estilos-padrão que os browsers estabelecem para páginas WEB

 

O grande problema é que pelo fato de serem extremamente genéricos, podem estar limpando elementos que não serão utilizados em seu site  (como um <ol>), e isso gera um overhead desnecessário na renderização

Importe o CSS de forma assíncrona

 

É possível importar o CSS como um preload

<!-- Inicia como um preload e depois alterna para estilo -->
<link rel="preload" as="style" href="estilo.css" onload="this.rel='stylesheet'"/>

<!-- Fallback pro caso de JavaScript estar bloqueado -->
<noscript><link rel="stylesheet" href="estilo.css" type="text/css"/></noscript>

Utilize alguma solução de JavaScript para o caso do browser não suportar preloads

Use cache

 

A utilização de cache retira a necessidade de ficar sempre requisitando arquivos que não mudam com frequência (como o Bootstrap, por exemplo). Estes arquivos poderiam ser cacheados para que em futuros acessos o usuário não precisasse mais baixar aquele arquivo.

JavaScript

 

<3

Por poder atuar diretamente no DOM e em parte do CSSOM, o JavaScript é indiretamente um recurso bloqueador de renderização

 

As recomendações são extremamente parecidas com as do CSS:

 

  • Disponibilize o JS o mais rapidamente possível
  • Incorpore o código crítico
  • Carregue de forma assíncrona o que não for crítico

Sempre que possível,

carregue seu código de forma assíncrona

 

Carregar o JavaScript de forma assíncrona atenua o impacto no carregamento do DOM. Você pode fazer isso através de bibliotecas específicas para isso como o RequireJS, SystemJS etc; ou requerendo-os a partir utilizando o atributo async

 

Também é possível carregar script após a construção do DOM e CSSOM usando defer, contudo eles serão carregados na ordem que forem inseridos

 

 

<script async src="meuscript.js"></script>
<script defer src="meuscript.js"></script>
<script defer src="meuscript2.js"></script>

Minifique seu código

 

A minificação, como dito anteriormente, torna seu código menor, fazendo com que o mesmo seja adquirido e interpretado mais rapidamente

 

Agora, tenha cuidado para o name-mangling não te causar problemas devido a mudança de nomes de variáveis.

 

Sempre re-teste seu código JavaScript após minificá-lo

Concatene seu código

 

A partir da concatenação você unifica todos (ou parte) de seus scripts em um único arquivo que, apesar de ser mais pesado que os demais, reduz a quantidade de requisições que o browser fará

 

Este ponto, especificamente, é discutível. Pois pode trazer códigos que não são críticos e que, consequentemente, não precisarão ser utilizados na hora

Coloque os scripts no final do HTML

 

O fato de você colocar os scripts no final do HTML reduz o tempo de renderização porque irá viabilizar o começo da construção do DOM e CSSOM mais rapidamente

PRPL - Push, Render, Pre-cache & Lazy-load

 

O PRPL é um padrão que otimiza o gerenciamento de códigos a partir de um massivo code-spliting e code-caching

 

Basicamente, ele pré-carrega alguns recursos que serão utilizados em outras views/rotas

 

Os Service Workers são muito utilizados para gerenciar o cacheamento e carregamento destes arquivos

Prefira, sempre que possível, animações em CSS ao invés de JavaScript

 

Como o CSS é pré-interpretado pelo browser, ele demanda menos processamento do que o JavaScript

 

Outra vantagem é que através das animações CSS você pode forçar a renderização em GPU ao invés de CPU

Faça uso de cache

 

A utilização de cache retira a necessidade de requerer arquivos que não mudam com frequência

 

Scripts de bibliotecas ou frameworks como JQuery, Angular, Vue e React, por exemplo, podem ser cacheados de forma que o usuário não precise requerer aquele arquivo novamente durante um período de tempo

Evite interações com DOM, Canvas etc

 

A interação com elementos do DOM, Canvas e afins tende a gerar uma degradação da performance por implicar em reflow e repaint

 

O Reflow é basicamente o recálculo do posicionamento, tamanho e outros atributos dos elementos que compõem o DOM

 

O Repaint é a reimpressão destes elementos em tela

 

Reavalie suas dependências

 

É comum que com o passar do tempo sejam adicionadas novas dependências enquanto algumas outras podem cair em desuso

 

Neste caso, sempre que deixar de utilizar uma dependência, lembre de removê-la do projeto, de forma a evitar processamento desnecessário

Cuidado com manipulação de eventos

 

Os eventos são uma ferramenta incrível. Porém, quando não utilizados corretamente, podem degradar sua aplicação

 

  • Eventos de rápida sucessão, como o mousemove, por exemplo;
  • Remover event listeners quando não precisar mais deles;
  • Event Bubling
<html>
 <body>
  <div id="div">
   <button id="botao">CLICA</button>
  </div>

  <script type="text/javascript">
   document.querySelector("#botao").addEventListener('click', event => console.log('CLIQUE EM BOTAO'));
   document.querySelector("#div").addEventListener('click', event => console.log('CLIQUE EM DIV'));
   document.querySelector("body").addEventListener('click', event => console.log('CLIQUE EM BODY'));
  </script>
 </body>
</html>

Tente seguir a especificação

da Ecma Foundation

 

O EcmaScript (nome oficial do JavaScript) é mantido pela Ecma Foundation. Sua especificação para o JavaScript define os propósitos e usos gerais do JavaScript

 

Essas especificações são seguidas por quem desenvolve browsers (seja Google, Microsoft, Apple, Mozilla etc) para implementar a forma com que o JavaScript deve ser interpretado

 

Convém ressaltar que essas empresas não implementam, necessariamente, todas especificações do JavaScript. Podem haver funcionalidades que estão implementadas em um browser e no outro não, contudo, isso tem se tornado cada vez mais raro

Fontes

Evite utilizar fontes demais

 

Utilizar muitas fontes implica em um trabalho extra para o browser

Evite utilizar muitas variantes

 

Só mantenha em seu código as fontes e variantes (semibold, italic etc) que você realmente usa

Evite utilizar muitas variantes

 

Só mantenha em seu código as fontes e variantes (semibold, italic etc) que você realmente usa

Forneça os formatos otimizados para cada navegador

 

Cada um dos formatos (WOFF2, WOFF, EOT, TTF etc) tende a ser mais otimizado para um browser ou outro. Portanto, opte por disponibilizar estes formatos que o browser se encarregará de utilizar o mais apropriado

 

Caso você não tenha todos formatos, existem ferramentas online (como o Transfonter, por exemplo) que convertem a fonte que você disponibilizar para os demais formatos

Utilize cache

 

Como as fontes são um recurso que não tendem a ser alteradas ao longo do tempo, podem, sem sombra de dúvidas, ser cacheadas

Font Loading API

 

A utilização da Font Loading API pode otimizar seu Critical Rendering Path por viabilizar carregamento assíncrono de fontes, entre outras funcionalidades

Imagens

As imagens na maioria das vezes as grandes vilãs na performance de páginas web

Mas na maioria das vezes,

também são essenciais

Lazy-load

 

O carregamento assíncrono de imagens geralmente já melhora bastante a velocidade de renderização quando se tem muitas imagens

 

Não existe muita vantagem em carregar imagens do final do site, se o usuário ainda está no começo

Tente utilizar formatos otimizados

 

Imagens em formatos otimizados como .webp dão um ganho de performance na renderização destas imagens

 

Porém, muito cuidado com questões de performance! 

Comprima imagens (por favor!)


Na maioria das vezes, as imagens tem metadados que não tem nenhuma utilidade para o browser (como o modelo da câmera que tirou a foto, por exemplo).


Além disso, dependendo do caso, também é possível reduzir a qualidade da mesma para diminuir o seu tamanho


Existem diversas ferramentas (como o TinyPNG e kraken.io, por exemplo) para realizar a compressão de imagens

Prefira estilizar diretamente na imagem

 

Se você tem uma imagem que vai servir apenas para ser um background com blur (por exemplo), opte por já disponibilizar a imagem com este estilo já aplicado ao invés de fazer isso via CSS

 

Agora, claro, só faça isso se a imagem sempre for ser utilizada daquela forma

Evite redimensionar no Front-end

 

Redimensionamento == Reflow / Repaint

 

Tente disponibilizar as imagens já no tamanho que elas devem se utilizadas. Por exemplo, se você vai usar uma imagem 200x200, pra quê você disponibilizaria uma imagem 1200x1200?

Tente utilizar sempre SVG ou font-icon para seus ícones

 

Dependendo da forma com que seja utilizado, o SVG já pode ser interpretado junto do HTML

 

Font-icons são melhores do que imagens por tratar as mesmas como fontes a serem utilizadas em elementos HTML

Cuidado com o tipo de imagem que usa

NUNCA use imagem

onde puder usar uma fonte

Se for utilizar muitas imagens pequenas, pense em utilizar um sprite

Repense se você realmente precisa daquela imagem

Outros

Se possível, use uma Content Delivery Network (CDN) 

Transmita dados como GZIP

server {
	...
	//Configurações de GZIP no Servidor NGINX
	gzip on;
	//Somente o HTML é comprimido por padrão
	gzip_types text/css application/javascript images/svg+xml;
}

Se possível, use HTTP2


  1. Remove restrição de 6 requisições por ter request multiplexada/assíncrona;
  2. Implementa Diff Request, omitindo headers que já foram enviados em outros momentos;
  3. Comprime Headers (Algoritmo HPACK)
  4. Implementa GZip por Padrão
  5. Reduz a necessidade de concatenação de arquivos

Cacheie tudo que puder

Utilize uma ferramenta de build para te auxiliar

 

Existem diversas opções como: Webpack, Grunt, Gulp, Browserify, Parcel e Yeoman

 

Cuidado com o Round Trip Time (RTT)

 

A latência da rede (RTT) implica na velocidade de transmissão dos bytes. Se possível, é bom optar por locais mais próximos dos prováveis usuários finais para reduzir o RTT.

 

Uma página web precisa de vários RTTs para funcionar. Desde o DNS Lookup (conversão da URL pra IP) até a HTTP Request

Após incorporar o código (SVG, CSS, JS etc), tente se manter no limite de 1460kb

 

Há uma especificação (RFC 6928) que indica aumentar o tamanho das janelas transmitidas pelo TCP para 10.

 

Cada janela tem 1460b, ou seja 1460b*10 = ~1460kb.

 

Isso implica em uma renderização mais rápida, visto que toda informação necessária é transmitida logo no começo (1 RTT)

 

Note que isso se refere ao tamanho transmitido, não ao tamanho real do arquivo necessariamente (ou seja, se você usa GZip, o arquivo pode ser um pouco maior do que 1460kb)

Utilize o resource hint preconnect para otimizar acesso a serviços externos

 

O resource-hint preconnect permite rodar em paralelo às requisições todo processo de DNS-Prefetch (busca do IP), SSL Handshake (tratamento de certificados de segurança, HTTPS) e abertura de conexão com o servidor.

 

 

 

Apesar de útil, é sugerível não exagerar nos preconnects para não afetar o processo das requisições.

 

 

<link rel="preconnect" href="//meu_video_do_youtube"/>
<link rel="preconnect" href="//meu_video_do_vimeo"/>

Utilize o resource-hint prefetch para pré-carregar e carregar informações

 

Utilizando o resource-hint prefetch é possível fazer o pré-download de arquivos e cachear os mesmos para uso futuro

 

 

É importante saber que o prefetch tem menos prioridade que as demais requisições. Portanto, seu uso é indicado para pré-carregar informações de páginas que ainda não estão sendo usadas mas que tem grande probabilidade de serem chamadas

<link rel="prefetch" href="script-da-proxima-pagina.js">
<link rel="prefetch" href="css-da-proxima-pagina.css">

Utilize o resource-hint preload para pré-carregar e carregar informações de alta prioridade

 

O resource-hint preload viabiliza o pré-carregamento de informações de alta prioridade.

 

É possível utilizar um atributo "as" informando para o browser com que prioridade ele deve baixar aquele resource.

 

É possível utilizar um atributo "type" para condicionar o download daquele resource ao suporte do navegador.

<link rel="preload" href="assets/styles/meuestilo.css" as="css">
<link rel="preload" href="assets/images/foto.jpg" as="image">
<link rel="preload" href="assets/fonts/OpenSans.woff2" as="font" type="font/woff2">
<link rel="preload" href="assets/fonts/OpenSans.ttf" as="font" type="font/ttf">

Utilize o resource-hint prerender para pré-renderizar páginas

 

O resource-hint prerender permite que o browser pré-renderize páginas HTML antes do usuário efetivamente abri-las.

 

Isso é feito em uma aba oculta. Quando o usuário vai efetivamente para a página, o navegador basicamente "transforma" essa aba oculta na aba principal.

 

 

Deve-se tomar cuidado com a pré-renderização para não sobrecarregar o browser do usuário. Além disso, indica-se também fazer a adição do pre-render dinamicamente via JS

<link rel="prerender" href="index.html">

Obrigado!

Depois me digam o que acharam

hugodeiro.com

/hugodeiro

/hdeiro

/hdeiro

hugodeiro@gmail.com

/hdeiro

Critical Rendering Path

By Hugo Deiró

Critical Rendering Path

Este slide aborda o Critical Rendering Path e recomendações de como otimizar páginas web.

  • 453