Lighthouse

CLS no WordPress: imagem sem width e height pulando a página no mobile

O Lighthouse aponta Image elements do not have explicit width and height e, no celular, o texto desce de repente quando a foto termina de carregar. Em quase todo tema que eu abro a causa é a mesma: um <img> montado na mão dentro do template, com a URL saindo de get_the_post_thumbnail_url().

Essa função devolve só a URL, mais nada. Sem os atributos width e height o navegador não tem como reservar o espaço antes do download: ele renderiza o texto colado e empurra tudo pra baixo depois. Esse empurrão é o CLS.

Deixe o WordPress escrever as dimensões

Troque a tag manual por wp_get_attachment_image(). Ela lê os metadados do anexo e devolve width, height, srcset e sizes prontos:

<?php
echo wp_get_attachment_image(
    get_post_thumbnail_id( get_the_ID() ),
    'large',
    false,
    array( 'class' => 'card-thumb' )
);

No upload o WordPress grava largura e altura reais de cada tamanho em _wp_attachment_metadata, e é de lá que a função tira os números. Com os dois atributos no HTML o navegador já segura o buraco do tamanho certo. Dentro do loop, the_post_thumbnail( 'large' ) faz o mesmo serviço.

Uma coisa que eu não passo mais no array de atributos: 'loading' => 'lazy'. Desde a 6.3 quem decide loading e fetchpriority é a wp_get_loading_optimization_attributes(), e forçar lazy marca a imagem como fora da viewport. Na primeira imagem da página isso tira o fetchpriority="high" e piora o LCP enquanto você conserta o CLS.

A armadilha da imagem esmagada

Agora o height virou um número fixo no HTML. Se o layout for fluido, a largura encolhe no celular e a altura não acompanha, deixando a foto achatada. O par que resolve mora no style.css do tema:

.card-thumb {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

O height: auto devolve a proporção pro CSS sem apagar os atributos que o navegador usou pra reservar o espaço, e o aspect-ratio só vale enquanto a altura estiver em auto. Rode o Lighthouse em modo mobile depois de publicar: o aviso some e o CLS cai junto.

Se travou nisso e precisa de ajuda, me chama aqui.

Post Recentes

CSRF no CodeIgniter 4: The action you requested is not allowed no AJAX

O primeiro POST via AJAX passa e o segundo estoura 403 porque o token foi regenerado. Envie o hash no…

1 dia atrás

Certbot renew sem reload do nginx: o navegador ainda vê o certificado vencido

O certbot diz que renovou, o navegador insiste que o certificado expirou. Compare as datas com openssl e crie o…

1 dia atrás

Campo bloqueado no admin do Magento 2: config travada pelo env.php

O campo aparece cinza no painel avisando que o valor vem de arquivo? Descubra o caminho da chave, remova do…

2 dias atrás

array_filter no PHP apaga o 0 junto: como filtrar só o que é vazio

Chamar array_filter sem callback descarta 0, '0' e false junto com os vazios. Veja o callback certo, o ARRAY_FILTER_USE_BOTH e…

3 dias atrás

413 Request Entity Too Large no WordPress: ajuste nginx e PHP-FPM juntos

O upload do tema ou do vídeo morre com 413 e o php.ini não resolve? Quem corta é o nginx:…

3 dias atrás

Apagar dados do cliente no WooCommerce sem perder o histórico do pedido

O cliente pediu exclusão pela LGPD mas a nota fiscal precisa ficar guardada. A saída é anonimizar o pedido, não…

4 dias atrás