The Stuff That Breaks Website Speed and What Still Works

The Stuff That Breaks Website Speed and What Still Works

Cloudflare Rocket Loader Isn’t Magic (and Sometimes Hurts)

First time I turned on Rocket Loader, I genuinely thought my site had learned to teleport. Then I checked the dev console. Array of warnings, a broken comment box, and my lazy-loaded AdSense units were suddenly MIA. Cool.

Rocket Loader alters how scripts are loaded — it injects its own async/deferral layering so scripts fire after page render. In theory, that helps site speed by unblocking the render path. But it doesn’t play fair with all scripts, especially if you’ve got JavaScript relying on DOM readiness or if it’s manipulating layout post-load.

If you’re using custom plugins for ads (especially sticky or anchor units), test everything with Rocket Loader on/off. Sometimes Rocket Loader double-defers scripts that were already async, pushing them beyond their useful init time. That’s where stuff just quietly doesn’t show.

Undocumented edge: One obscure combo — Sticky ad + vanilla JS ad loader function + jQuery 3.x — fails silently with Rocket Loader enabled. Rocket Loader rewrites your inline JS because it assumes you’re not you. AdSense blanks out. No errors logged.

If you must use it, set data-cfasync="false" on your ad-related inline scripts and test in incognito. Cached versions can mask breakage.


Font Preloading Can Backfire When You Self-Host

This one got me when I migrated a site off Google Fonts to a local copy — partly for GDPR compliance, partly to cut the extra calls. I preloaded the .woff2s like a good nerd. It looked fast on Lighthouse, but real-world users were getting FOUT in slow network scenarios where preload was outrunning actual usage.

Here’s what happened:

  • Preload hint for /fonts/MyFont.woff2 came early in head
  • The CSS using it came 3-4 files later, after a render-blocking CSS file
  • Browser downloaded the font before rendering knew it was needed
  • Font cache dumped on soft refresh after only one paint used it

When you self-host fonts and preload them, the preload only helps if:

  • The font is used above-the-fold
  • Your CSS using the font appears right after (or during) preload
  • You don’t have competing CSS files that block rendering first

Also, preload hints require crossorigin if you’re using @font-face with crossorigin: anonymous defined — otherwise, the font preloads from a different context, and you just doubled your font load time without realizing it.


AdSense Auto Ads and CLS: Professional Gaslighting

Google’s own metrics tools will quietly destroy your PageSpeed mobile scores for serving Auto Ads — even when you follow their official advice. There’s no “safe layout” for Auto Ads because their injection spot is non-deterministic. CLS is calculated based on visible layout shifts *during* interaction windows — and most of their ad injection happens right before or just after FCP.

What I didn’t expect is that sometimes the Auto Ads script takes 4–5 seconds to decide where to drop a banner. On one of my WordPress sites, it shoved a 320×100 between a Bootstrap card and a lazy image. The layout jumped like 70px mid-scroll. PageSpeed dinged me hard. Barely fixable without disabling Auto Ads entirely.

How I duct-taped it:

<div class="adsense-space-placeholder" style="min-height: 125px; margin-bottom: 1.5rem;"></div>

This is hacky but useful. Place strategic empty Divs where Auto Ads might drop a unit. Especially under your H2s or above the first paragraph. Just don’t do this below-the-fold or you’ll create phantom gaps with no monetization in return.

Aha moment: AdSense ignores data-ad-slot width constraints in responsive mode under Auto Ads. It doesn’t care about your CSS. It cares about available viewport width *at moment of decision*, which isn’t necessarily load time.


Third-Party Scripts Blocking TTFB — Yes, That Still Happens

This is the one they tell you is a backend problem when it’s actually your damn social share count plugin. I had a weird analytics spike where one specific page took ~8 seconds on TTFB. Thought it was a DB lock, checked logs, nada. Booted up WebPageTest with a cold start. The culprit? A Pinterest share count JS blocking on redirect to an expired endpoint.

Bug: Browsers sometimes queue actual HTML parsing behind a hung request from a script injected into the <head>. Even async doesn’t save it if the browser’s DNS wait timeout is triggered while the core HTML is unloading from TTFB.

Now I gate every third-party widget with JS injection on user interaction or defer like my life depends on it. You’d be amazed how many scripts still behave like it’s 2012.


Image Optimization Plugins Lie — Serve From CDN or Suffer

If you’re running WordPress and using any plugin to “optimize” images, double-check whether it’s actually offloading media to a CDN or just compressing it. I made the mistake of assuming Imagify + WP Rocket would auto-do-the-right-thing. Nope. On closer inspection, thumbnails were optimized, but full-size images still served from origin — and the server was in New Jersey.

Big problem was mobile users in Asia-Pacific — consistent 6–7s image load lag. Lighthouse missed it because test was run in NA.

You actually want a proper CDN layer over images. Cloudflare’s Polish helps, but so does just signing up for BunnyCDN or ImageKit and using rewrite rules on file extensions or a basic origin-pull bucket. Writing your own mapping for /wp-content/uploads/ to pull from a CDN subdomain can shave full seconds off load.

Undocumented gotcha: Firefox doesn’t like AVIFs served with incorrect mime-types. I served .avif off S3 with image/webp. It downloaded but didn’t render. No console error. Just… nothing.


Caching Headers Matter More Than You Think On Shared Hosting

Shared hosting often doesn’t let you touch nginx configs or add far-future cache headers globally. But even without root, you can manually slap caching directives into .htaccess or through WordPress headers if you’re using Apache. I was able to drag initial demo load times from 9s to under 3s just by adding these lines to .htaccess:

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/jpg "access plus 1 year"
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType text/css "access plus 1 month"
  ExpiresByType application/javascript "access plus 1 month"
</IfModule>

Stuff isn’t always fast because it’s compressed. Sometimes it’s just re-fetching CSS files every request because Apache hasn’t been told otherwise… for five years.

Also, be suspicious of plugins promising “full page cache” that clear the cache every time you log in. Makes cache misses great again.


Lazy Loading iframes Still Triggers Scroll Jank

Native lazy loading for iframes (loading="lazy") is great, but it still shifts layout during loading on real devices. I embedded a YouTube video inside an FAQ accordion. Looked fine expanded, but when someone tapped to open it, the browser would reserve zero space until the iframe rendered. The result? Scroll jump, jolt, worse CLS.

Now I calculate the dimensions beforehand using script-snipped container divs like:

<div style="width: 100%; height: 56.25vw; max-height: 315px; background: #000;">
  <iframe loading="lazy" ... ></iframe>
</div>

That way you preallocate a black box even if nothing loads. Doesn’t look gorgeous, but it’s better than the viewport shoving down 300 pixels because YouTube can’t decide what aspect ratio to pick.

Weird case: I had a Shopify product video iframe auto-expand the page by 1000px due to their iframe embed including inline scripts that forcibly resize the container even after loading="lazy" is respected by Chrome. No workaround unless you shadow it inside another div with overflow:hidden.


Content Layout Dirty Trick: Using CSS Grids for Predictable Paint

This is a weird one I discovered while rebuilding a single-column layout. Previously I floated two divs left, letting them collapse under each other in mobile view. Painful CLS ensued when dynamically-loaded content (like ads or Livewire widgets) inserted themselves mid-column. Grids helped.

.main-content {
  display: grid;
  grid-template-columns: 1fr;
  grid-auto-rows: min-content;
  row-gap: 2rem;
}

Grid actually lets browser pre-calculate spacing better than flex or float, even when dynamic content gets injected. I saw lower layout instability scores when wrapping in grid containers vs flex-direction: column, especially with plugins that append DOM elements late.

Also, this gave me one of those rare aha moments:

“It’s not how fast your content loads — it’s whether the browser knows how tall it will be.”

Grid gave it predictability. Flex doesn’t.

Similar Posts