DEV Community

Vinicius Fantinatto
Vinicius Fantinatto

Posted on

🚀 Guia Completo: Otimização de Performance Web com Core Web Vitals

📊 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">
Enter fullscreen mode Exit fullscreen mode


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
}
Enter fullscreen mode Exit fullscreen mode


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
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

💡 Dica: Use contain: layout style em 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;
}
Enter fullscreen mode Exit fullscreen mode

✅ 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
}
Enter fullscreen mode Exit fullscreen mode
// Teste de performance: CPU vs GPU const startCPU = performance.now(); // Animação em CPU document.querySelector('.cpu').style.marginLeft = '100px'; const endCPU = performance.now(); const startGPU = performance.now(); // Animação em GPU document.querySelector('.gpu').style.transform = 'translateX(100px)'; const endGPU = performance.now(); console.log(CPU: ${endCPU - startCPU}ms); console.log(GPU: ${endGPU - startGPU}ms);

✅ 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;
}
Enter fullscreen mode Exit fullscreen mode

📈 Resultados Obtidos

Antes das Otimizações ❌

CLS Score: 0.2709 (RUIM)
Performance: 65/100
Elementos problemáticos: 5
Enter fullscreen mode Exit fullscreen mode

Depois das Otimizações ✅

CLS Score: < 0.1 (BOM)
Performance: 90/100
Elementos problemáticos: 0
Enter fullscreen mode Exit fullscreen mode

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 width e height em imagens
  • [ ] Usar aspect-ratio em containers de imagem
  • [ ] Adicionar dimensões em <video> e <iframe>
  • [ ] Pré-carregar imagens críticas com <link rel="preload">

Fontes Web

  • [ ] Usar font-display: swap ou optional
  • [ ] Pré-carregar fontes críticas
  • [ ] Definir fallback fonts com métricas similares

Conteúdo Dinâmico

  • [ ] Reservar espaço com min-height antes 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 transform e opacity (composited properties)
  • [ ] Usar will-change com moderação

CSS Containment

  • [ ] Aplicar contain: layout style em 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
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Google Lighthouse

# Via CLI
npm install -g lighthouse
lighthouse <<seu-site> --view
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

2. Prefira Composited Properties

GPU Properties=transform+opacity \text{GPU Properties} = \text{transform} + \text{opacity}
// ✅ Bom: Renderizado em GPU
.animado {
  transition: transform 0.3s, opacity 0.3s;
}

// ❌ Ruim: Causa reflow
.animado {
  transition: width 0.3s, height 0.3s;
}
Enter fullscreen mode Exit fullscreen mode

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! */
}
Enter fullscreen mode Exit fullscreen mode

🔄 Monitoramento Contínuo

Budget de Performance no Angular

// angular.json
"budgets": [
  {
    "type": "anyComponentStyle",
    "maximumWarning": "15kb",
    "maximumError": "20kb"
  }
]
Enter fullscreen mode Exit fullscreen mode

CI/CD Integration

# GitHub Actions
- name: Lighthouse CI
  run: |
    npm install -g @lhci/cli
    lhci autorun --assert.assertions.cumulative-layout-shift=0.1
Enter fullscreen mode Exit fullscreen mode

🎯 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!

webperf #performance #css #frontend #webdev

Top comments (0)