Evitar pinturas desnecessárias - Edição de GIFs animados

Evitar pinturas é fundamental para alcançar uma taxa de frames suave, especialmente em dispositivos móveis. No entanto, às vezes, as tintas aparecem nos lugares mais incomuns. Este artigo analisa por que os GIFs animados podem causar pinturas desnecessárias e a correção simples que você pode aplicar.

Camadas de beleza

Como você provavelmente sabe, os navegadores modernos podem pintar grupos de elementos DOM em "imagens" separadas, chamadas de camadas. Às vezes, há uma camada para a página inteira, às vezes há centenas ou, em casos raros, milhares.

Quando os elementos do DOM são agrupados em uma camada e um deles muda visualmente, acabamos tendo que pintar não apenas o elemento alterado, mas todos os outros elementos na camada que se sobrepõem ao elemento alterado. Pintar uma coisa sobre a outra faz com que os pixels substituídos sejam "perdidos" para sempre. Se você quiser recuperar os pixels originais, será necessário pintá-los novamente.

Portanto, às vezes, queremos isolar um elemento dos outros para que, quando ele for pintado, não seja necessário pintar os outros elementos que não mudaram. Por exemplo, ao combinar um cabeçalho de página fixo com conteúdo rolável, é necessário repintar o cabeçalho sempre que o conteúdo rola, bem como o conteúdo recém-visível. Ao colocar o cabeçalho em uma camada separada, o navegador pode otimizar a rolagem. Quando você rola, o navegador pode mover as camadas, provavelmente com a ajuda da GPU, e evitar a repintura de qualquer uma delas.

Cada camada adicional aumenta o consumo de memória e adiciona sobrecarga de desempenho. Portanto, o objetivo é agrupar a página em poucas camadas e manter um bom desempenho.

O que isso tem a ver com GIFs animados?

Vamos analisar esta imagem:

Um app da Web dividido em quatro camadas.
Figura 1: um app da Web dividido em quatro camadas.

Essa é uma possível configuração de camadas para um app simples. Há quatro camadas aqui: três delas (camadas 2 a 4) são elementos da interface. A camada de trás é um carregador, que é um GIF animado. No fluxo normal, você mostra o carregador (camada 1) enquanto o app é carregado. Depois, quando tudo é concluído, você mostra as outras camadas. Mas aqui está a chave: você precisa ocultar o GIF animado.

Mas por que preciso esconder isso?

Boa pergunta. Em um mundo perfeito, o navegador simplesmente verificaria a visibilidade do GIF para você e evitaria a pintura automática. Infelizmente, verificar se o GIF animado está obscurecido ou visível na tela normalmente é mais caro do que simplesmente pintá-lo, então ele é pintado.

Na melhor das hipóteses, o GIF está na própria camada, e o navegador só precisa pintar e fazer o upload dele para a GPU. Mas, na pior das hipóteses, todos os elementos podem ser agrupados em uma única camada, e o navegador precisa pintar cada elemento. E, quando terminar, ainda precisa fazer upload de tudo para a GPU. Tudo isso ocorre para cada frame do GIF, mesmo que o usuário não consiga nem mesmo ver o GIF.

Em computadores, esse tipo de comportamento de pintura pode ser aceitável porque as CPUs e GPUs são mais potentes e há bastante largura de banda para transferir dados entre elas. No entanto, em dispositivos móveis, a pintura é extremamente cara, então você precisa ter muito cuidado.

Quais navegadores são afetados?

Como é comum, o comportamento varia de acordo com o navegador. Hoje, o Chrome, o Safari e o Opera são repintados, mesmo que o GIF esteja obscurecido. O Firefox, por outro lado, descobre que o GIF está obscurecido e não precisa ser pintado novamente. O Internet Explorer ainda é uma caixa-preta, e mesmo no IE11, já que as ferramentas F12 ainda estão sendo desenvolvidas, não há indicação de que uma nova pintura está ocorrendo.

Como posso saber se tenho esse problema?

A maneira mais fácil é usar a opção "Mostrar retângulos de pintura" no Chrome DevTools. Carregue as Ferramentas do desenvolvedor e pressione a engrenagem no canto inferior direito (Ícone de roda dentada) e escolha Mostrar retângulos de pintura na seção Renderização.

Ativação da opção "Mostrar retângulos de exibição" no Chrome DevTools
Figura 2: como ativar a opção "Mostrar retângulos de pintura" nas Chrome DevTools.

Agora, procure um retângulo vermelho como este:

A opção "Mostrar retângulos de pintura" das ferramentas do desenvolvedor indica problemas de GIF animado com um retângulo vermelho.
Figura 3: a opção "Show Paint Rectangles" das DevTools indica problemas de GIF animado com um retângulo vermelho.

A pequena caixa vermelha na tela mostra que o Chrome está repintando algo. Você sabe que há um GIF de carregamento oculto atrás dos outros elementos. Portanto, quando você vê uma caixa vermelha como essa, precisa ocultar os elementos visíveis e verificar se deixou o GIF animado girando. Se você tiver, será necessário usar algum CSS ou JavaScript para aplicar display: none ou visibility: hidden a ele ou ao elemento pai. Se for apenas uma imagem de plano de fundo, remova-a.

Para conferir um exemplo desse comportamento em um site ativo, acesse o Allegro, em que a imagem de cada produto tem um GIF de carregamento oculto, em vez de oculto explicitamente.

Conclusão

Alcançar 60 fps significa apenas fazer o necessário para renderizar a página e nada mais. Remover o excesso de tinta é uma etapa fundamental para alcançar esse objetivo. GIFs animados que são executados podem acionar pinturas desnecessárias, algo que você pode encontrar e depurar facilmente com a ferramenta Mostrar retângulos de exibição do DevTools.

Você não deixou o GIF animado do gatinho carregando para sempre, não é?