Tempos de exibição de CSS e peso de renderização da página

Introdução

Se você é do tipo de pessoa que acompanha coisas como como os navegadores funcionam, já sabe que há alguns artigos incríveis detalhando a operação de renderização/composição acelerada por GPU do Chrome. Em primeiro lugar, Renderização acelerada no Chrome: o modelo de camadas é uma ótima introdução sobre como o Chrome usa o conceito de camadas para desenhar a página. Para uma análise mais detalhada, Composição acelerada por GPU no Chrome discute como o Chrome usa essas camadas, junto com a GPU para renderizar sua página.

A pergunta filosófica

Depois de passar muito tempo criando rasterizadores de software para fins 3D, ficou claro na minha mente que algumas propriedades de CSS deveriam ter um desempenho variado ao desenhar sua página. Por exemplo, a rasterização de uma imagem pequena na tela é uma operação algorítmica completamente diferente do que desenhar uma sombra projetada em uma forma arbitrária. A pergunta passou a ser: Como as diferentes propriedades do CSS afetam o peso de renderização da sua página?

Meu objetivo era categorizar um grande conjunto de propriedades/valores CSS pelos tempos de pintura, para entendermos quais tipos de propriedades CSS têm mais desempenho do que outros. Para isso, escrevi automação com fita adesiva e chiclete para tentar adicionar visibilidade numérica aos tempos de pintura do CSS, que funcionou assim:

  • Gerar um conjunto de páginas HTML individuais, cada uma com um único elemento DOM e algumas permutações de propriedades CSS anexadas a ele.
  • Execute um script de automação que, em cada página, vai fazer o seguinte:
    • Abrir o Chrome
    • Carregar uma página
    • Produza uma imagem Skia Picture para a página
    • Execute cada imagem do Skia tirada pelo Skia Benchmark para receber os tempos.
  • Descarte todos os tempos e se surpreenda com os números. (Esta parte é importante…)

Com essa configuração, geramos um conjunto de páginas HTML, em que cada página contém uma permutação exclusiva de propriedades e valores CSS. Por exemplo, confira estes dois arquivos HTML:

<style>
#example1 {
    background: url(foo.png) top left / 50% 60%;
    padding: 20px; 
    margin-top: 10px;
    margin-right: 20px; 
    text-align: center;
}
</style>
<div id="example1">WOAH</div>

E outra, mais complexa

<style>
#example1 {
    background-color:#eee;
    box-shadow: 1px 2px 3px 4px black;
    border-radius: 50%;
    background: radial-gradient(circle closest-corner, white, black);
    padding: 20px; 
    margin-top: 10px;
    margin-right: 20px; 
    text-align: center;
}
</style>
<div id="example1">WOAH</div>

Veja abaixo, como variante do último exemplo, em que apenas o valor do gradiente radial é alterado:

<style>
#example1 
{
    background-color:#eee;
    box-shadow: 1px 2px 3px 4px black;
    border-radius: 50%;
    background: radial-gradient(farthest-side, white, black);
    padding: 20px; 
    margin-top: 10px;
    margin-right: 20px; 
    text-align: center;
}
</style>
<div id="example1" style="padding: 20px; margin-top: 10px;margin-right: 20px; text-align: center;">WOAH</div>

Cada página é carregada em uma instância nova do Chrome para garantir que os tempos não sejam enviesados por estados desatualizados em recarregamentos de página. Além disso, uma imagem Skia (*.SKP) é usada para avaliar quais comandos Skia são usados para pintar a página. Depois que os arquivos SKP são gerados para cada arquivo HTML, executamos outro lote para enviar os arquivos *.SKP pelo aplicativo Skia Benchmark (criado com o código-fonte do Skia), que descarta o tempo médio necessário para renderizar essa página.

Como avaliar os dados

Com isso, agora temos a capacidade aproximada de registrar o tempo que um conjunto de propriedades CSS leva para pintar. Ou seja, podemos começar a classificar as propriedades do CSS de acordo com a performance de pintura. Este é um gráfico grande feito com o Chrome 27 Beta mostrando todos os dados de tempo desse processo. Todos os dados estão sujeitos a mudanças à medida que o Chrome fica cada vez mais rápido com o tempo.

Momentos de todas as permutações no teste

Cada barra vertical representa o tempo de pintura de uma página com uma única combinação de propriedades CSS (ampliada em 100x; o valor real da escala deste gráfico é 0,1.56ms). Muitas linhas bonitas, mas nesse formato são um tanto inúteis. Precisamos fazer uma mineração de dados para encontrar tendências úteis.

Primeiro, encontramos provas de que algumas propriedades CSS simplesmente são mais caras de renderizar do que outras. Por exemplo, desenhar uma sombra projetada em um elemento DOM envolve uma operação de várias passagens com splines e outros tipos de coisas desagradáveis, em vez de opacidade, que é mais fácil de renderizar.

Tempo gasto para pintar um elemento que tem apenas uma propriedade CSS

Em segundo lugar, e mais interessante, combinações de propriedades CSS podem ter um tempo de pintura maior do que a soma das partes delas. Do ponto de vista de um observador, isso é um pouco estranho. Esperaríamos que A+B = C, não 2,2C. Por exemplo, adicionar box-shadow e border-radius-stroke:

Tempos de todas as permutações no teste

O que é realmente interessante sobre isso é que não é apenas a propriedade box-shadow em si, mas essa permutação de valor específica (link em inglês). Por exemplo, abaixo mostra um agrupamento de box-shadow : 50% e border-radius com variações de valor.

Tempos de todas as permutações no teste

Analisando os dados, isso continua por um tempo. Há diversas combinações estranhas, e meu pacote de testes quase não afeta todas elas. Ainda há vários testes e combinações que podem gerar resultados interessantes

Como encontrar o peso de renderização da página

Com a capacidade de rastrear os tempos de renderização de cada elemento na página, os desenvolvedores podem começar a avaliar o peso de renderização da página e como ele afeta a capacidade de resposta do site. Confira algumas dicas para começar.

  1. Use o modo de pintura contínua do Chrome nas Ferramentas para desenvolvedores do Chrome para entender quais propriedades CSS estão custando.
  2. Incorpore as análises de CSS ao seu processo de análise de código para detectar problemas de desempenho. Procure no CSS lugares em que você está usando recursos que são conhecidos por serem mais caros, como gradientes e sombras. Pergunte a si mesmo: "Eu realmente preciso disso aqui?"
  3. Em caso de dúvida, sempre opte pela melhor performance. Talvez os usuários não se lembrem da largura do padding nas colunas, mas vão se lembrar de como é visitar seu site.

Considerações finais

Uma das coisas mais interessantes sobre esse experimento é que os tempos vão continuar mudando com cada versão do Chrome (espero que se tornem mais rápidos ;). O software do navegador é uma área de superfície em constante mudança. O que é lento hoje pode ser rápido amanhã. Você pode evitar colocar box-shadow: 1px 2px 3px 4px em um elemento que já tem border-radius:5. No entanto, a conclusão mais valiosa deve ser que as propriedades do CSS afetam diretamente os tempos de pintura da página.

Referências