$npx -y skills add dembrandt/dembrandt-skills --skill performance-and-web-vitalsAudit UI performance with Lighthouse and fix Core Web Vitals — LCP, CLS, INP. Fast UI is good UX. Use when optimising page load, fixing layout shift, reducing input delay, improving Lighthouse scores, or reviewing images, fonts, and render-blocking resources.
| 1 | # Performance and Web Vitals |
| 2 | |
| 3 | ## Run a Lighthouse Audit |
| 4 | |
| 5 | ```bash |
| 6 | # CLI audit — outputs JSON and HTML report |
| 7 | npx lighthouse https://example.com --output html --output-path ./lighthouse-report.html |
| 8 | |
| 9 | # Headless, useful in CI |
| 10 | npx lighthouse https://example.com --chrome-flags="--headless" --output json --output-path ./report.json |
| 11 | |
| 12 | # Audit specific categories only |
| 13 | npx lighthouse https://example.com --only-categories=performance,accessibility,seo |
| 14 | ``` |
| 15 | |
| 16 | Or open Chrome DevTools → Lighthouse tab → Analyse page load. |
| 17 | |
| 18 | **Target scores:** |
| 19 | | Category | Target | |
| 20 | |---|---| |
| 21 | | Performance | ≥ 90 | |
| 22 | | Accessibility | 100 | |
| 23 | | Best Practices | ≥ 95 | |
| 24 | | SEO | ≥ 95 | |
| 25 | |
| 26 | --- |
| 27 | |
| 28 | ## Core Web Vitals |
| 29 | |
| 30 | ### LCP — Largest Contentful Paint |
| 31 | *How fast does the main content appear?* |
| 32 | |
| 33 | **Target: ≤ 2.5s** |
| 34 | |
| 35 | LCP measures when the largest visible element (hero image, heading, video poster) renders. It is the user's perception of "did the page load?" |
| 36 | |
| 37 | **Common causes and fixes:** |
| 38 | |
| 39 | | Cause | Fix | |
| 40 | |---|---| |
| 41 | | Unoptimised hero image | Use WebP/AVIF, correct size, `fetchpriority="high"` | |
| 42 | | Image not preloaded | `<link rel="preload" as="image" href="hero.webp">` | |
| 43 | | Render-blocking CSS/JS | Defer non-critical JS, inline critical CSS | |
| 44 | | Slow server response | CDN, caching headers, edge delivery | |
| 45 | | Web font blocking render | `font-display: swap` or `optional` | |
| 46 | |
| 47 | ```html |
| 48 | <!-- Preload LCP image --> |
| 49 | <link rel="preload" as="image" href="hero.webp" fetchpriority="high"> |
| 50 | |
| 51 | <!-- LCP image: no lazy loading --> |
| 52 | <img src="hero.webp" alt="..." fetchpriority="high" width="1200" height="600"> |
| 53 | ``` |
| 54 | |
| 55 | Never use `loading="lazy"` on the LCP image — it delays the most important render. |
| 56 | |
| 57 | --- |
| 58 | |
| 59 | ### CLS — Cumulative Layout Shift |
| 60 | *Does content jump around while loading?* |
| 61 | |
| 62 | **Target: ≤ 0.1** |
| 63 | |
| 64 | CLS measures unexpected layout shifts — content moving after it has rendered. Caused by images without dimensions, late-loading ads, fonts swapping, or dynamic content injected above existing content. |
| 65 | |
| 66 | **Common causes and fixes:** |
| 67 | |
| 68 | | Cause | Fix | |
| 69 | |---|---| |
| 70 | | Images without width/height | Always set `width` and `height` on `<img>` | |
| 71 | | Web font swap | Use `font-display: optional` or preload fonts | |
| 72 | | Dynamic content above fold | Reserve space with `min-height` on containers | |
| 73 | | Late-loading ads or embeds | Reserve fixed dimensions for ad slots | |
| 74 | | Animations that shift layout | Animate `transform` only, never `top/left/width/height` | |
| 75 | |
| 76 | ```html |
| 77 | <!-- Always include dimensions --> |
| 78 | <img src="product.jpg" width="400" height="300" alt="..."> |
| 79 | ``` |
| 80 | |
| 81 | ```css |
| 82 | /* Reserve space for dynamic content */ |
| 83 | .ad-slot { min-height: 250px; } |
| 84 | |
| 85 | /* Animate transform, not layout properties */ |
| 86 | .slide-in { transform: translateY(0); transition: transform 300ms; } |
| 87 | ``` |
| 88 | |
| 89 | --- |
| 90 | |
| 91 | ### INP — Interaction to Next Paint |
| 92 | *How quickly does the page respond to user input?* |
| 93 | |
| 94 | **Target: ≤ 200ms** |
| 95 | |
| 96 | INP measures the delay between a user interaction (click, tap, keyboard) and the next visual update. High INP makes the UI feel sluggish or frozen. |
| 97 | |
| 98 | **Common causes and fixes:** |
| 99 | |
| 100 | | Cause | Fix | |
| 101 | |---|---| |
| 102 | | Heavy JS on main thread | Break into smaller tasks, use `requestIdleCallback` | |
| 103 | | Large event handlers | Debounce/throttle scroll and resize handlers | |
| 104 | | Synchronous DOM updates | Batch DOM writes with `requestAnimationFrame` | |
| 105 | | Third-party scripts blocking | Load third-party scripts with `async` or `defer` | |
| 106 | | React re-renders | Memoize with `useMemo`, `useCallback`, `React.memo` | |
| 107 | |
| 108 | --- |
| 109 | |
| 110 | ## Images |
| 111 | |
| 112 | Images are the single biggest performance lever on most pages. |
| 113 | |
| 114 | ```html |
| 115 | <!-- Modern formats with fallback --> |
| 116 | <picture> |
| 117 | <source srcset="image.avif" type="image/avif"> |
| 118 | <source srcset="image.webp" type="image/webp"> |
| 119 | <img src="image.jpg" width="800" hei |