Performance Optimization
Optimize frontend performance for Core Web Vitals — LCP, CLS, and INP — with image optimization, CSS/JS strategies, and AI-powered performance analysis.
Premium Course Content
This lesson is part of a premium course. Upgrade to Pro to unlock all premium courses and content.
- Access all premium courses
- 1000+ AI skill templates included
- New content added weekly
🔄 Recall Bridge: In the previous lesson, you learned accessibility — WCAG guidelines, keyboard navigation, ARIA, and contrast requirements. Now let’s make your accessible, responsive pages load fast on any connection.
Core Web Vitals are Google’s metrics for user experience, and they directly affect search rankings. A page that’s beautiful and accessible but takes 5 seconds to load on mobile will rank lower and lose users. Performance optimization is the final pillar of production-quality frontend code.
Core Web Vitals
| Metric | Measures | Good | Needs Work | Poor |
|---|---|---|---|---|
| LCP (Largest Contentful Paint) | Loading speed | < 2.5s | 2.5-4s | > 4s |
| CLS (Cumulative Layout Shift) | Visual stability | < 0.1 | 0.1-0.25 | > 0.25 |
| INP (Interaction to Next Paint) | Responsiveness | < 200ms | 200-500ms | > 500ms |
Optimizing LCP (Loading Speed)
The LCP element is usually a hero image, heading, or large text block.
Optimization strategies by impact:
| Strategy | Impact | Implementation |
|---|---|---|
| Preload LCP image | High | <link rel="preload" as="image" href="hero.webp"> |
| Inline critical CSS | High | Above-fold styles in <style> in <head> |
| fetchpriority | Medium | <img fetchpriority="high"> on LCP element |
| Responsive images | High | srcset + WebP format (covered in Lesson 5) |
| Font optimization | Medium | font-display: swap + preload font files |
| Remove render-blocking JS | High | defer or async on script tags |
AI prompt for LCP analysis:
My page’s LCP is 4.2 seconds. The LCP element is [DESCRIBE — hero image, heading, etc.]. Here’s my
<head>section: [PASTE]. Suggest specific optimizations to get LCP under 2.5 seconds, ordered by impact. Show the exact code changes.
Preventing CLS (Layout Shift)
Layout shifts happen when elements change size or position after the initial render.
Common CLS causes and fixes:
| Cause | Fix |
|---|---|
| Images without dimensions | Always set width and height attributes |
| Web fonts loading | font-display: swap + size-adjust |
| Dynamic content injection | Pre-allocate space with CSS min-height |
| Ads without reserved space | Fixed-dimension ad containers |
| Late-loading CSS | Inline critical CSS in <head> |
CSS for preventing image CLS:
img {
max-width: 100%;
height: auto;
/* Browser reserves space from width/height attributes */
}
AI prompt for CLS debugging:
My page has a CLS score of 0.28. I’ve identified these elements that shift: [LIST]. For each, suggest how to pre-allocate space or prevent the shift. Show CSS and HTML changes.
Optimizing INP (Responsiveness)
INP measures how quickly the page responds to user interactions (clicks, taps, key presses).
Strategies:
| Strategy | Implementation |
|---|---|
| Break long tasks | Use requestIdleCallback or setTimeout(fn, 0) to yield to the browser |
| Debounce input handlers | Don’t run expensive operations on every keystroke |
| Use CSS for animations | CSS transitions/animations run on the compositor thread (don’t block main thread) |
| Web Workers | Move heavy computation off the main thread |
| Virtualize long lists | Only render visible items, not 10,000 DOM nodes |
JavaScript Loading Strategy
| Loading Method | When to Use | Syntax |
|---|---|---|
| Default (blocking) | Almost never | <script src="app.js"> |
| defer | Most scripts | <script defer src="app.js"> |
| async | Independent scripts (analytics) | <script async src="analytics.js"> |
| Dynamic import | Below-fold features | const mod = await import('./gallery.js') |
| Lazy (IntersectionObserver) | Below-fold content/images | Load when element enters viewport |
✅ Quick Check: You add
loading="lazy"to your hero image to improve performance. After deploying, your LCP gets WORSE. Why? (Answer:loading="lazy"tells the browser to delay loading until the element is near the viewport. For the hero image (which IS the viewport on load), this actually delays the load by adding an intersection observer check. Only useloading="lazy"for below-fold images. Above-fold images should usefetchpriority="high"and<link rel="preload">to load as fast as possible.)
Performance Testing Tools
| Tool | What It Measures | When to Use |
|---|---|---|
| Lighthouse (Chrome DevTools) | LCP, CLS, INP, accessibility | During development |
| PageSpeed Insights | Real-world + lab metrics | Before and after deployment |
| WebPageTest | Detailed waterfall analysis | Diagnosing specific issues |
| Chrome DevTools Performance | JavaScript execution timing | Debugging INP |
Key Takeaways
- LCP optimization goes beyond image compression: preloading the LCP image, inlining critical CSS, using
fetchpriority="high", and deferring non-critical JavaScript can collectively cut 2-3 seconds off loading time by removing delays in the browser’s loading chain - Every element that changes size or position after initial render causes CLS: always set
widthandheighton images, pre-allocate space for dynamic content and ads with CSSmin-height, and usefont-display: swapfor web fonts — these prevent the layout shifts users find most jarring - Use
loading="lazy"only for below-fold content, never for the hero/LCP element: lazy loading adds an intersection observer delay that makes above-fold content load slower, whilefetchpriority="high"and<link rel="preload">make it load faster
Up Next
In the final lesson, you’ll bring everything together — building a complete, responsive, accessible, performant page as your capstone project, with a personalized frontend improvement plan.
Knowledge Check
Complete the quiz above first
Lesson completed!