Core Web Vitals became a Google ranking signal in 2021. Since then we've run performance audits and optimization sprints on more sites than I can count. The patterns are consistent: a small number of root causes account for most failures, and fixing them in the right order creates compounding improvements.
Largest Contentful Paint (LCP): what actually causes it
LCP measures how long it takes for the largest content element in the viewport to load and render. The most common culprits, in our experience:
Render-blocking resources
CSS loaded in the <head> blocks rendering until it's fully parsed. JavaScript with no async or defer attribute blocks the HTML parser. These are table-stakes fixes. Audit your critical rendering path with Chrome DevTools' Coverage tab — you'll often find 60-80% of your CSS is unused on any given page.
Unoptimized hero images
The hero image is almost always the LCP element. Best practice: serve it as WebP or AVIF, use width and height attributes to prevent layout shift, and add fetchpriority="high" to the image tag. Do not lazy-load it. The browser's preload scanner needs to discover it early.
Slow server response
Time to First Byte (TTFB) directly caps your LCP. If your server takes 800ms to respond, your LCP cannot be below 800ms regardless of how well-optimized the page is. For Drupal sites, this typically means: enable page caching, use Redis for the database cache, and consider a reverse proxy cache (Varnish or Cloudflare's caching) in front of the application.
Cumulative Layout Shift (CLS): the invisible tax
CLS penalizes visual instability — elements jumping around as the page loads. The three most common causes:
- Images without explicit width/height attributes — the browser doesn't know how much space to reserve
- Ads and embeds that inject content after page load
- Web fonts causing a flash of unstyled text, then a layout reflow when the real font loads
The fix for images is simple: always set width and height. Use aspect-ratio CSS to let images be responsive while still reserving space. For fonts, use font-display: optional if you can live without a fallback rendering, or font-display: swap with careful fallback font metrics tuning.
Interaction to Next Paint (INP): the new metric
INP replaced First Input Delay as a Core Web Vitals metric in 2024. It measures the latency of all interactions throughout the page lifecycle, not just the first one. A poor INP score usually means too much JavaScript executing on the main thread in response to user input.
The most effective fix is code splitting: defer loading JavaScript that isn't needed for initial interactivity. For Drupal, this means auditing your aggregated JS bundles — many contributed modules load JavaScript on every page even when the module's functionality isn't present on that page.
Our optimization checklist (in priority order)
- Enable full page caching (Drupal's internal cache + Redis)
- Serve images as WebP/AVIF, with correct dimensions and fetchpriority on the hero
- Defer or remove non-critical JavaScript
- Inline critical CSS, defer the rest
- Add explicit dimensions to all images
- Use a CDN for static assets
- Preconnect to third-party origins (fonts, analytics)
- Audit and remove unused CSS
A typical Drupal site goes from a Lighthouse performance score of 45-60 to 85-95 within a focused two-week optimization sprint when we follow this checklist in order. The SEO impact is measurable within 60-90 days.
Contact us if you'd like us to run a performance audit on your site.