Eu ia clicar naquele botão! Por que a tela mexeu? 😭
Deslocamentos de Layout (Layout Shifts) podem distrair/atrapalhar as pessoas. Imagine que você começou a ler um artigo quando, de repente, elementos se deslocam pela página, causando desorientação momentânea e exigindo que você encontre novamente o lugar que estava.
Isso é muito comum na Web, inclusive ao ler as notícias ou ao clicar em botões como “Pesquisar” ou “Adicionar ao carrinho”. Tais experiências são visualmente chocantes e frustrantes.
Elas geralmente são causadas quando elementos visíveis são forçados a se mover porque outro elemento foi subitamente adicionado à página ou redimensionado.
Deslocamento Cumulativo de Layout, ou Cumulative Layout Shift (CLS), é uma métrica que faz parte dos Princípios Vitais da Web ou Core Web Vitals, para medir a instabilidade do conteúdo, somando as pontuações dos trancos de layout que não ocorrem a menos de 500ms de entradas de usuário (user input).
A métrica analisa a quantidade de conteúdo visível alterado na viewport e a distância em que os elementos afetados foram alterados.
Neste guia, abordaremos a otimização de causas comuns de Layout Shift.
Os casos mais comuns para um CLS ruim são:
- Imagens sem dimensões especificadas
- Anúncios, embeds e iframes sem dimensões especificadas
- Conteúdo dinâmico
- Fontes causando FOIT/FOUT
- Ações aguardando resposta de rede antes de atualizar o DOM
Deslocamento de Layout por Imagens sem dimensões especificadas
tl;dr Sempre inclua atributos de tamanho de largura (width
) e altura (height
) em imagens e elementos de vídeo. Como alternativa, reserve o espaço necessário aspect ratio de CSS. Essa abordagem garante que o navegador possa alocar a quantidade correta de espaço no documento enquanto as imagens estão sendo carregadas.
Uma das causas mais frequentes para Deslocamento de Layout acontecer são imagens não têm largura e altura especificadas:
Eis a diferença quando têm:
Histórico
Nos primórdios da Web, os desenvolvedores adicionávamos atributos de largura e altura às tags <img>
para garantir que espaço suficiente fosse alocado na página antes do navegador começar a baixar as imagens. Isso minimizava reflow e relayout.
1 |
<img src="puppy.jpg" width="640" height="360" alt="Cachorrinho brincando"> |
Note que a largura e a altura acima não incluem unidades. Essas dimensões de “pixel” garantiam que uma área de 640x360
seria reservada. A imagem se estenderia para caber nesse espaço, independentemente de as dimensões reais corresponderem ou não.
Quando surgiu Web Design Responsivo, os desenvolvedores começamos a omitir width
e height
e começamos a usar CSS para redimensionar imagens:
1 2 3 4 |
img { height: auto; width: 100%; /* ou max-width: 100%; */ } |
Uma desvantagem dessa abordagem é que o espaço só pode ser alocado para uma imagem depois que ela começa a ser baixada e o navegador pode determinar suas dimensões. À medida que as imagens eram carregadas, a página refletia essa mudança.
Tornou-se comum o texto aparecer subitamente na tela, o que, definitivamente, não é algo positivo para uma UX adequada. Aqui entra aspect ratio ou proporção. A proporção de uma imagem é a proporção entre sua largura e altura.
É comum ver isso expresso como dois números separados por dois pontos (por exemplo, 4:3
ou 16:9
). Para uma proporção de aspecto x:y
, a imagem tem x
unidades de largura e y
unidades de altura.
Isso significa que, se se conhece uma das dimensões, a outra pode ser determinada. Para um aspect ratio de 16:9
:
- Se
puppy.jpg
tiver uma altura de360px
, a largura será360 x (16 / 9) = 640px
- Se
puppy.jpg
tiver uma largura de640px
, a altura será640 x (9 / 16) = 360px
O conhecimento da proporção permite que o navegador calcule e reserve espaço suficiente para a altura e a área associadas.
Melhores práticas modernas
Navegadores modernos agora definem a proporção padrão das imagens com base nos atributos de width
e height
de uma imagem, por isso é recomendado configurá-los para evitar trancos no layout.
Graças ao CSS Working Group, os desenvolvedores precisamos definir largura e altura normalmente:
1 2 |
<!-- 16:9 aspect ratio --> <img src="puppy.jpg" width="640" height="360" alt="Cachorrinho brincando"> |
E as UA stylesheets de todos os navegadores adicionam uma proporção padrão com base nos atributos de largura e altura existentes do elemento:
1 2 3 |
img { aspect-ratio: attr(width) / attr(height); } |
Isso calcula uma proporção com base nos atributos width
e height
antes do carregamento da imagem, provendo essas informações no início do cálculo do layout.
Assim que se diz que uma imagem tem uma certa largura (por exemplo, largura: 100%), a proporção é usada para calcular a altura.
As alterações na proporção da imagem, mostradas acima, já estão disponíveis (na data de publicação deste artigo) no Firefox e no Chromium e estão chegando ao WebKit (Safari).
Se a imagem estiver em um contêiner, é possível usar CSS para redimensionar a imagem para a largura desse contêiner definindo height: auto;
para evitar que a altura da imagem seja um valor fixo (por exemplo, 360px
).
E as imagens responsivas?
Ao trabalhar com imagens responsivas, srcset
define as imagens que você permite ao navegador selecionar e qual o tamanho de cada imagem. Para garantir que os atributos largura e altura de <img>
possam ser definidos, cada imagem deve usar a mesma proporção.
1 2 3 4 5 6 |
<img width="1000" height="1000" src="puppy-1000.jpg" srcset="puppy-1000.jpg 1000w, puppy-2000.jpg 2000w, puppy-3000.jpg 3000w" alt="Cachorrinho brincando"/> |
Também com solução para quando é preciso direção de arte:
1 2 3 4 5 |
<picture> <source media="(max-width: 799px)" srcset="puppy-480w-cropped.jpg"> <source media="(min-width: 800px)" srcset="puppy-800w.jpg"> <img src="puppy-800w.jpg" alt="Cachorrinho brincando"> </picture> |
Se ficou com dúvidas sobre srcset, picture com source e outras questões sobre imagens responsivas, confira nosso artigo sobre imagens responsivas com srcset e sizes.
É muito possível que essas imagens tenham proporções diferentes e os navegadores ainda estejam avaliando qual deve ser a solução mais eficiente, inclusive se as dimensões devem ser especificadas em todas as fontes. Até que uma solução seja decidida, relayout ainda pode acontecer aqui.
Anúncios, embeds e iframes sem dimensões especificadas
Como citado, outro ponto dos casos mais comuns para deslocamentos de layout, causando um CLS ruim, são anúncios, embeds e iframes sem dimensões especificadas.
Anúncios
Anúncios (os famosos ads) são bem problemáticos em relação a Layout Shift na Web. As redes de anúncios e os editores geralmente oferecem suporte a tamanhos de anúncios dinâmicos.
Infelizmente, isso pode contribuir para uma experiência de usuário abaixo do ideal devido aos anúncios que empurram o conteúdo visível na página.
Durante o ciclo de vida do anúncio, o deslocamento de layout pode acontecer em vários momentos:
- Quando o site insere o contêiner de anúncio no DOM
- Quando o site redimensiona o contêiner de anúncio com código original
- Quando a biblioteca de tags de anúncio é carregada (e redimensiona o contêiner de anúncio)
- Quando o anúncio preenche um contêiner (e redimensiona se o anúncio final tiver um tamanho diferente)
A boa notícia é que é possível seguir determinadas práticas recomendadas para reduzir mexidas de tela com anúncios:
- Coloque anúncios em espaços reservados estaticamente.
- Em outras palavras, estilize o elemento antes do carregamento da biblioteca de tags de anúncio.
- Se colocar anúncios no fluxo de conteúdo, garanta que as mudanças sejam eliminadas reservando o tamanho do slot. Esses anúncios não devem causar alterações no layout se forem carregados fora da tela.
- Tome cuidado ao colocar anúncios não-sticky perto da parte superior da viewport.
- No exemplo abaixo, é recomendável mover o anúncio para abaixo do logotipo e reservar espaço suficiente para o slot.
- Evite recolher o espaço reservado se nenhum anúncio for retornado quando o espaço de anúncio estiver visível, mostrando um placeholder.
- Elimine deslocamentos reservando o maior tamanho possível para o espaço de anúncio.
- Isso funciona, mas corre o risco de ter um espaço em branco se um anúncio menor for colocado no slot.
- Escolha o tamanho mais provável para o slot do anúncio com base em dados do histórico.
Alguns podem achar que o recolhimento do slot (collapsing) inicialmente pode reduzir layout shifts se o espaço de anúncio não for preenchido, mas não há uma maneira fácil de escolher o tamanho exato de cada vez, a menos que você controle o anúncio que está sendo veiculado.
O que acha disso?
Comparado com isso:
Coloque anúncios em espaços reservados estaticamente
Isso pode ajudar a garantir que a biblioteca não introduza mudanças de layout ao carregar. Se você não fizer isso, a biblioteca poderá alterar o tamanho do elemento do slot após o carregamento do layout da página.
Quando o assunto é deslocamento de layouts, considere também os tamanhos das veiculações de anúncios menores.
Se um anúncio menor for exibido, um editor poderá estilizar o contêiner (maior) para evitar alterações no layout — a desvantagem dessa abordagem é que ela aumentará a quantidade de espaço em branco; considere o custo/benefício da abordagem.
Embeds e iframes
Widgets incorporados (embedded) permitem enxertar conteúdos em páginas (por exemplo, vídeos do YouTube, mapas do Google Maps, posts de mídia social etc.). Essas incorporações podem assumir várias formas:
- Fallback de HTML e uma tag JavaScript que transformam o fallback em um embed sofisticado
- Snippet HTML embutido
- iframe incorporado
Essas incorporações geralmente não têm conhecimento antecipado do tamanho de uma incorporação (por exemplo, no caso de uma postagem de mídia social, ela possui uma imagem incorporada? Vídeo? Várias linhas de texto?).
Como resultado, as plataformas que oferecem incorporações nem sempre reservam espaço suficiente para elas e podem causar alterações no layout quando elas finalmente são carregadas.
Um exemplo de deslocamento de layout com iframe embedado:
E aqui quando se reserva um espaço apropriado:
Para contornar isso, você pode minimizar o CLS pré-computando espaço suficiente para incorporações com um espaço reservado ou fallback.
Um fluxo sugerido:
- Obtenha a altura da sua incorporação final, inspecionando-a com as DevTools
- Depois que estiver carregada, o iframe contido será redimensionado para caber, de modo que o conteúdo caiba
Anote as dimensões e providencie um placeholder condizente. Pode ser necessário considerar diferenças sutis nos tamanhos de anúncio entre diferentes fatores usando media queries.
Deslocamento de Layout por Conteúdo dinâmico
tl;dr Para prevenir deslocamento de layout, evite inserir novo conteúdo acima do conteúdo existente, a menos que em resposta a uma interação do usuário. Isso garante que todas as mudanças de layout que ocorrem sejam esperadas.
Você provavelmente já sofreu com deslocamento de conteúdo devido à UI que aparece na parte superior ou inferior da viewport ao tentar carregar um site.
Semelhante aos anúncios, isso geralmente acontece com banners e formulários que alteram o restante do conteúdo da página:
- “Conteúdo Relacionado”
- “Instale nosso aplicativo”
- “Ainda estamos recebendo pedidos”
- “Aviso GDPR”
- etc.
Se você precisar exibir esses tipos de recursos de UI, reserve espaço suficiente na viewport com antecedência (por exemplo, usando placeholder loadings) para que, quando carregada, não faça com que o conteúdo da página mude de repente, causando layout shift.
Fontes causando FOIT/FOUT
O download e renderização de fontes Web podem causar alterações no layout de 2 maneiras:
- A fonte de fallback é trocada por uma nova fonte (FOUT – Flash of Unstyled Text)
- O texto “invisível” é exibido até que uma nova fonte seja renderizada (FOIT – Flash of Invisible Text)
As seguintes técnicas podem ajudar a minimizar esses problemas:
font-display
permite modificar o comportamento de renderização de fontes personalizadas com valores comoauto
,swap
,block
,fallback
eoptional
. Infelizmente, todos esses valores (excetooptional
) podem causar relayout de uma das maneiras acima.- A Font Loading API pode reduzir o tempo necessário para obter as fontes necessárias
Também é recomendado:
- Usar
<link rel="preload">
nas principais fontes Web usadas: uma fonte pré-carregada terá uma chance maior de aparecer na first paint (nesse caso, não haverá alteração no layout). - Combinar
<link rel=preload>
efont-display: optional
Deslocamento de Layout por Animações
tl;dr Dê preferência a usar a propriedade transform
em animações de propriedades que acionam alterações de layout.
Alterações nos valores de propriedade CSS exigem que o navegador reaja a essas alterações. Vários valores acionam o relayout, paint e composite, como box-shadow
e box-sizing
.
Várias propriedades CSS podem ser alteradas de maneira menos dispendiosa. A tabelinha CSS Triggers mostra exatamente quais propriedades ativam que ações.
DevTools
Felizmente, existem diversas ferramentas disponíveis para medir e depurar o CLS (Cumulative Layout Shift).
Lighthouse, a partir do 6.0, inclui suporte para medir o CLS, além de destacar os nós que causam mais deslocamento de layout.
O painel Performance nas DevTools destaca os deslocamentos de layout na seção Experience. A visualização do Resumo de um layout shift inclui a pontuação cumulativa de mudança de layout, bem como uma sobreposição de retângulo mostrando as regiões afetadas.
Certamente, um tipo de relatório mais do que útil, que realmente pode fazer a diferença em uma otimização de performance ao identificar deslocamentos de conteúdo.
Conclusão
Como foi visto neste verdadeiro guia sobre como melhorar Cumulative Layout Shift, diversos e variados podem ser os fatores que causam deslocamento de layout:
Imagens sem dimensões especificadas, anúncios, embeds e iframes sem dimensões especificadas, conteúdo dinâmico, fontes causando FOIT/FOUT, ações aguardando resposta de rede antes de atualizar o DOM e animações.
Para cada um deles, existe (pelo menos) uma possibilidade de mitigação de layout shift para melhorar a qualidade do projeto e evitar frustrações desnecessárias dos visitantes.
A métrica “CLS”, embora vista com mais preocupação só mais recentemente, deve ser considerada quando o assunto é a otimização de performance e UX de projetos Web.