Mudanças inesperadas de layout podem prejudicar a experiência do usuário de muitas maneiras, desde fazer com que ele se perca de lugar durante a leitura se o texto se mover repentinamente ou fazer com que cliquem no link ou botão errado. Em alguns casos, isso pode causar danos graves.
A movimentação inesperada do conteúdo da página geralmente acontece quando os recursos são carregados de maneira assíncrona ou os elementos DOM são adicionados dinamicamente à página antes do conteúdo existente. As mudanças de layout podem ser causadas por imagens ou vídeos com dimensões desconhecidas, fontes renderizadas maiores ou menores do que o substituto inicial ou anúncios ou widgets de terceiros que se redimensionam dinamicamente.
Há diferenças entre o funcionamento de um site em desenvolvimento e a experiência dos usuários que piora esse problema. Exemplo:
- O conteúdo personalizado ou de terceiros geralmente se comporta de maneira diferente no desenvolvimento e na produção.
- Geralmente, as imagens de teste já estão no cache do navegador do desenvolvedor, mas levam mais tempo para serem carregadas para o usuário final.
- As chamadas de API executadas localmente são frequentemente tão rápidas que atrasos imperceptíveis no desenvolvimento podem se tornar substanciais na produção.
A métrica Cumulative Layout Shift (CLS) ajuda a solucionar esse problema medindo a frequência com que ele ocorre para usuários reais.
O que é CLS?
A CLS é uma medida do maior burst de pontuações de mudança 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 a posição de um frame renderizado para outro. Os detalhes sobre como as pontuações de mudanças de layout individuais são calculadas são abordados mais adiante neste guia.
Um burst de mudanças de layout, conhecido 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 um máximo de 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 trocas de layout dentro dessa janela.
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 você alcance essa meta para a maioria dos usuários, um bom limite para medir é o 75o percentil de carregamentos de página, segmentado em dispositivos móveis e computadores.
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 de 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. Esses elementos 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 um existente mudar de tamanho, isso 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 alterem sua posição inicial.
Pontuação da troca de layout
Para calcular a pontuação de troca de layout, o navegador analisa o tamanho da janela de visualização e o movimento de elementos instáveis nela entre dois frames renderizados. A pontuação da troca de layout é o 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 quanto 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 desse frame e do frame anterior, como uma fração da área total da janela de visualização.
![Exemplo de fração de impacto com um elemento instável](https://web.dev/static/articles/cls/image/impact-fraction-example-164341c82ee76.png?authuser=6&hl=pt)
Na imagem anterior, há um elemento que ocupa metade da janela de visualização em um frame. No frame seguinte, o elemento é deslocado 25% da altura da janela de visualização. O retângulo pontilhado vermelho indica a união da área visível do elemento nos dois frames, que, nesse caso, representa 75% da janela de visualização total. Portanto, a fração de impacto é 0.75
.
Fração de distância
A outra parte da equação de pontuação da troca 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](https://web.dev/static/articles/cls/image/distance-fraction-example-9146d2a862482.png?authuser=6&hl=pt)
No exemplo anterior, a maior dimensão da janela de visualização é a altura, e o elemento instável se moveu 25% da altura, 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
, então a pontuação de 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 troca de layout:
![Exemplo de mudança de layout com vários elementos estáveis e _instáveis_](https://web.dev/static/articles/cls/image/layout-shift-example-mul-10d90b67b5d6a.png?authuser=6&hl=pt)
Neste exemplo, a caixa cinza muda de tamanho, mas a posição inicial não muda, por isso ela não é um elemento instável.
O aplicativo "Click Me!" não estava anteriormente no DOM, e sua posição inicial também não foi alterada.
No entanto, a posição inicial da caixa verde muda, mas como ela foi parcialmente movida 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. Como a caixa verde foi movida para baixo em cerca de 14% da janela de visualizaçã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 troca de layout de uma página:
![Exemplo de mudança de layout com _elementos estáveis e _unstable_ e recorte da janela de visualização](https://web.dev/static/articles/cls/image/layout-shift-example-sta-05cf93597fcee.png?authuser=6&hl=pt)
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 sua posição inicial entre os frames, por isso é estável. Da mesma forma, os novos itens adicionados à lista não estavam anteriormente no DOM e, portanto, suas posições iniciais também não foram alteradas. Mas os itens rotulados como "Cão", "Cavalo" e "Zebra" mudar as posições iniciais, o que os torna elementos instáveis.
Novamente, os retângulos pontilhados vermelhos representam a união desses três elementos instáveis. áreas antes e depois, que nesse caso são 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 se moveram das posições iniciais. A "Zebra" representado pela seta azul, que mais se moveu: cerca de 30% da altura da janela de visualização. 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
.
Trocas de layout esperadas e inesperadas
Nem todas as trocas de layout são ruins. De fato, 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 está esperando.
Trocas 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 boas, desde que a mudança ocorra próxima o suficiente da interação, de modo 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 um tempo para ser concluída, é melhor criar algum 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 noção de quando o recurso estará pronto, ele pode tentar clicar em outra coisa enquanto espera, algo que pode sair de baixo dele.
As mudanças de layout que ocorrem até 500 milissegundos após a entrada do usuário têm a flag hadRecentInput
definida. Portanto, elas podem 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 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 se move de maneira gradual e natural de uma posição para outra muitas vezes 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
, já que algumas pessoas podem notar efeitos nocivos ou problemas de atenção na animação.
A propriedade CSS transform
permite animar elementos sem acionar mudanças de layout:
- Em vez de mudar as propriedades
height
ewidth
, usetransform: scale()
. - Para mover elementos, evite mudar as propriedades
top
,right
,bottom
ouleft
e usetransform: translate()
.
Como medir a CLS
A CLS pode ser medida no laboratório ou em campo e está disponível nestas ferramentas:
Ferramentas de campo
- Experiência do usuário no Chrome Relatório
- PageSpeed Insights
- Search Console (Core Web Vitals) do Google Ads)
- Biblioteca JavaScript
web-vitals
Ferramentas do laboratório
Medir mudanças de layout em JavaScript
Para medir as mudanças de layout no JavaScript, use a API Layout Instability.
O exemplo a seguir mostra como criar um PerformanceObserver
para registrar entradas do 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 em JavaScript
Para medir a CLS em JavaScript, agrupe essas entradas layout-shift
inesperadas em sessões e calcule o valor máximo da sessão. Você pode consultar 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 de CLS atual no momento em que a página está sendo descarregada é o valor final da página, mas existem 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 Web.
Diferenças entre a métrica e a API
- Se uma página é carregada em segundo plano, ou se está em segundo plano antes de o navegador exibir o conteúdo, ela não deve informar nenhum valor de CLS.
- Se uma página for restaurada do cache de avanço e retorno, o valor de CLS dela precisará ser redefinido para zero, já que os usuários percebem isso como uma visita diferente à página.
- A API não informa entradas
layout-shift
para mudanças que ocorrem nos iframes, mas a métrica faz isso porque elas fazem parte da experiência do usuário na página. Isso pode aparecer como uma diferença entre CrUX e RUM. Para medir corretamente a CLS, você deve considerá-las. Os subframes podem usar a API para informar as entradaslayout-shift
ao frame pai para agregação.
Além dessas exceções, a CLS tem certa complexidade porque mede toda a vida útil de uma página:
- Os usuários podem manter uma guia aberta por muito tempo, como dias, semanas, meses. Na verdade, o usuário pode nunca fechar uma guia.
- Em sistemas operacionais 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 de resultados "finais". .
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 vão precisar calcular o valor final de 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 o 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 em campo e usar dados de laboratório para otimizá-las, consulte nosso guia sobre como otimizar a CLS.
Outros recursos
- Orientação da Tag do editor do Google sobre como minimizar a mudança de layout
- Understanding Cumulative Layout Shift (link em inglês), de Annie Sullivan e Steve Kobes em #PerfMatters (2020)
Registro de alterações
Às vezes, eles são descobertos nas APIs usadas para medir as métricas e, às vezes, nas definições das próprias métricas. Como resultado, é preciso fazer alterações algumas vezes e elas podem aparecer como melhorias ou regressões nos seus relatórios e painéis internos.
Para ajudar você a gerenciar isso, todas as alterações na implementação ou na definição dessas métricas serão exibidas neste registro de alterações.
Se você tiver feedback sobre essas métricas, envie no Grupo do Google web-vitals-feedback.