Evite layouts grandes e complexos e a troca frequente de layouts

O layout é onde o navegador descobre informações geométricas dos elementos, como tamanho e localização na página. Cada elemento terá informações de dimensionamento explícitas ou implícitas de acordo com o CSS usado, o conteúdo do elemento ou um elemento principal. O processo é chamado de Layout no Chrome.

O layout é onde o navegador descobre informações geométricas dos elementos: seu tamanho e localização na página. Cada elemento terá informações de dimensionamento explícitas ou implícitas de acordo com o CSS usado, o conteúdo do elemento ou um elemento principal. O processo é chamado de "Layout no Chrome" (e navegadores derivados, como o Edge) e o Safari. No Firefox, é chamado de Reflow, mas o processo é o mesmo.

Da mesma forma que os cálculos de estilo, as preocupações imediatas para o custo do layout são:

  1. O número de elementos que exigem layout, que é um subproduto do tamanho do DOM da página.
  2. A complexidade desses layouts.

Resumo

  • O layout tem efeito direto na latência de interação
  • Normalmente o escopo do layout é o documento todo.
  • O número de elementos DOM afeta o desempenho. Evite acionar o layout sempre que possível.
  • Evite layouts síncronos forçados e a troca frequente de layouts: leia os valores de estilo e depois faça as mudanças.

Os efeitos do layout na latência de interação

Quando um usuário interage com a página, essas interações devem ser as mais rápidas possível. O tempo que uma interação leva para ser concluída, ou seja, 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 do desempenho da página que a métrica Interação com a próxima pintura avalia.

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 de estilos, o navegador verifica se alguma mudança exige que o layout seja calculado e que a árvore de renderização seja atualizada. As mudanças nas "propriedades geométricas", como larguras, alturas, esquerda ou topo, exigem layout.

.box {
 
width: 20px;
 
height: 20px;
}

/**
  * Changing width and height
  * triggers layout.
  */


.box--expanded {
 
width: 200px;
 
height: 350px;
}

O layout quase sempre tem escopo para todo o documento. Se você tiver muitos elementos, levará muito tempo para descobrir as localizações e as dimensões de todos.

Se não for possível evitar o layout, o segredo é usar o Chrome DevTools mais uma vez para ver 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ê interromper a gravação, vai aparecer um detalhamento do desempenho do site:

DevTools mostrando muito tempo no Layout.

Ao analisar o rastro no exemplo acima, vemos que mais de 28 milissegundos são gastos no layout de cada frame. Quando temos 16 milissegundos para exibir um frame em uma animação, 28 milissegundos é tempo demais. O DevTools também informa o tamanho da árvore (neste caso,1.618 elementos) 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 do layout 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 é feito nesta ordem:

Usando o flexbox como layout.

Primeiro, o JavaScript é executado, depois os cálculos de estilo e depois o layout. No entanto, é possível forçar o navegador a executar antecipadamente o layout com o JavaScript. Isso é chamado de layout síncrono forçado.

A primeira coisa a se lembrar é que, à medida que o JavaScript é executado, todos os valores de layout antigos do quadro anterior são conhecidos e estão disponíveis para consulta. Portanto, se por exemplo você quiser exibir a altura de um elemento (vamos chamá-lo de "caixa") no início do quadro, poderá criar um código semelhante a 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 mais complicadas se você alterou os estilos da caixa antes de consultar 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 poder responder à consulta de altura, o navegador deve primeiro aplicar a mudança de estilo (por causa da adição da classe super-big) e em seguida executar o layout. Somente então será possível retornar a altura correta. Esse trabalho é desnecessário e possivelmente caro.

Por isso, você deve sempre agrupar suas leituras de estilo e fazê-las primeiro (onde o navegador pode usar os valores de layout do frame anterior) e depois fazer as gravações:

Realizada corretamente, a função acima 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 será necessário aplicar estilos e consultar valores. O uso dos valores do último quadro deverá ser suficiente. A execução dos cálculos de estilo e layout de forma síncrona e antes do momento escolhido pelo navegador é um possível gargalo e, normalmente, deve ser evitada.

Evitar a troca frequente de layouts

Há uma forma de piorar ainda mais os layouts síncronos forçados: executar vários deles em rápida sucessão. 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`;
 
}
}

Este código faz um loop sobre um grupo de parágrafos e define cada largura de parágrafo para corresponder com a 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 que os estilos mudaram desde que o offsetWidth foi solicitado pela última vez (na iteração anterior) e, portanto, precisa aplicar as mudanças de estilo e executar o layout. Isso vai acontecer em cada iteração.

A correção para este exemplo é novamente read e depois write os valores:

// Read.
const width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth () {
 
for (let i = 0; i < paragraphs.length; i++) {
   
// Now write.
    paragraphs
[i].style.width = `${width}px`;
 
}
}

Se você quer garantir a segurança, use o FastDOM, que agrupa automaticamente suas leituras e gravações em lotes e evita que você acione acidentalmente layouts síncronos forçados ou troca frequente de layouts.