Publicado em 20 de março de 2015, última atualização: 7 de maio de 2025
O layout é onde o navegador descobre as informações geométricas dos elementos: o tamanho e a localização deles na página. Cada elemento terá informações de dimensionamento explícitas ou implícitas com base no CSS usado, no conteúdo do elemento ou em um elemento pai. O processo é chamado de layout no Chrome (e navegadores derivados, como o Edge) e no Safari. No Firefox, ele é chamado de "reflow", mas o processo é o mesmo.
Assim como nos cálculos de estilo, as preocupações imediatas com o custo do layout são:
- O número de elementos que exigem layout, que é um subproduto do tamanho do DOM da página.
- A complexidade desses layouts.
Resumo
- O layout tem efeito direto na latência de interação
- O layout normalmente é aplicado a todo o documento.
- O número de elementos DOM afeta a performance. Evite acionar o layout sempre que possível.
- Evite layouts síncronos forçados e o uso excessivo de layout. Leia os valores do estilo e faça mudanças.
Os efeitos do layout na latência de interação
Quando um usuário interage com a página, essas interações precisam ser o mais rápidas possível. O tempo necessário para concluir uma interação, que termina quando o navegador apresenta o próximo frame para mostrar os resultados da interação, é conhecido como latência de interação. Esse é um aspecto da performance da página que a métrica Interaction to Next Paint mede.
O tempo que o navegador leva para apresentar o próximo frame em resposta a uma interação do usuário é conhecido como delay de apresentação da interação. O objetivo de uma interação é fornecer feedback visual para sinalizar ao usuário que algo ocorreu, e as atualizações visuais podem envolver algum trabalho de layout para alcançar essa meta.
Para manter o INP do seu site o mais baixo possível, é importante evitar o layout sempre que possível. Se não for possível evitar o layout totalmente, é importante limitar o trabalho de layout para que o navegador possa apresentar o próximo frame rapidamente.
Evite o layout sempre que possível
Quando você muda os estilos, o navegador verifica se alguma das mudanças exige que o layout seja calculado e se a árvore de renderização precisa ser atualizada. As mudanças nas "propriedades geométricas", como width
, height
, left
ou top
, exigem layout.
.box {
width: 20px;
height: 20px;
}
/**
* Changing width and height
* triggers layout.
*/
.box--expanded {
width: 200px;
height: 350px;
}
O layout quase sempre tem o escopo de todo o documento. Se você tiver muitos elementos, vai levar muito tempo para descobrir os locais e as dimensões de todos eles.
Se não for possível evitar o layout, a chave é usar novamente o Chrome DevTools para saber quanto tempo está demorando e determinar se o layout é a causa de um gargalo. Primeiro, abra o DevTools, acesse a guia "Timeline", clique em "Record" e interaja com o site. Quando você parar de gravar, vai aparecer um detalhamento do desempenho do seu site:

Ao analisar o rastro no exemplo anterior, vemos que mais de 28 milissegundos são gastos no layout para cada frame, o que, quando temos 16 milissegundos para exibir um frame na tela em uma animação, é muito alto. Você também pode ver que as Ferramentas do desenvolvedor informam o tamanho da árvore (1.618 elementos neste caso) e quantos nós precisavam de layout (5 neste caso).
O conselho geral aqui é evitar o layout sempre que possível, mas nem sempre é possível evitar o layout. Nos casos em que não é possível evitar o layout, saiba que o custo dele tem uma relação com o tamanho do DOM. Embora a relação entre os dois não seja muito estreita, DOMs maiores geralmente incorrem em custos de layout mais altos.
Evitar layouts síncronos forçados
O envio de um frame para a tela tem esta ordem:

Primeiro, o JavaScript é executado, depois os cálculos de estilo e, depois o layout. No entanto, é possível forçar um navegador a executar o layout mais cedo com JavaScript. Isso é chamado de layout síncrono forçado (ou às vezes refluxo forçado).
A primeira coisa a se lembrar é que, à medida que o JavaScript é executado, todos os valores de layout antigos do frame anterior são conhecidos e disponíveis para consulta. Por exemplo, se você quiser escrever a altura de um elemento (vamos chamar de "caixa") no início do frame, escreva um código como este:
// Schedule our function to run at the start of the frame:
requestAnimationFrame(logBoxHeight);
function logBoxHeight () {
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
}
As coisas ficam problemáticas se você tiver mudado os estilos da caixa antes de solicitar a altura dela:
function logBoxHeight () {
box.classList.add('super-big');
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
}
Agora, para responder à pergunta sobre a altura, o navegador precisa primeiro aplicar a mudança de estilo (por causa da adição da classe super-big
) e depois executar o layout. Só então ele poderá retornar a altura correta. Isso é desnecessário e pode ser caro.
Por isso, sempre faça a leitura em lote dos estilos e faça isso primeiro (quando o navegador pode usar os valores de layout do frame anterior) e depois faça as gravações:
Uma versão mais eficiente da função anterior seria:
function logBoxHeight () {
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
box.classList.add('super-big');
}
Na maioria das vezes, não é necessário aplicar estilos e consultar valores. Usar os valores do último frame é suficiente. Executar os cálculos de estilo e layout de forma síncrona e antes do que o navegador gostaria são possíveis gargalos, e não algo que você normalmente quer fazer.
Evite a sobrecarga de layout
Há uma maneira de tornar os layouts síncronos forçados ainda piores: fazer muitos deles em sucessão rápida. Confira este código:
function resizeAllParagraphsToMatchBlockWidth () {
// Puts the browser into a read-write-read-write cycle.
for (let i = 0; i < paragraphs.length; i++) {
paragraphs[i].style.width = `${box.offsetWidth}px`;
}
}
Esse código repete um grupo de parágrafos e define a largura de cada parágrafo para corresponder à largura de um elemento chamado "caixa". Parece inofensivo, mas o problema é que cada iteração do loop lê um valor de estilo (box.offsetWidth
) e o usa imediatamente para atualizar a largura de um parágrafo (paragraphs[i].style.width
). Na próxima iteração do loop, o navegador precisa considerar o fato de que os estilos mudaram desde a última solicitação de offsetWidth
(na iteração anterior), portanto, ele precisa aplicar as mudanças de estilo e executar o layout. Isso vai acontecer em cada iteração.
A correção para este exemplo é ler e gravar os valores novamente:
// Read.
const width = box.offsetWidth;
function resizeAllParagraphsToMatchBlockWidth () {
for (let i = 0; i < paragraphs.length; i++) {
// Now write.
paragraphs[i].style.width = `${width}px`;
}
}
Identificar layouts síncronos forçados e thrashing
As DevTools têm um insight de reflow forçado para ajudar a identificar rapidamente casos de layouts síncronos forçados (também conhecidos como "reflow forçado"):

Os layouts síncronos forçados também podem ser identificados no campo usando a atribuição de script da API Long Animation Frame com a propriedade forcedStyleAndLayoutDuration
.