📊 O que são Core Web Vitals?
Core Web Vitals são métricas essenciais definidas pelo Google para medir a experiência do usuário em websites. Elas impactam diretamente o SEO e o ranking do site nos resultados de busca.
🎯 As 3 Métricas Principais
1️⃣ LCP - Largest Contentful Paint
(Maior Renderização de Conteúdo)
O que mede: Tempo para carregar o maior elemento visível na tela
Metas de Performance:
- 🟢 < 2.5s - Bom
- 🟡 2.5-4s - Precisa melhorar
- 🔴 > 4s - Ruim
Elementos comuns: Imagens hero, banners, blocos de texto grandes
Exemplo de otimização LCP
<!-- ❌ Ruim: Imagem sem otimização -->
<img src="banner-grande.jpg" alt="Banner">
<!-- ✅ Bom: Imagem otimizada com loading priority -->
<img src="banner-otimizado.webp"
alt="Banner"
loading="eager"
fetchpriority="high"
width="1200"
height="600">
2️⃣ FID - First Input Delay
(Atraso da Primeira Interação)
O que mede: Tempo entre a primeira interação do usuário e a resposta do navegador
Metas de Performance:
- 🟢 < 100ms - Bom
- 🟡 100-300ms - Precisa melhorar
- 🔴 > 300ms - Ruim
Eventos comuns: Cliques em botões, links, inputs
Exemplo de otimização FID
// ❌ Ruim: Código pesado bloqueando thread principal
ngOnInit() {
this.processarDadosPesados(); // Bloqueia interações
}
// ✅ Bom: Adiar processamento pesado
ngOnInit() {
setTimeout(() => {
this.processarDadosPesados();
}, 0); // Permite interações imediatas
}
3️⃣ CLS - Cumulative Layout Shift
(Mudança Cumulativa de Layout)
O que mede: Instabilidade visual durante o carregamento
Metas de Performance:
- 🟢 < 0.1 - Bom
- 🟡 0.1-0.25 - Precisa melhorar
- 🔴 > 0.25 - Ruim
Causas comuns: Imagens sem dimensões, anúncios, fontes web, animações
⚠️ Este será o foco principal deste artigo!
🔍 Caso Real: Otimizando CLS de 0.27 para < 0.1
🚨 O Problema
Ao analisar meu portfólio com Vercel Speed Insights, identifiquei um CLS de 0.27 - classificado como RUIM 🔴.
Elementos causando Layout Shifts:
-
button.lang-btn- Botão de idioma com transform scale -
div.hero-stats- Cards de estatística sem dimensões fixas -
section.explore-section- Seção sem altura reservada -
nav.nav- Menu com transitions em "all" -
div.explore-column- Colunas sem altura mínima
💡 6 Técnicas de Otimização Aplicadas
✅ 1. Reservar Espaço com Min-Height
O Problema: Elementos dinâmicos sem altura definida causam "pulos" quando o conteúdo carrega.
Ver código antes/depois
// ❌ Antes: Elemento sem altura definida
.hero-stats {
display: grid;
gap: 1rem;
}
// ✅ Depois: Espaço reservado antes do conteúdo
.hero-stats {
display: grid;
gap: 1rem;
min-height: 100px; // ← Reserva espaço
contain: layout; // ← Isola o elemento
}
Impacto: Elimina shift de 0.15 em cards de estatísticas.
✅ 2. Evitar Transform Scale em Estados Ativos
O Problema: transform: scale() altera dimensões físicas, causando reflow.
Ver código antes/depois
/* ❌ Antes: Scale causa layout shift */
.lang-btn {
transform: scale(0.9);
transition: all 0.3s ease;
}
.lang-btn.active {
transform: scale(1); /* ← CAUSA SHIFT! */
}
/* ✅ Depois: Apenas opacity e background */
.lang-btn {
width: 48px;
height: 36px; /* ← Dimensões fixas */
transition: opacity 0.2s ease, background-color 0.2s ease;
opacity: 0.5;
transform: translateZ(0); /* ← GPU acceleration */
}
.lang-btn.active {
opacity: 1; /* ← Sem mudança de tamanho */
background: rgba(59, 214, 113, 0.1);
}
Impacto: Reduz shift de 0.08 ao trocar idiomas.
✅ 3. CSS Containment para Isolar Elementos
O Problema: Mudanças em um elemento podem afetar elementos vizinhos.
// ✅ Isola renderização do elemento
.stat-card {
min-height: 80px;
contain: layout style; // ← Mudanças não afetam vizinhos
will-change: transform; // ← Otimiza animação
}
.explore-column {
min-height: 400px;
contain: layout style;
}
💡 Dica: Use
contain: layout styleem cards, modais e componentes isolados.
✅ 4. Otimizar Transitions - Evitar "all"
O Problema: transition: all anima propriedades desnecessárias.
/* ❌ Antes: Transition em todas propriedades */
.nav-link {
transition: all 0.2s ease; /* ← Pesado */
}
/* ✅ Depois: Apenas propriedades necessárias */
.nav-link {
transition: color 0.2s ease, background-color 0.2s ease;
contain: layout style;
}
✅ 5. GPU Acceleration com TranslateZ
O Problema: Animações em CPU causam jank e shifts.
// ✅ Força renderização em GPU (mais suave)
.hero-stats,
.explore-section,
.app-header {
transform: translateZ(0); // ← GPU layer
will-change: opacity; // ← Informa mudanças futuras
}
✅ 6. Dimensões Fixas em Imagens e Cards
O Problema: Imagens sem dimensões expandem quando carregam.
// ✅ Previne shift quando imagens carregam
.post-image {
height: 140px; // ← Altura fixa
contain: layout style;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.post-card {
min-height: 300px; // ← Altura mínima garantida
contain: layout style;
}
📈 Resultados Obtidos
Antes das Otimizações ❌
CLS Score: 0.2709 (RUIM)
Performance: 65/100
Elementos problemáticos: 5
Depois das Otimizações ✅
CLS Score: < 0.1 (BOM)
Performance: 90/100
Elementos problemáticos: 0
Impactos Medidos
- ⚡ Performance Score: +25 pontos
- 🚀 Tempo de Interatividade: -40%
- 👤 Experiência do Usuário: Sem "pulos" visuais
- 📊 SEO: Melhor ranking potencial
📋 Checklist de Otimização CLS
Imagens e Media
- [ ] Sempre definir
widtheheightem imagens - [ ] Usar
aspect-ratioem containers de imagem - [ ] Adicionar dimensões em
<video>e<iframe> - [ ] Pré-carregar imagens críticas com
<link rel="preload">
Fontes Web
- [ ] Usar
font-display: swapouoptional - [ ] Pré-carregar fontes críticas
- [ ] Definir fallback fonts com métricas similares
Conteúdo Dinâmico
- [ ] Reservar espaço com
min-heightantes de carregar dados - [ ] Usar skeleton screens durante loading
- [ ] Evitar injetar conteúdo acima do conteúdo existente
Animações e Transitions
- [ ] Evitar
transition: all - [ ] Não animar
width,height,top,left - [ ] Preferir
transformeopacity(composited properties) - [ ] Usar
will-changecom moderação
CSS Containment
- [ ] Aplicar
contain: layout styleem componentes isolados - [ ] Usar em cards, modais, sidebars
- [ ] Combinar com
transform: translateZ(0)para GPU
🛠️ Ferramentas de Medição
1. Vercel Speed Insights
(Usado neste projeto)
import { injectSpeedInsights } from '@vercel/speed-insights';
export class AppComponent {
ngOnInit() {
injectSpeedInsights(); // ← Coleta métricas reais
}
}
2. Google Lighthouse
# Via CLI
npm install -g lighthouse
lighthouse <<seu-site> --view
3. PageSpeed Insights
- 🔗 [pagespeed.web.dev]
- Analisa mobile e desktop
- Fornece sugestões específicas
4. Web Vitals Extension
- Extensão Chrome oficial
- Métricas em tempo real
💡 Boas Práticas Resumidas
1. Sempre Reserve Espaço
.dynamic-content {
min-height: 300px; // Evita shift quando dados chegam
contain: layout;
}
2. Prefira Composited Properties
// ✅ Bom: Renderizado em GPU
.animado {
transition: transform 0.3s, opacity 0.3s;
}
// ❌ Ruim: Causa reflow
.animado {
transition: width 0.3s, height 0.3s;
}
3. Use Will-Change com Moderação
// ✅ Apenas em elementos que animam
.hover-card {
will-change: transform;
}
// ❌ Não use globalmente
* {
will-change: transform; /* Consome memória! */
}
🔄 Monitoramento Contínuo
Budget de Performance no Angular
// angular.json
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "15kb",
"maximumError": "20kb"
}
]
CI/CD Integration
# GitHub Actions
- name: Lighthouse CI
run: |
npm install -g @lhci/cli
lhci autorun --assert.assertions.cumulative-layout-shift=0.1
🎯 Conclusão
Otimizar CLS não é apenas sobre performance técnica - é sobre respeitar o usuário. Quando elementos não "pulam" durante o carregamento, criamos uma experiência mais profissional e confiável.
Key Takeaways
✅ Dimensões fixas previnem surpresas visuais
✅ CSS containment isola componentes
✅ GPU acceleration suaviza animações
✅ Transitions específicas economizam recursos
Resultado: Site mais rápido, usuários mais felizes, melhor SEO. 🚀
💬 Você já otimizou CLS no seu projeto? Compartilhe sua experiência nos comentários!


Top comments (0)