Mudanças inesperadas no layout podem atrapalhar a experiência do usuário de várias maneiras, desde fazer com que ele perca o lugar enquanto lê se o texto se move repentinamente até fazer com que ele clique no link ou botão errado. Em alguns casos, isso pode causar danos graves.
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 o funcionamento 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 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 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 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 burst maior é a janela de sessão com a pontuação cumulativa máxima de todas as mudanças de layout nessa 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 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 com que outros elementos visíveis mudem a 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 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.
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 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).
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
, 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:
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 botão "Click Me!" não estava no DOM anteriormente, então a posição inicial dele também não muda.
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:
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 iniciais deles também não mudam. Mas 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 todas as mudanças 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.
Mudanças 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.
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
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 posição de forma gradual e natural pode ajudar o usuário a entender melhor o que está acontecendo e a guiar 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
ewidth
, usetransform: scale()
. - Para mover elementos, evite mudar as propriedades
top
,right
,bottom
ouleft
e usetransform: 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
- Relatório de experiência do usuário do Chrome
- PageSpeed Insights
- Search Console (relatório Core Web Vitals)
- Biblioteca JavaScript
web-vitals
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 inesperadas de layout-shift
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 entradaslayout-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
- Orientações da Tag do editor do Google para 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, são descobertos bugs nas APIs usadas para medir métricas e, às vezes, nas definições das métricas. Como resultado, às vezes é necessário fazer mudanças, 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 no Registro de alterações.
Se você tiver feedback sobre essas métricas, envie no Grupo do Google web-vitals-feedback.