Cumulative Layout Shift (CLS)

Compatibilidade com navegadores

  • Chrome: 77.
  • Edge: 79.
  • Firefox: não é compatível.
  • Safari: não é compatível.

Origem

Mudanças inesperadas no layout podem atrapalhar a experiência do usuário de várias maneiras, como fazer com que ele perca o lugar enquanto lê se o texto se mover repentinamente ou fazer com que ele clique no link ou botão errado. Em alguns casos, isso pode causar danos graves.

Uma mudança repentina no layout faz com que o usuário confirme um pedido grande que ele pretendia cancelar.

O movimento inesperado do conteúdo da página geralmente acontece quando os recursos são carregados de forma assíncrona ou quando os elementos DOM são adicionados dinamicamente à página antes do conteúdo atual. A causa das mudanças de layout pode ser imagens ou vídeos com dimensões desconhecidas, fontes renderizadas maiores ou menores do que o fallback inicial ou anúncios ou widgets de terceiros que se redimensionam dinamicamente.

As diferenças entre a funcionalidade de um site em desenvolvimento e a experiência dos usuários pioram esse problema. Exemplo:

  • O conteúdo personalizado ou de terceiros geralmente se comporta de maneira diferente no desenvolvimento e na produção.
  • As imagens de teste geralmente já estão no cache do navegador do desenvolvedor, mas demoram mais para carregar para o usuário final.
  • As chamadas de API executadas localmente geralmente são tão rápidas que atrasos imperceptíveis no desenvolvimento podem se tornar substanciais na produção.

A métrica de Shift de layout cumulativo (CLS) ajuda a resolver esse problema medindo a frequência com que ele ocorre para usuários reais.

O que é CLS?

A CLS é uma medida do maior número de pontuações de mudança de layout para cada mudança de layout não esperada que ocorre durante todo o ciclo de vida de uma página.

Uma mudança de layout ocorre sempre que um elemento visível muda de posição de um frame renderizado para o próximo. Mais adiante neste guia, você vai encontrar detalhes sobre como as pontuações de troca de layout individuais são calculadas.

Um pico de mudanças de layout, conhecido como janela de sessão, ocorre quando um ou mais deslocamentos de layout individuais ocorrem em sucessão rápida, com menos de um segundo entre cada deslocamento e um máximo de cinco segundos para a duração total da janela.

O burst maior é a janela de sessão com a pontuação cumulativa máxima de todas as mudanças de layout nessa janela.

Exemplo de janelas de sessão. As barras azuis representam as pontuações de cada mudança de layout.

Qual é uma boa pontuação de CLS?

Para oferecer uma boa experiência ao usuário, os sites devem ter uma pontuação de CLS de 0,1 ou menos. Para garantir que essa meta seja atingida para a maioria dos usuários, um bom limite é o 75º percentil de carregamentos de página, segmentado em dispositivos móveis e computadores.

Valores de CLS bons são 0,1 ou menos, valores ruins são maiores que 0,25, e qualquer valor entre esses dois extremos precisa ser melhorado
Valores de CLS bons são 0,1 ou menos. Os valores ruins são maiores que 0,25.

Para saber mais sobre a pesquisa e a metodologia por trás dessa recomendação, consulte Como definir os limites das métricas das Core Web Vitals.

Trocas de layout em detalhes

As mudanças de layout são definidas pela API Layout Instability, que informa entradas layout-shift sempre que um elemento visível na viewport muda de posição inicial (por exemplo, a posição superior e esquerda no modo de gravação padrão) entre dois frames. Esses elementos são considerados elementos instáveis.

As mudanças de layout só ocorrem quando os elementos mudam a posição inicial. Se um novo elemento for adicionado ao DOM ou um elemento existente mudar de tamanho, ele não vai contar como uma mudança de layout, desde que a mudança não faça outros elementos visíveis mudarem a posição inicial.

Pontuação da troca de layout

Para calcular a pontuação de mudança de layout, o navegador analisa o tamanho da janela de visualização e o movimento de elementos instáveis na janela de visualização entre dois frames renderizados. O Layout Shift Score é um produto de duas medidas desse movimento: a fração de impacto e a fração de distância (ambas definidas abaixo).

layout shift score = impact fraction * distance fraction

Fração de impacto

A fração de impacto mede como os elementos instáveis afetam a área da janela de visualização entre dois frames.

A fração de impacto de um determinado frame é uma combinação das áreas visíveis de todos os elementos instáveis para esse frame e o frame anterior, como uma fração da área total da viewport.

Exemplo de fração de impacto com um elemento instável
Se um elemento mudar de posição, a posição anterior e a atual vão contribuir para a fração de impacto dele.

Na imagem anterior, há um elemento que ocupa metade da janela de visualização em um frame. Em seguida, no próximo frame, o elemento se move para baixo em 25% da altura da viewport. O retângulo vermelho pontilhado indica a união da área visível do elemento em ambos os frames, que, neste caso, é de 75% da viewport total. Portanto, a fração de impacto é 0.75.

Fração de distância

A outra parte da equação da pontuação de mudança de layout mede a distância que os elementos instáveis se moveram em relação à janela de visualização. A fração de distância é a maior distância horizontal ou vertical que qualquer elemento instável se moveu no frame dividido pela maior dimensão da janela de visualização (largura ou altura, o que for maior).

Exemplo de fração de distância com um elemento instável
A fração de distância mede a distância percorrida por um elemento na janela de visualização.

No exemplo anterior, a maior dimensão da janela de visualização é a altura, e o elemento instável se moveu 25% da altura da janela de visualização, o que torna a fração de distância 0,25.

Neste exemplo, a fração de impacto é 0.75, e a fração de distância é 0.25. Portanto, a pontuação de mudança de layout é 0.75 * 0.25 = 0.1875.

Exemplos

O próximo exemplo ilustra como adicionar conteúdo a um elemento afeta a pontuação de mudança de layout:

Exemplo de mudança de layout com vários elementos estáveis e _instáveis_
A adição de um botão na parte de baixo da caixa cinza empurra a caixa verde para baixo e parcialmente para fora da janela.

Nesse exemplo, a caixa cinza muda de tamanho, mas a posição de início não muda, então não é um elemento instável.

O botão "Click Me!" não estava no DOM anteriormente, então a posição inicial dele também não mudou.

A posição inicial da caixa verde muda, mas, como ela foi movida parcialmente para fora da viewport, a área invisível não é considerada no cálculo da fração de impacto. A união das áreas visíveis da caixa verde nos dois frames (ilustrada pelo retângulo vermelho pontilhado) é igual à área da caixa verde no primeiro frame: 50% da viewport. A fração de impacto é 0.5.

A fração de distância é ilustrada com a seta roxa. A caixa verde foi movida para baixo em cerca de 14% da viewport, então a fração de distância é 0.14.

A pontuação da troca de layout é 0.5 x 0.14 = 0.07.

O exemplo a seguir mostra como vários elementos instáveis afetam a pontuação da mudança de layout de uma página:

Exemplo de mudança de layout com elementos estáveis e _instáveis_ e recorte de janela de visualização
Conforme mais nomes aparecem na lista classificada, os nomes atuais são movidos para preservar a ordem alfabética.

No primeiro frame da imagem anterior, há quatro resultados de uma solicitação de API para animais, classificados em ordem alfabética. No segundo frame, mais resultados são adicionados à lista classificada.

O primeiro item da lista ("Gato") não muda de posição inicial entre os frames, então ele é estável. Da mesma forma, os novos itens adicionados à lista não estavam no DOM anteriormente, então as posições de início também não mudam. No entanto, os itens "Dog", "Horse" e "Zebra" mudam suas posições iniciais, tornando-se elementos instáveis.

Novamente, os retângulos vermelhos pontilhados representam a união das áreas antes e depois desses três elementos instáveis, que, neste caso, é de cerca de 60% da área da viewport (fração de impacto de 0.60).

As setas representam as distâncias que os elementos instáveis se moveram em relação às posições iniciais. O elemento "Zebra", representado pela seta azul, se moveu mais, cerca de 30% da altura da viewport. Isso faz com que a fração de distância neste exemplo seja 0.3.

A pontuação da troca de layout é 0.60 x 0.3 = 0.18.

Mudanças de layout esperadas x inesperadas

Nem todos os deslocamentos de layout são ruins. Na verdade, muitos aplicativos da Web dinâmicos mudam com frequência a posição inicial dos elementos na página. Uma mudança de layout só é ruim se o usuário não a espera.

Trocas de layout iniciadas pelo usuário

As mudanças de layout que ocorrem em resposta a interações do usuário (como clicar ou tocar em um link, pressionar um botão ou digitar em uma caixa de pesquisa) geralmente são aceitáveis, desde que a mudança ocorra perto o suficiente da interação para que a relação fique clara para o usuário.

Por exemplo, se uma interação do usuário acionar uma solicitação de rede que pode levar algum tempo para ser concluída, é melhor criar um espaço imediatamente e mostrar um indicador de carregamento para evitar uma mudança de layout desagradável quando a solicitação for concluída. Se o usuário não perceber que algo está sendo carregado ou não tiver uma ideia de quando o recurso vai ficar pronto, ele pode tentar clicar em outra coisa enquanto espera, algo que possa desaparecer.

Os deslocamentos de layout que ocorrem em até 500 milissegundos da entrada do usuário terão a flag hadRecentInput definida para que possam ser excluídos dos cálculos.

Animações e transições

As animações e transições, quando bem feitas, são uma ótima maneira de atualizar o conteúdo da página sem surpreender o usuário. Conteúdo que muda de forma abrupta e inesperada na página quase sempre gera uma experiência ruim para o usuário. No entanto, o conteúdo que muda de uma posição para a próxima de forma gradual e natural geralmente ajuda o usuário a entender melhor o que está acontecendo e o orienta entre as mudanças de estado.

Respeite as configurações do navegador prefers-reduced-motion, porque alguns visitantes do site podem ter efeitos adversos ou problemas de atenção com a animação.

A propriedade CSS transform permite animar elementos sem acionar mudanças de layout:

  • Em vez de mudar as propriedades height e width, use transform: scale().
  • Para mover elementos, evite mudar as propriedades top, right, bottom ou left e use transform: translate().

Como medir o CLS

A CLS pode ser medida no laboratório ou no campo, e está disponível nas seguintes ferramentas:

Ferramentas de campo

Ferramentas de laboratório

Medir mudanças de layout no JavaScript

Para medir as mudanças de layout em JavaScript, use a API Layout Instability.

O exemplo a seguir mostra como criar um PerformanceObserver para registrar entradas de layout-shift no console:

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('Layout shift:', entry);
  }
}).observe({type: 'layout-shift', buffered: true});

Medir o CLS no JavaScript

Para medir o CLS em JavaScript, é necessário agrupar essas entradas layout-shift inesperadas em sessões e calcular o valor máximo da sessão. Consulte o código-fonte da biblioteca JavaScript web vitals, que contém uma implementação de referência sobre como o CLS é calculado.

Na maioria dos casos, o valor atual de CLS no momento em que a página está sendo descarregada é o valor final de CLS para essa página, mas há algumas exceções importantes, conforme observado na próxima seção. A biblioteca JavaScript web vitals considera isso o máximo possível, dentro das limitações das APIs da Web.

Diferenças entre a métrica e a API

  • Se uma página for carregada em segundo plano ou se estiver em segundo plano antes que o navegador mostre qualquer conteúdo, ela não vai informar nenhum valor de CLS.
  • Se uma página for restaurada do cache de avanço e retorno, o valor de CLS dela será redefinido para zero, já que os usuários percebem isso como uma visita à página diferente.
  • A API não informa entradas de layout-shift para mudanças que ocorrem em iframes, mas a métrica sim, porque elas fazem parte da experiência do usuário na página. Isso pode mostrar uma diferença entre o CrUX e o RUM. Para medir corretamente o CLS, considere esses fatores. As subframes podem usar a API para informar as entradas layout-shift ao frame pai para agregação.

Além dessas exceções, a CLS tem uma complexidade adicional devido ao fato de medir toda a vida útil de uma página:

  • Os usuários podem manter uma guia aberta por um muito tempo, dias, semanas, meses. Na verdade, um usuário pode nunca fechar uma guia.
  • Em sistemas operacionais para dispositivos móveis, os navegadores geralmente não executam callbacks de descarregamento de página para guias em segundo plano, o que dificulta o registro do valor "final".

Para lidar com esses casos, o CLS precisa ser informado sempre que uma página está em segundo plano, além de quando ela é descarregada. O evento visibilitychange abrange esses dois cenários. E os sistemas de análise que recebem esses dados precisam calcular o valor final da CLS no back-end.

Em vez de memorizar e lidar com todos esses casos, os desenvolvedores podem usar a biblioteca JavaScript web-vitals para medir o CLS, que considera tudo o que foi mencionado acima, exceto o caso de iframe:

import {onCLS} from 'web-vitals';

// Measure and log CLS in all situations
// where it needs to be reported.
onCLS(console.log);

Como melhorar o CLS

Para mais orientações sobre como identificar mudanças de layout no campo e usar dados de laboratório para otimizar, consulte nosso guia para otimizar o CLS.

Outros recursos

Registro de alterações

Às vezes, são descobertos bugs nas APIs usadas para medir métricas e, às vezes, nas definições das próprias métricas. Como resultado, às vezes é necessário fazer mudanças, que podem aparecer como melhorias ou regressões nos relatórios e painéis internos.

Para ajudar você a gerenciar isso, todas as mudanças na implementação ou definição dessas métricas serão exibidas no Registro de alterações.

Se você tiver feedback sobre essas métricas, envie-o no grupo de feedback do Web Vitals no Google.