DEV Community

Jaji
Jaji

Posted on • Edited on

Improving App Performance: Optimizing Core Web Vitals

This article is based on real-world experience optimizing web performance and the strategies discussed here can be adapted for various web applications facing similar challenges.

As a frontend engineer at an events intelligence AI platform, I faced a crucial challenge: improving the performance of our most visited page. This experience taught me valuable lessons about optimizing Core Web Vitals and enhancing user experience. Here's what I learned along the way.

Understanding Core Web Vitals: The Three Pillars

Before diving into specific optimizations, it's essential to understand what we're measuring. Core Web Vitals consist of three key metrics that Google uses to evaluate user experience:

1. Largest Contentful Paint (LCP): Measures loading performance

  • Good: ≤ 2.5 seconds
  • Needs Improvement: ≤ 4 seconds
  • Poor: > 4 seconds

2. First Input Delay (FID): Measures interactivity

  • Good: ≤ 100 milliseconds
  • Needs Improvement: ≤ 300 milliseconds
  • Poor: > 300 milliseconds

3. Cumulative Layout Shift (CLS): Measures visual stability

  • Good: ≤ 0.1
  • Needs Improvement: ≤ 0.25
  • Poor: > 0.25

Our Core Web Vitals report categorized URLs into these three status groups, helping us prioritize our optimization efforts.

Technical Deep Dive: Performance Optimizations

1. Font Loading Strategy

Implemented a comprehensive font loading strategy that included several technical optimizations:

<!-- Preload critical fonts -->
<link 
  rel="preload" 
  href="/fonts/primary-font.woff2" 
  as="font" 
  type="font/woff2" 
  crossorigin
/>
<!-- Font-face definitions with size-adjust -->
<style>
@font-face {
  font-family: 'Primary Font';
  font-display: optional;
  src: url('/fonts/primary-font.woff2') format('woff2');
  size-adjust: 97.5%; /* Matched to fallback font */
}
/* Fallback font metrics matching */
@font-face {
  font-family: 'Arial Fallback';
  src: local('Arial');
}
</style>
Enter fullscreen mode Exit fullscreen mode

2. Resource Optimization

Resource blocking is about controlling how and when your web page loads different resources (like scripts, stylesheets, images, fonts) to improve performance. The key idea is to block (delay) non-essential resources while prioritizing critical ones.

<!-- Only loads on mobile devices -->
<link rel="stylesheet" href="/mobile.css" media="screen and (max-width: 600px)">

<!-- async: Load in parallel, execute when ready -->
<script async src="/non-critical.js"></script>

<!-- defer: Load in parallel, execute after HTML parsing -->
<script defer src="/can-wait.js"></script>

<!-- Tell browser to preload critical resources -->
<link rel="preload" href="/critical-font.woff2" as="font" crossorigin>

<!-- Connect early to required origins -->
<link rel="preconnect" href="https://api.example.com">
Enter fullscreen mode Exit fullscreen mode
<!-- Load resource only when needed--> 
if (someCondition) {
  const script = document.createElement('script');
  script.src = '/feature.js';
  document.head.appendChild(script);
}
Enter fullscreen mode Exit fullscreen mode

Measurable Results

Here's how we improved each Core Web Vital and the specific optimizations that made it possible:

1. Largest Contentful Paint (LCP)

Before: 4.2s (Poor) → After: 2.1s (Good)

The dramatic improvement in LCP came from identifying and fixing several critical issues:

  • We discovered our hero image (1.2MB) was blocking the critical rendering path. By implementing responsive images and modern formats (WebP/AVIF), we reduced the image size by 70%.
  • Moving our web fonts to use font-display: optional prevented font-loading delays.
  • Implementing preload hints for critical assets helped prioritize important resources.

2. Cumulative Layout Shift (CLS)

Before: 0.28 (Poor) → After: 0.08 (Good)

The major reduction in layout shifts came from addressing three main culprits:

  • Font swapping was causing significant shifts. We fixed this by implementing font size-adjust and matching fallback fonts metrics.
  • Dynamic content loading (like attendee lists) was pushing content down. We implemented skeleton screens and reserved space for dynamic content.

3. First Input Delay (FID)

Before: 250ms (Needs Improvement) → After: 85ms (Good)

The improvement in interactivity came from:

  • Breaking up long-running JavaScript tasks that were blocking the main thread. We identified these using the Performance panel in Chrome DevTools.
  • Moving heavy computations (like filtering) to Web Workers.
  • Implementing proper event delegation instead of attaching hundreds of individual event listeners. e.g Use useCallback to memoize the event handler

Additional Critical Improvements

1. First Contentful Paint (FCP)

  • Improved from 2.8s to 1.4s
  • Achieved by inlining critical CSS and deferring non-critical styles
  • Implemented route-based code splitting to reduce initial JavaScript payload

2. Total Blocking Time (TBT)

  • Decreased from 600ms to 200ms
  • Achieved by deferring non-critical JavaScript execution
  • Implemented requestIdleCallback for non-essential operations

Key Technical Takeaways

1. Implement Resource Hints Strategically

  • Use preload for critical resources
  • Implement prefetch for resources needed later
  • Enable preconnect for third-party domains

2. Optimize Font Loading

  • Use size-adjust and metric overrides
  • Implement fallback font matching
  • Leverage font-display strategies

3. Monitor Performance Continuously

  • Use Performance Observer API
  • Track Core Web Vitals in real-time
  • Set up automated performance budgets

Looking Forward

Web performance optimization is an ongoing journey. We continue to monitor our Core Web Vitals and make adjustments as needed. The improvements we've made to our page have not only enhanced user experience but also contributed to better engagement metrics across the platform.

Top comments (0)