De ce contează
Core Web Vitals sunt semnale de calitate: viteza percepută, stabilitatea layout-ului și cât de “responsive” e site-ul la interacțiuni. În Next.js poți obține rezultate foarte bune, dar doar dacă optimizezi corect: nu doar scor Lighthouse, ci viteza reală pe mobil.
Indicatori principali:
- LCP: cât de repede apare conținutul principal (de obicei imagine/hero/text mare)
- CLS: cât de mult “saltă” pagina
- INP: cât de repede răspunde site-ul la click/tap
1) Începe cu măsurarea corectă
Nu începe cu “hai să minificăm CSS”. Începe cu:
- Lighthouse (debug local, rapid)
- Real User Monitoring (RUM) dacă ai (cel mai bun)
- PageSpeed Insights pentru trenduri (ok ca semnal, nu ca adevăr absolut)
Checklist minim de măsurare:
- 3 pagini critice: Home, categorie/listare, produs/checkout
- test pe mobil, nu doar desktop
- notează LCP elementul (ce e exact) și sursa CLS (ce componentă saltă)
2) Fixează LCP
A) Imaginea din hero / produs
În Next.js, folosește next/image și fă imaginea above the fold prioritară.
Reguli simple:
- set
prioritydoar pentru imaginea principală - definește
width/height(saufill+ container stabil) - folosește
sizescorect pentru responsive
Exemplu:
import Image from "next/image";
export function HeroImage() {
return (
<div style={{ position: "relative", width: "100%", height: 420 }}>
<Image
src="/hero.webp"
alt="..."
fill
priority
sizes="(max-width: 768px) 100vw, 1200px"
style={{ objectFit: "cover" }}
/>
</div>
);
}
B) Server response / caching
LCP moare dacă:
- faci fetch-uri lente fără caching
- ai logică grea în request (SSR) fără reason
Reguli:
- cache pe datele care nu se schimbă la fiecare secundă
- evită SSR la pagini de marketing dacă poți (SSG/ISR)
- controlezi caching cu
next: { revalidate: ... }
C) Fonturi
Fonturile mari + încărcare blocantă = LCP slab.
Reguli:
- folosește
next/font - evită 10 greutăți (2 sunt suficiente)
3) Fixează CLS
CLS apare când UI își schimbă mărimea după ce pagina a început să se afișeze.
Cauze clasice:
- imagini fără dimensiuni fixe
- bannere care apar după load și împing conținutul
- font swap fără fallback bun
- componente care injectează conținut (cookie banner, modale)
Fixuri rapide:
- rezervă spațiu pentru imagini
- cookie banner ca overlay (fără push)
- skeletons cu dimensiuni reale
4) Fixează INP
INP scade când:
- ai prea mult JS în bundle
- ai handler-e grele la click/scroll
- ai re-render-uri masive
Reguli practice:
- dynamic import pentru componente grele
- mută logică în Server Components unde se poate
- evită librării grele pentru lucruri simple
Exemplu:
import dynamic from "next/dynamic";
const HeavyChart = dynamic(() => import("./HeavyChart"), { ssr: false });
export function Dashboard() {
return (
<section>
<h2>Raport</h2>
<HeavyChart />
</section>
);
}
Optimizări React simple:
- folosește
useMemo/useCallbackdoar când chiar previi re-render - evită state global care re-render‑uiește tot
- debouncing la input‑uri care fac query/search
5) Quick wins care aduc rezultate reale
- Hero image:
priority+sizes+ format webp/avif - Reduce font weights la 2
- Elimină scripturi inutile (analytics multiple, chat, heatmaps)
- Code split pentru componente rare (carusele, hărți)
- Cache pentru date stabile (ISR / revalidate)
Checklist final
LCP
- elementul LCP identificat
- imaginea principală are
priority+sizes - fonturi optimizate (
next/font) - caching pentru fetch‑uri lente
CLS
- imagini cu dimensiuni rezervate
- bannere fără push (overlay sau spațiu rezervat)
- componente dinamice cu skeleton stabil
INP
- bundle redus (dynamic import)
- re-render‑uri limitate
- handler‑e optimizate (debounce, fără heavy work pe main thread)