Resolvendo problemas de CLS em um site de comércio eletrônico com tecnologia Next.js (estudo de caso)
Publicados: 2022-03-10A Fairprice é uma das maiores mercearias online de Cingapura. Estamos continuamente procurando áreas de oportunidades para melhorar a experiência de compra online do usuário. O desempenho é um dos principais aspectos para garantir que nossos usuários tenham uma experiência agradável, independentemente de seus dispositivos ou conexão de rede.
Existem muitos indicadores-chave de desempenho (KPI) que medem diferentes pontos durante o ciclo de vida da página da Web (como TTFB, domInteractive
e onload
), mas essas métricas não refletem como o usuário final experimenta a página.
Queríamos usar alguns KPIs que correspondam de perto à experiência real dos usuários finais, para que saibamos que, se algum desses KPIs não tiver um bom desempenho, isso afetará diretamente a experiência do usuário final. Descobrimos que as métricas de desempenho centradas no usuário são perfeitas para essa finalidade.
Existem muitas métricas de desempenho centradas no usuário para medir diferentes pontos no ciclo de vida de uma página, como FCP, LCP, FID, CLS e assim por diante. Para este estudo de caso, vamos nos concentrar principalmente no CLS.
O CLS mede a pontuação total de todas as mudanças inesperadas de layout que ocorrem entre quando a página começa a ser carregada e até que ela seja descarregada.
“
Portanto, ter um valor CLS baixo para uma página garante que não haja mudanças aleatórias de layout causando frustração ao usuário. Barry Pollard escreveu um excelente artigo aprofundado sobre o CLS.
Como descobrimos o problema do CLS em nossa página de produto
Usamos o Lighthouse e o WebPagetest como nossas ferramentas de teste sintéticas de desempenho para medir o CLS. Também usamos a biblioteca web-vitals para medir o CLS para usuários reais. Além disso, verificamos a seção Relatório de Vitais da Web do Google Search Console para ter uma ideia de possíveis problemas de CLS em qualquer uma de nossas páginas. Ao explorar a seção de relatórios, descobrimos que muitos URLs da página de detalhes do produto tinham mais de 0,1 valor CLS, sugerindo que há algum evento importante de mudança de layout acontecendo lá.
Depurando o problema do CLS usando ferramentas diferentes
Agora que sabemos que há um problema de CLS na página de detalhes do produto, a próxima etapa foi identificar qual elemento estava causando isso. A princípio, decidimos executar alguns testes usando ferramentas de teste sintéticas.
Então, rodamos o farol para verificar se ele poderia encontrar algum elemento que pudesse estar provocando uma grande mudança de layout, ele relatou CLS para 0,004, o que é bastante baixo.
A página de relatório do Lighthouse tem uma seção de diagnóstico. Isso também não mostrou nenhum elemento causando um alto valor de CLS.
Em seguida, executamos o WebpageTest e decidimos verificar a visualização da tira de filme:
Achamos esse recurso muito útil, pois podemos descobrir qual elemento em que momento causou a mudança de layout. Mas quando executamos o teste para ver se alguma mudança de layout é destacada, não havia nada contribuindo para o enorme LCS:
A peculiaridade do CLS é que ele registra pontuações individuais de mudança de layout durante toda a vida útil da página e as adiciona.
“
Nota : A forma como o CLS é medido foi alterada desde junho de 2021.
Como o Lighthouse e o WebpageTest não conseguiram detectar nenhum elemento que desencadeou uma grande mudança de layout, o que significa que estava acontecendo após o carregamento inicial da página, possivelmente devido a alguma ação do usuário. Por isso, decidimos usar a extensão Web Vitals do Google Chrome, pois ela pode gravar o CLS em uma página enquanto o usuário está interagindo com ela. Depois de realizar diferentes ações, descobrimos que a pontuação de mudança de layout aumenta quando o usuário usa o recurso de ampliação da imagem.
Para verificar se a mudança de layout está ocorrendo enquanto o mouse está na imagem, usamos o snippet de código abaixo de https://web.dev/cls/ que adiciona console.log
quando ocorre a mudança de layout:
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});
Em uma investigação mais aprofundada, descobrimos que o ASDA enfrentou um tipo de problema semelhante e o levantou para o chrome.
Causa raiz
Na página de detalhes do produto, os usuários podem mover o mouse sobre a imagem do produto para visualizar uma seção ampliada da imagem lado a lado da imagem real do produto, pois este vídeo mostra exatamente do que estamos falando.
O recurso de ampliação de imagem ajuda nossos usuários a obter a aparência do produto, além de garantir que seja a variante correta do produto que desejam comprar.
Usamos a biblioteca de react-image zoom
para criar essa funcionalidade de ampliação de imagem.
As bibliotecas Image Magnify geralmente têm uma lente (um quadrado que se move quando o mouse se move dentro da imagem). Como essa lente muda sua posição superior e esquerda com o movimento do mouse, ela está sendo detectada como uma mudança de layout que aciona o CLS. Verificamos a página da biblioteca, bem como outras bibliotecas de reação semelhantes ( react-image-magnify
, react-image-zoom
, react-image-magnifiers
) e descobrimos que todas elas estão sofrendo do mesmo problema de CLS.
Como consertamos
Percebemos que react-image-zoom
estava usando a biblioteca js-image-zoom
. Portanto, tivemos que modificar a biblioteca de js-image zoom
para corrigir o problema.
A solução é bastante simples. Enquanto o mouse se move na imagem do produto, o elemento da lente da imagem se move alterando sua posição esquerda e superior. Para corrigir o problema, usamos transform translate
que move o elemento para uma nova camada, ou seja, qualquer movimento que ocorra nessa nova camada não causa mais mudança de layout:
Também criei um PR para o repositório original para que outros desenvolvedores que usam essa biblioteca possam se livrar do problema do CLS.
O impacto da mudança
Depois que o código foi implantado na produção, o CLS foi corrigido na página de detalhes do produto e o número de páginas impactadas com o CLS foi reduzido em 98%:
Como usamos transform
, isso também ajudou a ampliar a imagem para uma experiência mais suave para os usuários.
Nota : Paul Irish escreveu um excelente artigo sobre este tema.
Outras mudanças importantes que fizemos para o CLS
Há também alguns outros problemas que enfrentamos em muitas páginas do nosso site que contribuem para o CLS. Vamos examinar esses elementos e componentes e ver como tentamos mitigar as mudanças de layout decorrentes deles.
Fontes da Web:
Percebemos que o carregamento tardio de fontes causa frustrações ao usuário, pois o conteúdo pisca e também causa algumas mudanças de layout. Para minimizar isso, fizemos algumas alterações:- Nós auto-hospedamos as fontes em vez de carregar de CDN de terceiros.
- Nós pré-carregamos as fontes.
- Usamos font-display opcional.
Imagens:
O valor de altura ou largura ausente na imagem faz com que o elemento após a imagem se desloque quando a imagem for carregada. Isso acaba se tornando um dos principais contribuintes para o CLS. Como estamos usando Next.js, aproveitamos o componente de imagem integrado chamadonext/images
. Este componente incorpora várias práticas recomendadas relacionadas a imagens. Ele é construído sobre a tag HTML<img>
e pode ajudar a melhorar o LCP e o CLS. Eu recomendo a leitura deste RFC para descobrir os principais recursos e vantagens de usá-lo.Rolagem infinita:
Em nosso site, as páginas de listagem de produtos têm rolagem infinita. Então, inicialmente, quando os usuários rolam até o final da página, eles veem um rodapé por uma fração de segundos antes que o próximo conjunto de dados seja carregado, isso causa mudanças de layout. Para resolver isso, tomamos alguns passos:- Chamamos a API para carregar dados antes mesmo que o usuário chegue ao final absoluto da lista.
- Reservamos espaço suficiente para o estado de carregamento e mostramos os esqueletos do produto durante o status de carregamento. Então, agora, quando o usuário rola, ele não vê o rodapé por uma fração de segundos enquanto os produtos estão sendo carregados.
Addy Osmani escreveu um artigo detalhado sobre essa abordagem que eu recomendo verificar.
Principais conclusões
- Embora o Lighthouse e o WebpageTest ajudem a descobrir problemas de desempenho que ocorrem até o carregamento da página, eles não podem detectar problemas de desempenho após o carregamento da página.
- As extensões do Web Vitals podem detectar alterações de CLS acionadas por interações do usuário, portanto, se uma página tiver um valor CLS alto, mas o Lighthouse ou o WebpageTest relatar um CLS baixo, a extensão do Web Vitals poderá ajudar a identificar o problema.
- Os dados do Google Search Console são baseados em dados de usuários reais para que também possam apontar para possíveis problemas de desempenho que ocorrem em qualquer ponto do ciclo de vida de uma página. Depois que um problema for detectado e corrigido, verificar a seção de relatório novamente pode ajudar a verificar a eficácia da correção de desempenho. As alterações são refletidas em poucos dias na seção de relatório do Web vitals.
Pensamentos finais
Embora os problemas do CLS sejam comparativamente mais difíceis de depurar, usar uma combinação de ferramentas diferentes até o carregamento da página (Lighthouse, WebPageTest) e a extensão Web Vitals (após o carregamento da página) pode nos ajudar a identificar o problema. É também uma das métricas que está passando por muito desenvolvimento ativo para cobrir uma ampla gama de cenários e isso significa que a forma como é medida será alterada no futuro. Estamos seguindo https://web.dev/evolving-cls/ para saber sobre quaisquer mudanças futuras.
Quanto a nós, estamos trabalhando continuamente para melhorar também outros Core Web Vitals. Recentemente, implementamos o pré-carregamento de imagem responsivo e começamos a veicular imagens no formato WebP, o que nos ajudou a reduzir 75% da carga útil da imagem, reduzir o LCP em 62% e o Índice de velocidade em 24%. Você pode ler mais detalhes de otimização para melhorar o LCP e o Índice de velocidade ou seguir nosso blog de engenharia para conhecer outros trabalhos interessantes que estamos fazendo.
Gostaríamos de agradecer a Alex Castle por nos ajudar a depurar o problema do CLS na página do produto e resolver as peculiaridades na implementação de next/images
.