I Fixed My Own Site’s Core Web Vitals: Here’s What Was Slow

In 2026, Core Web Vitals (CWV) are no longer just ‘SEO metrics’; they are the ultimate baseline for professional engineering. For a business i...

My own site had terrible Core Web Vitals. Heavy animations in the hero section, interactive elements with bloated JavaScript files, and images without lazy loading. The hero section alone was dragging down the entire page performance.

I noticed the problem when I ran Lighthouse out of curiosity. The scores were bad — not just a little bad, but “needs work” on mobile. Largest Contentful Paint was slow because a full-size hero image was loading before anything else. First Input Delay was mediocre because the JS bundle included libraries I did not even use on the homepage. Cumulative Layout Shift was fine at least, but the other two metrics were dragging the experience well below Google’s threshold.

This was my own site, so there was no client to blame. The embarrassing truth is that I built it like a prototype, added features iteratively, and never stopped to clean up the performance debt. Every new animation, every interactive element, every “would not it be cool if” addition made the page heavier. The cumulative effect was a site that looked good on my development machine but loaded slowly on the networks my actual visitors use. I normalized the slowness because I saw it happen gradually — it was not a sudden break, it was death by a thousand cuts.

What Was Wrong

The hero section was the main culprit. I had a full-width animation that played on load — SVG morphing, text fading in, background shifting. It looked impressive during development. But the JavaScript required to run it was a separate library that added over 200KB to the bundle. On a 4G connection that meant a visible delay before the hero rendered. On the mobile networks that most Algerian visitors use, where 3G is still common outside major cities, it was worse than visible — it was frustrating enough to make people leave.

The images were the second problem. I had high-resolution portfolio screenshots loading at full size. No lazy loading attribute on any of them. Every image on the page requested its full resolution version upfront, even the ones far below the fold that the user would not see unless they scrolled. That is a rookie mistake, but I made it because I was focused on how the images looked during development, not how they loaded in production. The total page weight was over 2MB, most of it from images that the user might never scroll to see.

The interactive elements — hover effects, scroll-triggered animations, a custom cursor that followed the mouse — were all bundled into one JS file that loaded on every page, including blog posts and contact pages that did not use any of them. The code was clean, but the delivery was wasteful. I was making the user download an entire animation framework just to read a text article or view a simple contact form. That is not optimization. That is laziness disguised as good engineering.

What I Changed

First, I removed the hero animation entirely. Not optimized it — removed it. The site looked cleaner without it, and the performance gain was immediate. That is a hard decision for a developer who spent time building the animation, but most visitors do not care about animated intros. They care about finding the information they came for. The animation was serving my ego, not my users. Deleting it was the single most impactful change I made.

Second, I added native lazy loading to all images below the fold. One HTML attribute — loading=”lazy” — fixed the image loading problem. The above-the-fold images stayed eager, but everything else loaded only when the user scrolled near them. This alone cut the initial page weight by more than half. The images were still there. They just loaded at the right time instead of all at once, competing for bandwidth with the content the user actually needed to see.

Third, I code-split the JavaScript. The animation library loads only on pages that use animations — the homepage and portfolio pages. The custom cursor script loads only on desktop. Heavy interactive components are lazy-loaded when the user interacts with them. The initial JS bundle went from around 400KB to about 60KB. That reduction alone made the site feel instantly faster, and the difference was visible even before I ran the benchmark.

Fourth, I started testing after every change. A quick Lighthouse run before pushing any update caught regressions early. I also started using the browser’s Performance tab to see exactly what was happening during load — which resources were blocking the render, how long each phase took, where the real bottlenecks were. The tools were always available. I just was not using them because I assumed the problem was too complex for a simple fix.

The Results

LCP went from 4.2 seconds to 1.8 seconds on mobile simulation. FID dropped from over 100ms to under 50ms. The overall Lighthouse performance score went from the low 60s to the mid 90s. The site feels faster — not just in benchmarks, but in real usage. Pages render visibly quicker, and the interaction lag that I had normalized through months of daily use is gone. The difference is noticeable even on my own connection, and I know exactly what changed because I made the changes myself.

The lesson I took from this: performance optimization is mostly about removing what you do not need. The biggest gains came from deleting the hero animation and adding lazy loading, not from micro-optimizing CSS selectors or compressing web fonts. A clean, minimal page will always outperform a feature-rich one on real networks with real connection speeds. I still add interactive elements to client projects, but I always test the performance impact before shipping. And I will never skip lazy loading ever again — it costs nothing to add and the benefit is enormous.

If your own site has bad Core Web Vitals, do not reach for a caching plugin or a CDN first. Look at what you can remove. The biggest performance gain is often the delete key.

Leave a Reply

Your email address will not be published. Required fields are marked *

Gravatar profile