Como levei um blog em PHP puro de 84 para 97 no PageSpeed (e a acessibilidade para 100)
CONTEÚDO (cole no editor, em Markdown):
Tenho um blog em PHP 8 + MySQL + Bootstrap 5, sem framework, em cPanel atrás do Cloudflare. O PageSpeed no celular:
| Métrica | Antes | Depois |
|---|---|---|
| Desempenho (home) | 84 | 97 |
| Acessibilidade | 90 | 100 |
| CLS | 0,083 | 0 |
| Requisições bloqueando a renderização | 1.650 ms | nenhuma |
Sem reescrever o site, só ajustes pontuais. Serve para qualquer site PHP com Bootstrap.
1. O Bootstrap inteiro era o maior vilão
O bootstrap.min.css tem cerca de 230 KB, e mais de 90% não era usado. E vinha de outro domínio (jsDelivr), somando DNS + TLS antes da primeira pintura.
O que fiz:
- Baixei o Bootstrap para o próprio domínio.
- Rodei o PurgeCSS sobre os arquivos PHP para gerar só as classes usadas:
npx purgecss --css assets/vendor/bootstrap.min.css \
--content "*.php" "templates/*.php" \
--output assets/vendor/purged \
--safelist show collapsing collapse fade active
- Resultado: 230 KB → 37 KB. Pequeno o suficiente para ir inline no
<head>, eliminando a requisição bloqueante:
<?php $css = __DIR__ . '/../assets/vendor/purged/bootstrap.min.css'; ?>
<?php if (is_file($css)): ?>
<style><?= file_get_contents($css) ?></style>
<?php else: ?>
<link rel="stylesheet" href="/assets/vendor/bootstrap.min.css">
<?php endif; ?>
O else garante que o site nunca fica sem estilo.
Cuidados:
- A
safelistprecisa das classes adicionadas pelo JavaScript do Bootstrap e das que vêm do conteúdo no banco. O PurgeCSS só enxerga os arquivos. - No Windows, o PurgeCSS 8 não carregou o config (
Received protocol 'c:'). A linha de comando resolveu. - Toda classe nova num PHP exige rodar o PurgeCSS de novo.
2. Fontes e ícones fora do caminho crítico
Google Fonts e Bootstrap Icons passaram a carregar de forma assíncrona:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap"
media="print" onload="this.media='all'">
3. CLS zerado com fonte substituta de métricas ajustadas
A troca de fonte fazia o texto "pular". Solução: fallback com as métricas da Inter:
@font-face {
font-family: "Inter Fallback";
src: local("Arial");
size-adjust: 107.12%;
ascent-override: 90.44%;
descent-override: 22.52%;
line-gap-override: 0%;
}
body { font-family: "Inter", "Inter Fallback", system-ui, sans-serif; }
Somando width/height nas imagens, o CLS foi de 0,083 para 0.
4. LCP
Preload da capa com fetchpriority="high" e media para celular e desktop.
5. Acessibilidade: quase tudo era contraste
Quase tudo era cor que parecia ok a olho nu:
- O vermelho da marca (
#e63946) dava 4,2:1 sobre branco. O mínimo é 4,5:1. Troquei por#d62839, visualmente quase igual. - O azul de link do Bootstrap (
#0d6efd) dava 4,3:1 sobre#f8f9fa. Três variáveis resolveram:
:root {
--bs-link-color: #0a58ca;
--bs-link-color-rgb: 10, 88, 202;
--bs-link-hover-color-rgb: 8, 66, 152;
}
text-muteddo Bootstrap 5.3 sobre fundo escuro (rodapé) fica quase invisível.- O resto:
<label>em campos só com placeholder,aria-labelem botões de ícone e ordem dos títulos.
6. Cache: o .htaccess não estava valendo
O PageSpeed mostrava 4 horas de cache no JS, o padrão do Cloudflare: o servidor não enviava o cabeçalho. Resolvi com uma Cache Rule no Cloudflare por extensão, com Browser TTL de 1 ano.
O que aprendi
- Medir antes de mexer. Os insights do Lighthouse valem mais que a nota.
- O maior ganho foi o CSS, não imagens nem JavaScript.
- Acessibilidade é, em grande parte, contraste. Vale testar as cores da marca logo no começo do projeto.
- Rode o PageSpeed 2 ou 3 vezes. A variação entre execuções é grande.
Alguém já usou PurgeCSS com conteúdo vindo do banco? Como resolveram a safelist?
Fonte: https://bizflowcraft.com