Tableless

Busca Menu

Entendendo os Reflows

Seja o primeiro a comentar por

Reflow é um assunto extenso e necessário. Ele sempre vai existir nos navegadores, então temos que entendê-lo para saber como utilizá-lo de maneira racional. O mais legal é entender todo o contexto sobre o que são e como funcionam, para a partir daí repensar o código que renderizamos no navegador para obtermos maior performance.

Reflow é o resultado de um evento que desencadeia mudanças no jeito que a pagina deve ser renderizada, tomando tempo para cálculo e reposicionamento de elementos.

Para explicar como isso acontece, o importante é entender como um navegador renderiza uma página web.

DOM

Document Object Model (DOM) é uma interface independente de linguagem e plataforma para representar e interagir com objetos em HTML, XHTML e XML. Mas o DOM é mais que isso; toda linguagem estruturada tem uma arvore DOM.

Exemplo de arvore DOM para documento HTML

Exemplo de arvore DOM para documento HTML

Mas sobre o DOM podemos dizer que programas ou scripts podem dinamicamente acessar elementos na árvore DOM e alterar seu conteúdo, estrutura e estilo. Adicional ao estado inicial da pagina, estas alterações são agregadas a árvore DOM. O resultado é a renderização – o que nós vemos em um navegador. Mas a nossa Render Tree tem mais que isso:

Render Tree e como realmente entender display X visibility

Como a render tree e montada

Como a render tree é montada

O DOM é resultado do parse do markup HTML que você montou dentro de um navegador. Só que dentro de um HTML você não tem apenas a estrutura do documento, estilos em CSS e funcionalidades em javascript também estarão no seu markup. E a Render tree é a soma de DOM mais estilos, que depois podem ser manipulados (seus scripts).

Pode parecer estranho, mas para mim a melhor maneira de entender as diferencas entre DOM e Render Tree é encarar esta última como um individuo narcisista. Isso mesmo: A Render Tree gosta de aparecer, é o que vemos no browser. O DOM acontece por trás das cortinas. À Render tree, o palco. (Para saber mais sobre o DOM, veja este outro artigo)

Uma página que tem controles de show/hide mostra isso muito bem. Enquanto todo o conteúdo da página está presente na árvore DOM, apenas alguns itens estarão disponíveis na Render Tree – os visíveis na página (display:block). Alterar os elementos display:none vão disparar mudanças na render tree, e não na árvore DOM.

Já tentou entender as diferenças entre display:none e visibility:hidden? A maioria das explicações que vemos é que um “deixa de mostrar o elemento totalmente, incluindo seu espaço em tela” e o outro “deixa de mostrar o elemento visual, mas sua área de exibição continua sendo utilizada”. Esta explicação não está incorreta, mas seria melhor dizer que a propriedade display altera a estrutura da render tree, adicionando algo que antes não estava ali, enquanto visibility não faz alterações, apenas o câmbio de mostrar ou não um elemento que já esta na render tree.

Repaint

Entendido as diferenças entre display e visibility, além do contexto de área do elemento, conseguimos explicar o Repaint. Uma ação que faça alteração de propriedades de background sem alterar dimensões ou outras propriedades do elemento não causam o reflow, apenas o repaint, que seria a atualização da propriedade de cor ou da imagem – literalmente pintar novamente o elemento. Repaints gastam menos CPU que reflows.

Como um navegador monta seu documento HTML

Esses vídeos são sensacionais. Eles explicam o que são os reflows e dai como minimizá-los durante a fase de desenvolvimento do documento (sempre usando Progressive Enhancement quando possível) é mais fácil..

[youtube http://www.youtube.com/watch?v=ZTnIxIA5KGw]

Esta é uma representação de como a página da Mozilla é montada. Quer mais? Veja também como a Wikipedia e a página do Google no Japão são renderizadas.

Analisando o primeiro vídeo, perceba que ao finalizar a montagem do rodapé, “algo mais” acontece (a partir de 12seg). São os Reflows. A maioria dos elementos são recalculados e reposicionados. Se ponderarmos que o rodapé acaba de ser montado aos 14 segundos e a renderização termina aos 26 segundos da pagina, estamos falando quase de 50% do tempo de renderização sendo gasto com Reflows, o que é muito, dependendo do que a sua página deve fazer.

O que causam exatamente os reflows?

var bstyle = document.body.style; // cache
bstyle.padding = "20px"; // reflow, repaint
bstyle.border = "10px solid red"; // outro reflow e repaint
bstyle.color = "blue"; // repaint
bstyle.backgroundColor = "#fad"; // repaint
bstyle.fontSize = "2em"; // reflow, repaint
// novo elemento DOM - reflow, repaint
document.body.appendChild(document.createTextNode('Leeento'));

Reflows são excessivamente pesados e para reduzir efeitos uma das táticas que navegadores usam é processar nossos scripts em lote. Uma fila é criada para todos os comandos que causam reflow sejam processados de uma única vez. Porém o foco é entender o que causa um reflow e tentar minimizar o seu uso para ganhar performance na aplicação.

Este assunto é novo, e com certeza, A lista que mostro abaixo deve crescer. É importante mantermos a atenção a este assunto porque pequenos cuidados podem significar muito. Em um site web visualizado em desktops a diferença é óbvia sobre o tempo de renderização. Mas isso implica em outras coisas, que podem fazer a diferença não apenas em montar uma página mais rápido, mas também para menor gasto de processamento, o que garante também mais tempo de bateria em mobiles e tablets por exemplo.

  1. Adicionar, remover ou atualizar o DOM;
  2. Esconder nós do DOM usando display:none;
  3. Mover e animar o DOM na página;
  4. Adicionar folhas de estilo on-the-fly que mudem o comportamento dos elementos;
  5. Redimensionar janelas;
  6. Alterar tamanho de fontes;
  7. Scroll de página;

Em um dos posts sobre o assunto, Tony G mapeou pesquisas prévias e montou a seguinte tabela, que também está sendo constantemente atualizada.

Element

Frame, Image

Range

SVGLocatable

SVGTextContent

SVGUse

window

clientHeight,
clientLeft,
clientTop,
clientWidth,
focus(), getBoundingClientRect(), getClientRects(), innerText,
offsetHeight,
offsetLeft,
offsetParent,
offsetTop,
offsetWidth,
outerText,
scrollByLines(), scrollByPages(), scrollHeight, scrollIntoView(), scrollIntoViewIfNeeded(), scrollLeft,
scrollTop,
scrollWidth
height, width getBoundingClientRect(), getClientRects() computeCTM(), getBBox()

getCharNumAtPosition(), getComputedTextLength(), getEndPositionOfChar(), getExtentOfChar(), getNumberOfChars(), getRotationOfChar(), getStartPositionOfChar(), getSubStringLength(), selectSubString() instanceRoot getComputedStyle(),
scrollBy(),
scrollTo(),
scrollX,
scrollY, webkitConvertPointFromNodeToPage(), webkitConvertPointFromPageToNode()

Como melhorar o meu código para minimizar os reflows?

É simples. Basta minimizar o uso de requisições de estilo, que façam o navegador executar reflows ou repaints.

  1. Planejar a sua aplicação e entender como plugins e scripts criados vão se comportar em relação a reflow e repaints. Arquitetar o uso de plugins de acordo com a personalização que deve ser feita. Minimize o uso de alteração de estilos on-the-fly.
  2. Quando precisar alterar a propriedade de um estilo, troque o nome da classe, planeje a existência deste estado e adicione-o ao CSS previamente. Se o valor desta nova classe for dinâmica, use cssText. Evite alterar a propriedade diretamente para qualquer mudança.
  3. Pense como suas mudanças afetam a render tree e o quanto precisará ser revalidado depois desta mudanca. Se você usa position:absolute em um elemento, ele deixa de pertencer ao nó que está, e passa a ser filho do BODY. Alterá-lo então, não será tão custoso em termos de performance. Mesmo que alterações neste nó sobreponha outras areas, o reflow acontecerá apenas neste nó, e não em toda a render tree.
  4. Limpe seu CSS. Classes não utilizadas devem ser removidas.
  5. Reduza o número de mudanças no DOM. Ele vai causar mudanças estruturais em todas as outras etapas. E mais tempo de reflow.
  6. Animações na página, transições? Pondere sobre posicioná-la de maneira absoluta e trabalhar com ela a partir do BODY.
  7. Vá com calma nos seletores CSS – os descendentes em particular – pois usam maior poder de CPU para executar a tarefa (CPU = Bateria).

Referências

Publicado no dia