Entendendo os Reflows
O que são e como os Reflows podem ser otimizados para aplicações ficarem ainda mais rápidas.
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.
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
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..
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'));
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.
- Adicionar, remover ou atualizar o DOM;
- Esconder nós do DOM usando display:none;
- Mover e animar o DOM na página;
- Adicionar folhas de estilo on-the-fly que mudem o comportamento dos elementos;
- Redimensionar janelas;
- Alterar tamanho de fontes;
- 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.
- 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.
- 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.
- 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.
- Limpe seu CSS. Classes não utilizadas devem ser removidas.
- 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.
- Animações na página, transições? Pondere sobre posicioná-la de maneira absoluta e trabalhar com ela a partir do BODY.
- Vá com calma nos seletores CSS – os descendentes em particular – pois usam maior poder de CPU para executar a tarefa (CPU = Bateria).
Referências
- DOM pela wikipedia
- Gecko Reflow
- DOM, HTML5, CSS3 e Performance – Slides por Paul Irish
- Reflow pelo Mozilla Labs
- Reflow e Repaint na Ajaxian
- Reflow pelo Google Code
- W3C Overview do DOM
- 1 dia de javascript com Alex Russel: Como Navegadores Veem as suas Apps
- Como (não) criar um layout no webkit por Tony G
- Usando a timeline panel em navegadores webkit
- The book of Speed
- Reflow/Repaint por Stoyan Stefanov
- Inconsistências dos navegadores em Reflows por Stoyan Stefanov
- BrowserScope tests para reflows
- Browsers para Web Developers David Baron da Mozilla labs
- Renderização no webkit, o básico


Pingback: Entenda o que é o Document Object Model e tenha o DOM. | Tableless - Desenvolvimento com Padrões Web
Pingback: Entendendo o DOM (Document Object Model) - m² | blog
Pingback: Problemas com Reflow e Repaint em javascript | Wiliam Kudaka