Cumulative Layout Shift (CLS)

Compatibilidade com navegadores

  • 77
  • 79
  • x
  • x

Origem

Mudanças inesperadas de layout podem atrapalhar a experiência do usuário de várias maneiras, fazendo com que ele se perca durante a leitura (se o texto se mover repentinamente) ou fazendo 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 o usuário confirmar um pedido grande que pretendia cancelar.

A movimentação inesperada do conteúdo da página geralmente acontece quando os recursos carregam de forma assíncrona ou os elementos DOM são adicionados dinamicamente à página antes do conteúdo existente. As mudanças de layout podem ser imagens ou vídeos com dimensões desconhecidas, fontes que renderizam maior ou menor do que o substituto inicial ou anúncios ou widgets de terceiros que se redimensionam dinamicamente.

As diferenças entre o funcionamento de um site durante o desenvolvimento e a experiência dos usuários tornam esse problema pior. Exemplo:

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

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

O que é CLS?

A CLS é uma medida da maior quantidade de pontuações de mudanças de layout para cada mudança inesperada 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 outro. Mais detalhes sobre como as pontuações de mudanças de layout individuais são calculadas mais adiante neste guia.

Uma sequência de mudanças de layout, conhecida como janela de sessão, ocorre quando uma ou mais mudanças de layout individuais ocorrem em rápida sucessão, com menos de 1 segundo entre cada mudança e no máximo 5 segundos para a duração total da janela.

O maior burst é 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 individual.

O que é uma boa pontuação de CLS?

Para oferecer uma boa experiência do usuário, os sites precisam 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 75o percentil de carregamentos de página, segmentado em dispositivos móveis e computadores.

Os valores bons de CLS são 0,1 ou menores, os valores ruins são maiores do que 0,25 e qualquer valor intermediário precisa ser melhorado
Valores bons de CLS são 0,1 ou menos. 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 Core Web Vitals.

Mudanças 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 janela de visualização muda a posição inicial (por exemplo, a posição superior e esquerda no modo de gravação padrão) entre dois frames. Eles são considerados elementos instáveis.

As mudanças de layout só ocorrem quando os elementos existentes mudam a posição inicial. Se um novo elemento for adicionado ao DOM ou se um elemento existente mudar de tamanho, ele não será contabilizado como uma mudança de layout, desde que a alteração não faça com que outros elementos visíveis mudem 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 entre dois frames renderizados. A pontuação da mudança de layout é 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 impactam 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 desse frame e do anterior, como uma fração da área total da janela de visualização.

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 contribuem para a fração de impacto.

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

Fração da 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 moveu no frame dividida 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 o quanto um elemento foi movido na janela de visualização.

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

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

Exemplos

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

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

Neste exemplo, a caixa cinza muda de tamanho, mas a posição inicial não muda para que não seja um elemento instável.

O botão "Click Me!" não estava anteriormente no DOM, por isso, sua posição inicial também não muda.

A posição inicial da caixa verde, no entanto, muda, mas como ela foi movida parcialmente para fora da janela de visualização, 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 em ambos os frames (ilustrada pelo retângulo vermelho pontilhado) é a mesma que a área da caixa verde no primeiro frame — 50% da janela de visualização. 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 janela de visualização, 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 instáveis_ e recorte da 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 quadro 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 a posição inicial entre os frames, por isso é estável. Da mesma forma, os novos itens adicionados à lista não estavam anteriormente no DOM, portanto, suas posições iniciais também não mudam. No entanto, os itens rotulados como "Cachorro", "Cavalo" e "Zebra" mudam de posição inicial, o que os torna elementos instáveis.

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

As setas representam as distâncias que os elementos instáveis moveram das posições iniciais. O elemento "Zebra", representado pela seta azul, foi o mais movido, em cerca de 30% da altura da janela de visualização. Isso torna a fração de distância neste exemplo 0.3.

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

Mudanças de layout esperadas e inesperadas

Nem todas as trocas de layout são ruins. Na verdade, muitos aplicativos da Web dinâmicos costumam alterar a posição inicial dos elementos na página. Uma mudança de layout só é ruim se o usuário não estiver esperando isso.

Mudanças de layout iniciadas pelo usuário

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á carregando ou não tiver uma ideia de quando o recurso estará pronto, ele poderá tentar clicar em outra coisa enquanto espera, algo que pode sair por baixo dele.

Mudanças de layout que ocorrem até 500 milissegundos após a entrada do usuário terão a flag hadRecentInput definida para que possam ser excluídas dos cálculos.

Animações e transições

Animações e transições, quando bem-feitas, são uma ótima maneira de atualizar o conteúdo na página sem surpreender o usuário. Conteúdos que mudam de forma abrupta e inesperada na página quase sempre criam uma experiência ruim para o usuário. No entanto, o conteúdo que se move de maneira gradual e natural de uma posição para outra geralmente pode ajudar o usuário a entender melhor o que está acontecendo e guiá-lo entre as mudanças de estado.

Respeite as configurações do navegador prefers-reduced-motion, porque alguns visitantes do site podem notar efeitos nocivos ou problemas de atenção durante as animações.

Com a propriedade CSS transform, é possível 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. Em vez disso, use transform: translate().

Como medir a CLS

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

Ferramentas de campo

Ferramentas de laboratório

Medir mudanças de layout em 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 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 a CLS no JavaScript

Para medir a CLS em JavaScript, você precisa 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 a CLS é calculada.

Na maioria dos casos, o valor atual do CLS no momento em que a página está sendo descarregada é o valor final da página, mas há algumas exceções importantes, conforme indicado na próxima seção. A biblioteca JavaScript web vitals considera isso o máximo possível, dentro das limitações das APIs 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 da exibição do conteúdo pelo navegador, ela não deverá relatar nenhum valor de CLS.
  • Se uma página for restaurada do cache de avanço e retorno, o valor da CLS precisará ser redefinido como zero, já que isso é registrado como uma visita diferente à página para os usuários.
  • A API não informa entradas de layout-shift para mudanças que ocorrem em iframes, mas a métrica faz isso 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 a CLS, você precisa considerá-los. Os subframes podem usar a API para informar as entradas layout-shift ao frame pai para agregação.

Além dessas exceções, a CLS apresenta certa complexidade devido ao fato de que mede toda a vida útil de uma página:

  • Os usuários podem manter uma guia aberta por muito tempo: dias, semanas, meses. Na verdade, é possível que um usuário nunca feche uma guia.
  • Em sistemas operacionais para dispositivos móveis, os navegadores normalmente não executam callbacks de descarregamento de páginas para guias em segundo plano, o que dificulta a geração de relatórios do valor "final".

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

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

import {onCLS} from 'web-vitals';

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

Como melhorar a CLS

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

Outros recursos

Registro de alterações

Às vezes, são encontrados bugs nas APIs usadas para medir as métricas e, às vezes, nas próprias definições de métricas. Por isso, às vezes é preciso fazer alterações, que podem aparecer como melhorias ou regressões nos seus 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 neste registro de alterações.

Se você tiver feedback sobre essas métricas, envie seu feedback no Grupo do Google web-vitals-feedback.