Core Web Vitals
Audit HTML for patterns that negatively impact Core Web Vitals — the performance metrics Google uses as a ranking signal.
Overview
| Metric | Full name | Good threshold | What it measures |
|---|---|---|---|
| LCP | Largest Contentful Paint | ≤ 2.5s | Loading — time until the largest visible element renders |
| CLS | Cumulative Layout Shift | ≤ 0.1 | Visual stability — unexpected layout movement |
| INP | Interaction to Next Paint | ≤ 200ms | Responsiveness — delay between user input and visual update |
1. LCP (Largest Contentful Paint) checks
Identify the likely LCP element and check for blockers:
Identify LCP candidate
The LCP element is typically the largest visible element above the fold:
- Hero image (
<img>near top of<body>) - Hero background image (CSS
background-image) - Large heading (
<h1>) with significant text - Video poster image
LCP blockers to flag
| Check | Status |
|---|---|
Hero/banner <img> missing fetchpriority="high" |
⚠️ WARN "Add fetchpriority=high to LCP image" |
Hero image uses loading="lazy" |
❌ FAIL "Never lazy-load the LCP element" |
LCP image not preloaded (<link rel="preload" as="image">) |
⚠️ WARN "Preload LCP image for faster rendering" |
Render-blocking CSS in <head> (stylesheets without media attribute) |
⚠️ WARN |
Render-blocking JS in <head> (scripts without async/defer) |
⚠️ WARN |
| LCP image served in legacy format (JPG/PNG instead of WebP/AVIF) | ⚠️ WARN |
| No render-blocking resources | ✅ PASS |
Font loading
| Check | Status |
|---|---|
Custom fonts without <link rel="preload" as="font"> |
⚠️ WARN "Preload critical fonts" |
No font-display: swap or font-display: optional in @font-face |
⚠️ WARN "Add font-display to prevent invisible text" |
| Fonts preloaded properly | ✅ PASS |
2. CLS (Cumulative Layout Shift) checks
Identify HTML patterns that cause layout shift:
| Check | Status |
|---|---|
<img> without width and height attributes |
❌ FAIL "Missing dimensions cause layout shift" |
<video> or <iframe> without width/height |
⚠️ WARN |
| Ads/embeds without reserved space (no explicit dimensions) | ⚠️ WARN "Reserve space for dynamic content" |
Web fonts causing FOIT (Flash of Invisible Text) — no font-display |
⚠️ WARN |
| Content injected above existing content (banners, cookie notices without reserved space) | ⚠️ WARN |
| All images have dimensions | ✅ PASS "No layout shift from images" |
CSS animation checks
| Check | Status |
|---|---|
Animations using top, left, width, height (trigger layout) |
⚠️ WARN "Use transform instead for animations" |
Animations using transform and opacity only |
✅ PASS "GPU-accelerated, no layout shift" |
3. INP (Interaction to Next Paint) checks
Identify patterns that block the main thread:
| Check | Status |
|---|---|
<script> tags without async or defer |
⚠️ WARN "Blocks main thread during parsing" |
Inline <script> with heavy computation (> 50 lines) |
⚠️ WARN "Move heavy JS to async external file" |
Event handlers in HTML attributes (onclick, onchange, etc.) |
⚠️ WARN "Use addEventListener instead for better performance" |
| Third-party scripts loaded synchronously | ⚠️ WARN "Load third-party scripts with async" |
| All scripts properly deferred/async | ✅ PASS |
Third-party impact
Count third-party scripts (different domain):
- 0–3 → ✅ PASS
- 4–8 → ⚠️ WARN "Consider reducing third-party scripts"
- 9+ → ❌ FAIL "Excessive third-party scripts severely impact INP"
4. General performance patterns
| Check | Status |
|---|---|
<link rel="preconnect"> for third-party origins |
✅ PASS if present, ⚠️ WARN if missing with 3rd-party resources |
<link rel="dns-prefetch"> for third-party origins |
✅ PASS if present |
<link rel="preload"> for critical resources |
✅ PASS if present |
| Excessive DOM size (> 1500 elements) | ⚠️ WARN "Large DOM slows rendering" |
<meta name="viewport"> with width=device-width |
Required for mobile CWV (see mobile-optimization for full viewport checks) |
Reporting format
Core Web Vitals Audit
─────────────────────
LCP Risk Factors: X issues found
CLS Risk Factors: Y issues found
INP Risk Factors: Z issues found
Overall CWV Risk: LOW / MEDIUM / HIGH
- 0 issues → LOW risk
- 1–3 issues → MEDIUM risk
- 4+ issues → HIGH risk
Edge cases
- This skill audits HTML patterns that correlate with CWV issues — actual CWV scores require real-browser measurement (Lighthouse, CrUX data)
- Next.js automatically handles image optimization, code splitting, and font loading — check for Next.js-specific patterns before flagging generic issues
- Inline
<style>for critical CSS is intentional and should NOT be flagged as a CLS risk — distinguish from injected layout-shifting styles <script type="module">is inherently deferred — do not flag as render-blocking- Third-party scripts loaded inside
<iframe>do not block the main thread — exclude from INP third-party count - AMP pages have their own performance model — flag CWV patterns but note that AMP runtime handles many optimizations automatically