Depurar mudanças de layout

Saiba como identificar e corrigir mudanças de layout.

Katie Hempenius
Katie Hempenius

A primeira parte deste artigo discute ferramentas para depurar mudanças de layout, enquanto a segunda parte discute o processo de pensamento a ser usado ao identificar a causa de uma mudança de layout.

Ferramentas

API Layout Instability

A API Layout Instability é o mecanismo do navegador para medir e informar mudanças de layout. Todas as ferramentas para depurar mudanças de layout, incluindo as DevTools, são criadas com base na API Layout Instability. No entanto, usar a API Layout Instability diretamente é uma ferramenta de depuração poderosa devido à flexibilidade dela.

Uso

O mesmo snippet de código que mede o Cumulative Layout Shift (CLS) também pode ser usado para depurar mudanças de layout. O snippet abaixo registra informações sobre mudanças de layout no console. A inspeção desse registro vai fornecer informações sobre quando, onde e como uma mudança de layout ocorreu.

let cls = 0;
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

Ao executar esse script, tenha em mente que:

  • A opção buffered: true indica que o PerformanceObserver precisa verificar o buffer de entrada de performance do navegador para entradas de performance que foram criadas antes da inicialização do observador. Como resultado, o PerformanceObserver vai informar mudanças de layout que aconteceram antes e depois da inicialização. Tenha isso em mente ao inspecionar os registros do console. Um excesso inicial de mudanças de layout pode refletir um atraso de relatórios, em vez da ocorrência repentina de várias mudanças de layout.
  • Para evitar impacto na performance, o PerformanceObserver espera até que a linha de execução principal fique ociosa para informar sobre as mudanças de layout. Como resultado, dependendo de como a linha de execução principal está ocupada, pode haver um pequeno atraso entre o momento em que uma mudança de layout ocorre e quando ela é registrada no console.
  • Esse script ignora as mudanças de layout que ocorreram em até 500 ms da entrada do usuário e, portanto, não são contabilizadas na CLS.

As informações sobre mudanças de layout são informadas usando uma combinação de duas APIs: as interfaces LayoutShift e LayoutShiftAttribution. Cada uma dessas interfaces é explicada em mais detalhes nas seções a seguir.

LayoutShift

Cada mudança de layout é informada usando a interface LayoutShift. O conteúdo de uma entrada tem esta aparência:

duration: 0
entryType: "layout-shift"
hadRecentInput: false
lastInputTime: 0
name: ""
sources: (3) [LayoutShiftAttribution, LayoutShiftAttribution, LayoutShiftAttribution]
startTime: 11317.934999999125
value: 0.17508567530168798

A entrada acima indica uma mudança de layout em que três elementos do DOM mudaram de posição. A pontuação da troca de layout foi 0.175.

Estas são as propriedades de uma instância LayoutShift mais relevantes para depurar mudanças de layout:

Propriedade Descrição
sources A propriedade sources lista os elementos DOM que foram movidos durante a mudança de layout. Essa matriz pode conter até cinco fontes. Se houver mais de cinco elementos afetados pela mudança de layout, as cinco maiores fontes de mudança de layout (medidas pelo impacto na estabilidade do layout) serão relatadas. Essas informações são informadas usando a interface LayoutShiftAttribution (explicada em mais detalhes abaixo).
value A propriedade value informa a pontuação da troca de layout para uma troca de layout específica.
hadRecentInput A propriedade hadRecentInput indica se uma mudança de layout ocorreu em até 500 milissegundos após a entrada do usuário.
startTime A propriedade startTime indica quando uma mudança de layout ocorreu. startTime é indicado em milissegundos e é medido em relação ao momento em que o carregamento da página foi iniciado.
duration A propriedade duration sempre será definida como 0. Essa propriedade é herdada da interface PerformanceEntry. A interface LayoutShift estende a interface PerformanceEntry. No entanto, o conceito de duração não se aplica a eventos de mudança de layout. Por isso, ele é definido como 0. Para mais informações sobre a interface PerformanceEntry, consulte a especificação.

LayoutShiftAttribution

A interface LayoutShiftAttribution descreve um único deslocamento de um único elemento DOM. Se vários elementos forem movidos durante uma mudança de layout, a propriedade sources vai conter várias entradas.

Por exemplo, o JSON abaixo corresponde a uma mudança de layout com uma origem: a mudança para baixo do elemento DOM <div id='banner'> de y: 76 para y:246.

// ...
  "sources": [
    {
      "node": "div#banner",
      "previousRect": {
        "x": 311,
        "y": 76,
        "width": 4,
        "height": 18,
        "top": 76,
        "right": 315,
        "bottom": 94,
        "left": 311
      },
      "currentRect": {
        "x": 311,
        "y": 246,
        "width": 4,
        "height": 18,
        "top": 246,
        "right": 315,
        "bottom": 264,
        "left": 311
      }
    }
  ]

A propriedade node identifica o elemento HTML que foi deslocado. Passar o cursor sobre essa propriedade no DevTools destaca o elemento de página correspondente.

As propriedades previousRect e currentRect informam o tamanho e a posição do nó.

  • As coordenadas x e y informam a coordenada x e a coordenada y respectivamente do canto superior esquerdo do elemento.
  • As propriedades width e height informam a largura e a altura, respectivamente, do elemento.
  • As propriedades top, right, bottom e left informam os valores de coordenadas x ou y correspondentes à borda especificada do elemento. Em outras palavras, o valor de top é igual a y. O valor de bottom é igual a y+height.

Se todas as propriedades de previousRect forem definidas como 0, isso significa que o elemento foi movimentado para a visualização. Se todas as propriedades de currentRect forem definidas como 0, isso significa que o elemento foi movido para fora da visualização.

Uma das coisas mais importantes a entender ao interpretar essas saídas é que os elementos listados como fontes são os elementos que mudaram durante a mudança de layout. No entanto, é possível que esses elementos estejam apenas indiretamente relacionados à "causa raiz" da instabilidade do layout. Confira alguns exemplos.

Exemplo 1

Essa mudança de layout seria informada com uma origem: elemento B. No entanto, a causa raiz dessa mudança de layout é a alteração no tamanho do elemento A.

Exemplo mostrando uma mudança de layout causada por uma mudança nas dimensões do elemento

Exemplo 2

A mudança de layout neste exemplo seria informada com duas origens: elemento A e elemento B. A causa raiz dessa mudança de layout é a alteração na posição do elemento A.

Exemplo que mostra uma mudança de layout causada por uma mudança na posição do elemento

Exemplo 3

A mudança de layout neste exemplo seria informada com uma origem: elemento B. A mudança da posição do elemento B resultou nessa mudança de layout.

Exemplo que mostra uma mudança de layout causada por uma mudança na posição do elemento

Exemplo 4

Embora o elemento B mude de tamanho, não há mudança de layout neste exemplo.

Exemplo que mostra um elemento mudando de tamanho, mas não causando uma mudança de layout

Confira uma demonstração de como as mudanças do DOM são informadas pela API Layout Instability.

DevTools

Painel de desempenho

O painel Experiência das Ferramentas do desenvolvedor Performance mostra todas as mudanças de layout que ocorrem durante um determinado rastro de performance, mesmo que ocorram em até 500 ms de uma interação do usuário e, portanto, não sejam contabilizadas para a CLS. Passar o cursor sobre uma mudança de layout específica no painel Experiência destaca o elemento DOM afetado.

Captura de tela de uma mudança de layout exibida no painel de rede do DevTools

Para conferir mais informações sobre a mudança de layout, clique nela e abra a gaveta Resumo. As mudanças nas dimensões do elemento são listadas usando o formato [width, height]. As mudanças na posição do elemento são listadas usando o formato [x,y]. A propriedade Had recent input indica se uma mudança de layout ocorreu em até 500 ms de uma interação do usuário.

Captura de tela da guia &quot;Resumo&quot; das ferramentas do desenvolvedor para uma mudança de layout

Para saber a duração de uma mudança de layout, abra a guia Registro de eventos. A duração de uma mudança de layout também pode ser aproximada procurando no painel Experiência o comprimento do retângulo vermelho de mudança de layout.

Captura de tela da guia &quot;Registro de eventos&quot; do DevTools para uma mudança de layout

Para mais informações sobre como usar o painel Performance, consulte a Referência de análise de performance.

Destacar regiões de mudança de layout

Destacar regiões de troca de layout pode ser uma técnica útil para ter uma visão rápida do local e do momento das trocas de layout que ocorrem em uma página.

Para ativar as regiões de Layout Shift nas Ferramentas do desenvolvedor, acesse Configurações > Mais ferramentas > Renderização > Regiões de Layout Shift e atualize a página que você quer depurar. As áreas de mudança de layout são destacadas brevemente em roxo.

Processo de pensamento para identificar a causa das mudanças de layout

Use as etapas abaixo para identificar a causa das mudanças de layout, independente de quando ou como elas ocorrem. Essas etapas podem ser complementadas com a execução do Lighthouse. No entanto, lembre-se de que o Lighthouse só pode identificar mudanças de layout que ocorreram durante o carregamento inicial da página. Além disso, o Lighthouse só pode fornecer sugestões para algumas causas de mudanças de layout, por exemplo, elementos de imagem que não têm largura e altura explícitas.

Como identificar a causa de uma mudança de layout

Os deslocamentos de layout podem ser causados pelos seguintes eventos:

  • Mudanças na posição de um elemento DOM
  • Mudanças nas dimensões de um elemento DOM
  • Inserção ou remoção de um elemento DOM
  • Animações que acionam o layout

Em particular, o elemento DOM imediatamente anterior ao elemento deslocado é o elemento mais provável de estar envolvido na "causa" da mudança de layout. Portanto, ao investigar por que uma mudança de layout ocorreu, considere:

  • A posição ou as dimensões do elemento anterior mudaram?
  • Um elemento DOM foi inserido ou removido antes do elemento deslocado?
  • A posição do elemento deslocado foi alterada explicitamente?

Se o elemento anterior não causou a mudança de layout, continue a pesquisa considerando outros elementos anteriores e próximos.

Além disso, a direção e a distância de uma mudança de layout podem fornecer dicas sobre a causa raiz. Por exemplo, um grande deslocamento para baixo geralmente indica a inserção de um elemento DOM, enquanto um deslocamento de layout de 1 px ou 2 px geralmente indica a aplicação de estilos CSS conflitantes ou o carregamento e a aplicação de uma fonte da Web.

Diagrama mostrando uma mudança de layout causada por uma troca de fonte
Nesse exemplo, a troca de fontes fez com que os elementos da página fossem movidos para cima em cinco pixels.

Estes são alguns dos comportamentos específicos que causam eventos de mudança de layout com mais frequência:

Mudanças na posição de um elemento (que não são devido ao movimento de outro elemento)

Esse tipo de mudança geralmente é resultado de:

  • Folhas de estilo que são carregadas com atraso ou que substituem estilos declarados anteriormente.
  • Efeitos de animação e transição.

Mudanças nas dimensões de um elemento

Esse tipo de mudança geralmente é resultado de:

  • Folhas de estilo que são carregadas com atraso ou que substituem estilos declarados anteriormente.
  • Imagens e iframes sem atributos width e height que são carregados depois que o "slot" foi renderizado.
  • Blocos de texto sem atributos width ou height que trocam de fonte depois que o texto é renderizado.

A inserção ou remoção de elementos DOM

Isso geralmente é resultado de:

  • Inserção de anúncios e outras incorporações de terceiros.
  • Inserção de banners, alertas e modais.
  • Rolagem infinita e outros padrões de UX que carregam conteúdo adicional acima do conteúdo atual.

Animações que acionam o layout

Alguns efeitos de animação podem aciona o layout. Um exemplo comum é quando os elementos DOM são "animados" incrementando propriedades como top ou left em vez de usar a propriedade transform do CSS. Leia Como criar animações CSS de alto desempenho para mais informações.

Como reproduzir mudanças de layout

Não é possível corrigir mudanças de layout que não podem ser reproduzidas. Uma das coisas mais simples e eficazes que você pode fazer para ter uma ideia melhor da estabilidade do layout do seu site é interagir com ele por 5 a 10 minutos com o objetivo de acionar mudanças de layout. Mantenha o console aberto enquanto faz isso e use a API Layout Instability para informar sobre mudanças de layout.

Para localizar mudanças de layout difíceis, repita este exercício com diferentes dispositivos e velocidades de conexão. Em particular, usar uma velocidade de conexão mais lenta pode facilitar a identificação de mudanças de layout. Além disso, é possível usar uma instrução debugger para facilitar a navegação pelos deslocamentos de layout.

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      debugger;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

Por fim, para problemas de layout que não são reproduzíveis no desenvolvimento, considere usar a API Layout Instability com a ferramenta de registro de front-end de sua preferência para coletar mais informações sobre esses problemas. Confira o exemplo de código para saber como rastrear o maior elemento deslocado em uma página.