{"id":"wylrnr7glvebq4u","title":"Core Web Vitals Failing After a Redesign (First Fixes)","slug":"core-web-vitals-failing-after-redesign","summary":"We swapped the entire frontend stack for a new library and framework, only to have real-world performance metrics crash the moment we went live.  Synthetic…","imageUrl":"https://briancrabtree.me/images/journal-core-web-vitals-failing-after-redesign.webp","category":"Performance","date":"2026-01-29T18:00:00.000Z","featured":false,"likes":40,"author":"Brian Crabtree","content":"<h2>The cold truth after launch</h2>\n\n<p>We recently pushed live a significant site redesign, which involved a complete overhaul of our frontend architecture. This included a migration to a modern component library, a new JavaScript framework, and an updated build process, all with the underlying expectation of substantial performance improvements. There was a genuine sense of optimism that this refactor would deliver a snappier, more efficient user experience.</p>\n\n<p>However, that optimism quickly met reality once the real user monitoring (RUM) data started rolling in. The metrics painted a clear and concerning picture: our Core Web Vitals were demonstrably failing after the redesign. Specifically, Largest Contentful Paint (LCP) saw a significant increase, Cumulative Layout Shift (CLS) spiked dramatically, and First Input Delay (FID) — now often correlated with Interaction to Next Paint (INP) — showed measurable regression for a notable segment of our user base. It was a clear, unambiguous CWV drop immediately after launch, despite extensive pre-launch synthetic testing.</p>\n\n<p>This situation, while frustrating, isn't uncommon in the world of web development. You embark on a refactor with the best intentions for speed and efficiency, only to inadvertently introduce new, unforeseen bottlenecks. My initial reaction wasn't panic, but rather a structured approach to systematically identify what exactly had changed and where the new performance hurdles lay. This necessitated a deep dive beyond mere synthetic tests, focusing squarely on the true impact experienced by our actual users.</p>\n\n<pre><code>// After redesign — compare field vs lab\n// PSI field: CrUX p75 LCP / INP / CLS\n// Lab: Lighthouse on staging URL before cutover</code></pre>\n\n<p><figure>\n  <img src=\"/images/journal-inline-core-web-vitals-failing.webp\" alt=\"Before and after redesign Core Web Vitals scores with LCP CLS INP labels\" width=\"1200\" height=\"675\" loading=\"lazy\" />\n  <figcaption>Redesigns often regress LCP first — fix the hero element before chasing lab luck.</figcaption>\n</figure></p>\n\n<h2>Initial suspects in the performance lineup</h2>\n\n<p>When Core Web Vitals metrics take a hit, my diagnostic process always begins with a thorough examination of render-blocking resources. These are often the lowest-hanging fruit and the most impactful culprits. Common offenders include excessively large images, custom fonts loaded inefficiently, or JavaScript bundles that unnecessarily block the main thread during initial page render. Our redesign introduced an array of new assets and, crucially, new loading patterns, making these the prime suspects.</p>\n\n<p>For LCP, specifically, the hero section of the page is almost universally the first area I scrutinize. Is there a large background image being served without proper optimization, such as responsive `srcset` attributes or effective compression for different screen sizes? Did the introduction of a new web font delay text rendering, thus pushing back the LCP element? These seemingly minor details often get overlooked in the excitement of delivering new visual designs and complex component interactions.</p>\n\n<p>CLS regressions almost invariably point to elements within the page that lack explicit size constraints or are dynamically injected without reserving space. This could involve new third-party ad slots, user consent banners, or other dynamically loaded content. Images without explicit `width` and `height` attributes are classic culprits. Furthermore, I always check for Flash of Unstyled Text (FOUT) or Flash of Invisible Text (FOIT) issues stemming from new font loading strategies, as these can cause significant visual instability.</p>\n\n<h2>Largest Contentful Paint often breaks first</h2>\n\n<p>Our LCP regression was particularly stark and immediate. The visually appealing new hero banner image, while striking, was implemented as a single, large JPEG file loaded at full resolution for all screen sizes. There was no `srcset` for responsiveness, no intelligent `loading=\"lazy\"` attribute applied where appropriate below the fold, and certainly no consideration for modern, more efficient formats like WebP or AVIF by default. This meant a substantial, unoptimized asset was being fetched and rendered as a top-priority item.</p>\n\n<p>We also introduced a new custom font for headings, which was unfortunately loaded via an `@import` rule within the main CSS file. This sub-optimal loading method meant that not only was the font rendering delayed, but it also blocked the parsing and rendering of other critical CSS rules. Implementing a `preload` directive for the font in the `<head>` section and utilizing `font-display: swap` made an immediate, measurable improvement by allowing text to render with a fallback font much sooner.</p>\n\n<p>Another significant factor contributing to the elevated LCP was late-loading JavaScript that was responsible for rendering critical content. Certain elements that formed part of the LCP were initially hidden by default, only to be revealed or fully constructed via JavaScript execution, even when their underlying content was static. This unnecessary dependency on client-side scripting pushed the LCP event significantly later than it should have been, delaying the point at which the primary content was visible to the user.</p>\n\n<h2>Layout shifts from new components</h2>\n\n<p>The Cumulative Layout Shift (CLS) score jumped from a near-zero, excellent figure to a noticeably problematic value shortly after launch. This wasn't entirely surprising; a new design often means the introduction of new UI components with inherently different intrinsic dimensions and rendering behaviors. Images were particularly problematic, often lacking explicit `width` and `height` attributes, which allowed the page to reflow dramatically as these resources eventually loaded.</p>\n\n<p>Dynamic content injection proved to be another major source of CLS. Elements such as promotional banners, cookie consent pop-ups, or social sharing widgets were frequently injected into the DOM without reserving adequate space beforehand. This meant that when they appeared, they would abruptly push existing content further down the page, creating jarring visual instability. Our solution involved explicitly reserving space for these elements using CSS or, in some cases, employing `position: absolute` or `position: fixed` to take them out of the document flow where appropriate.</p>\n\n<p>Custom fonts also contributed to our CLS woes. When the browser initially renders text with a fallback font, and then swaps to the custom web font once it's loaded, it can trigger a reflow if the font metrics (like character width and line height) differ significantly. While the `font-display: swap` strategy is generally beneficial for LCP by ensuring text is visible quickly, one must be acutely aware of its potential CLS impact. We mitigated this by carefully selecting fallback fonts with similar metrics and, where possible, using font loading APIs to manage the swap more gracefully, as discussed in detail in our previous post on fixing font loading issues.</p>\n\n<h2>Input delay from bloated JavaScript</h2>\n\n<p>While the regressions in First Input Delay (FID) — and by extension, Interaction to Next Paint (INP) — weren't as immediately dramatic as LCP or CLS, they still represented a measurable hit to user experience. The new frontend framework, along with its associated libraries and an increased number of third-party tracking scripts, collectively added a significant amount of main thread work. This prolonged periods of CPU-intensive computation, directly delaying the browser’s ability to respond promptly to user interactions like clicks, taps, or key presses.</p>\n\n<p>Upon profiling, we found that several new components within our modern framework were aggressively hydrated, meaning their JavaScript was executed and bound to the DOM even if they weren't immediately interactive or visible to the user. This led to larger-than-necessary JavaScript bundles and excessive parsing and execution time upfront. Deferring the loading and execution of non-critical JavaScript, especially for components below the fold or those that are only interacted with later in the user journey, became an immediate priority for our optimization efforts.</p>\n\n<p>Auditing third-party scripts, while often a painful and time-consuming exercise, proved absolutely necessary. We discovered a new analytics script that was being loaded synchronously in the `<head>` section of the document. This critical error blocked the initial render process and significantly delayed the point at which the page became truly interactive. Refactoring its inclusion to use `async` or `defer` attributes, and prioritizing only absolutely critical scripts for synchronous loading, was an obvious and impactful fix that dramatically improved our FID and INP scores.</p>\n\n<h2>Practical debugging with Chrome DevTools</h2>\n\n<p>My absolute first stop for any performance diagnosis is always Chrome DevTools. The Performance tab is an indispensable tool, providing a granular timeline view of exactly what the browser is doing at every millisecond. You can meticulously trace JavaScript execution, pinpoint layout recalculations, and observe paint events to precisely identify when and why LCP occurs or when a CLS event takes place. It's like having an X-ray vision into the browser's rendering engine.</p>\n\n<p>Lighthouse reports, accessible directly from DevTools or via Google's PageSpeed Insights, offer an invaluable quick overview of common performance bottlenecks. While synthetic in nature, they provide a strong baseline for identifying major issues across various categories, from accessibility to best practices and, crucially, performance. My approach isn't to chase a perfect 100 score, but rather to use their concrete suggestions as a guide for prioritizing and implementing the most impactful fixes.</p>\n\n<p>For the unvarnished truth about user experience, I rely heavily on Real User Monitoring (RUM) data. Tools like Google Analytics 4, especially with its enhanced measurements for Core Web Vitals, or dedicated RUM providers, track actual user experiences across a diverse range of devices, network conditions, and locations. This is where the real story lives, showing you how your site truly performs for *everyone*, not just on a high-spec development machine with a pristine network connection. It's the ultimate source of truth.</p>\n\n<h2>What I do next</h2>\n\n<p>The immediate fixes implemented for LCP, CLS, and FID were primarily focused on achieving quick wins: aggressive image optimization, correcting inefficient font loading strategies, and deferring non-critical JavaScript. These initial interventions bought us valuable time and successfully restored our baseline performance to acceptable levels. However, true performance excellence is not a one-time achievement, but rather an ongoing commitment to systematic improvement.</p>\n\n<p>My next step involves initiating a much deeper, more comprehensive audit of the entire component library that was introduced with the redesign. Each new component needs to be rigorously evaluated for its individual and cumulative impact on overall performance, extending beyond mere visual appeal or functional correctness. We are also in the process of setting up automated CI/CD checks for Core Web Vitals, integrating performance budgets and alerts directly into our development workflow to proactively catch regressions before they ever make it to production.</p>\n\n<p>Ultimately, site performance isn't a static target that can be</p>\n\n<p>fixed</p>\n\n<p>and forgotten; it’s an iterative, continuous process that requires vigilance and dedicated effort. If your site is struggling after a significant redesign, or if you're experiencing unexplained Core Web Vitals regressions, a detailed performance audit can uncover deeply hidden issues and lay out a clear, actionable path forward. Don't hesitate to reach out to me directly at /contact?ref=audit to discuss how we can partner for a deeper analysis and sustained performance gains. For a related angle I keep coming back to, see <a href=\"/journal/why-pagespeed-scores-change-every-run/\">Why PageSpeed Scores Change Every Run (And What to Fix First)</a>.</p>","tags":["core-web-vitals","redesign","lcp"],"views":123}