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

Criar swapfile no Ubuntu: parar o OOM killer de matar o MySQL

VPS de 2 GB onde o mysqld morre de madrugada e o site volta com erro de conexão. Como confirmar…

9 horas atrás

Grupos nomeados no preg_match: pare de contar índice de $matches

Regex com cinco parênteses e ninguém lembra se a data é $matches[2] ou $matches[3]. Nomeie os grupos e leia o…

23 horas atrás

Token de integração da API do Magento 2: gerar e usar no header Bearer

Erro The consumer isn't authorized to access resources ao chamar a REST do Magento 2.4.8? Ative a integração, libere os…

1 dia atrás

Rate limit no wp-login.php com nginx: barrar força bruta antes do PHP

Bots batendo centenas de POST por minuto no login derrubam a CPU. Configure limit_req_zone no nginx e devolva 429 antes…

2 dias atrás

Anonimizar IP no nginx: mascarar o último octeto do log para a LGPD

Seu access.log guarda o IP inteiro dos visitantes há meses sem necessidade. Mascare o último octeto com map e log_format…

3 dias atrás

Prompt injection em campo de usuário: isole a observação do pedido

A observação do pedido chegou com ordem embutida para gerar cupom. Delimite o texto do cliente e trate a resposta…

3 dias atrás