Front-end · Senior

Web performance: Core Web Vitals, lazy loading and bundle size

Performance stopped being guesswork and became a measurable metric — even a ranking factor on Google. The Core Web Vitals are the industry standard for answering "is this site good to use?". Knowing what each one measures, why it gets worse and how to fix it is a central part of a senior's job.

The three metrics

The current Core Web Vitals measure three distinct experiences: how fast the main content appears, how stable the layout is and how responsive the site is to interaction.

MetricWhat it measures"Good" target
LCPTime until the largest visible element paints≤ 2.5 s
CLSHow much the layout "jumps" without warning≤ 0.1
INPLatency of the response to interactions≤ 200 ms

LCP: does the main content appear fast?

Largest Contentful Paint marks when the largest element (usually the hero image or a text block) is rendered. Common causes of bad LCP: slow server, CSS/JS blocking rendering, huge images. Fixes: prioritize the critical resource (fetchpriority="high"), use a CDN, compress images and avoid fonts that block text.

CLS: does the layout stay put?

Cumulative Layout Shift measures visual jumping — that moment when you go to click a button and an ad pushes everything down. The classic causes: images without reserved dimensions, fonts that change size when loading, content injected above what was already there. Fix: always reserve space (width/height or aspect-ratio on images).

<!-- Reserves space → no jump -->
<img src="foto.jpg" width="800" height="600" alt="...">

INP: does the site respond to touch?

Interaction to Next Paint measures how long it takes between the click and the screen responding. Bad INP is almost always heavy JavaScript blocking the main thread — which connects directly to rendering and the critical path. Fix: break up long tasks, defer non-urgent work and avoid expensive click handlers.

Loading less: splitting, lazy loading and images

The biggest performance lever is simply sending less code and fewer bytes:

  • Code splitting: split the bundle by route, loading only what's needed for the current screen.
  • Lazy loading: defer what's off-screen — loading="lazy" on images, dynamic import() for components.
  • Images: modern formats (WebP/AVIF), responsive sizes (srcset), compression.
// Loads the component only when it's used
const Grafico = lazy(() => import('./Grafico'));

Bundle analysis and perceived performance

A bundle analyzer shows what's fattening your package — often a heavy library imported in full for a single use. Cutting that usually yields more than any micro-optimization.

And then there's perceived performance: users feel speed, they don't measure milliseconds. Skeletons instead of spinners, showing partial content, instant feedback on click — it all makes the site feel faster even when the numbers are similar.

The optimization that pays off most is almost never making the code smarter — it's not shipping the code the user doesn't need right now.

Senior interviews commonly ask you to name the Core Web Vitals, their thresholds and how you'd attack a bad LCP. Day to day, it shows up when Lighthouse lights up red or the product team complains that "the site takes a while to show up".

Conclusion

LCP covers content appearing, CLS visual stability and INP responsiveness. The levers are almost always the same: send less (splitting, lazy loading, optimized images) and take care of perception. Performance is experience — and, with it and the architecture under control, what remains is protecting the user with security.

Read also

Back to track