NNicheStackTutorials
← All tutorials
Hugo

Hugo Dark Mode vs Ad Blockers (Compatibility Fix)

When dark-mode CSS hides ad containers or ad blockers strip theme variables — diagnose and fix both.

·10 min read·Hugo
Hugo Dark Mode vs Ad Blockers (Compatibility Fix) cover

Tested on: PaperMod v8, uBlock Origin 1.62, Brave Shields, dark + light themes Bug: Ad slots collapsed to 0px in dark mode. Ad blockers removed ins.adsbygoogle and broke layout grid.

Symptom 1: dark mode hides ad background

PaperMod dark CSS:

.dark ins.adsbygoogle { background: transparent !important; }

Fine for AdSense. My placeholder .ad-slot used background: var(--entry) same as page — looked like missing content, editors filed bugs.

Fix — visible but neutral placeholder when ad blocked or loading:

.ad-slot {
  min-height: 90px;
  background: color-mix(in srgb, var(--border) 30%, transparent);
  border: 1px dashed var(--border);
  border-radius: 6px;
}
.dark .ad-slot:not(:has(ins[data-adsbygoogle-status="done"])) {
  /* fallback if :has unsupported, use .ad-slot.is-empty */
  opacity: 0.6;
}

Symptom 2: uBlock removes ad node, grid collapses

Sidebar layout:

.post-layout {
  display: grid;
  grid-template-columns: 1fr 300px;
}

When aside.sidebar-ad empty, main column didn't expand.

Fix:

.post-layout:has(.sidebar-ad:empty) {
  grid-template-columns: 1fr;
}
@supports not selector(:has(*)) {
  .post-layout.no-sidebar { grid-template-columns: 1fr; }
}

JS fallback (tiny, 400 bytes):

document.querySelectorAll('.sidebar-ad').forEach(el => {
  if (!el.children.length) el.closest('.post-layout')?.classList.add('no-sidebar');
});

Only load when hugo.IsProduction.

Symptom 3: filter list blocks plausible + ads

Some lists block /ads/ path — my partial was /partials/ads/ triggering cosmetic filters on unrelated divs with class ad-slot.

Renamed:

layouts/partials/monetization/   # was ads/
class="sponsor-slot"             # was ad-slot

Avoid ad- prefix in class names if blockers target cosmetic rules (controversial but fixed false positives).

Dark mode toggle + localStorage (if you keep JS)

Ad refresh on theme flip broke AdSense policy (invalid activity warning).

Solution: don't re-push ads on theme change. Reload page:

// theme toggle handler
localStorage.setItem('pref-theme', next);
location.reload(); // heavy but safe for ads

I removed JS toggle entirely — prefers-color-scheme only. Problem gone.

Detect ad block (optional, non-hostile)

<script>
setTimeout(() => {
  const slot = document.querySelector('.sponsor-slot ins');
  if (slot && slot.offsetHeight === 0) {
    document.body.classList.add('ads-blocked');
  }
}, 3000);
</script>
.ads-blocked .sponsor-slot { display: none; }
.ads-blocked .post-layout { grid-template-columns: 1fr; }

Show polite "support us" link instead of empty box.

Verify

  1. Chrome light + dark → ad/placeholder visible dimensions stable
  2. uBlock enabled → no horizontal scroll, no empty sidebar gap
  3. View source — sponsor-slot present, no broken HTML
  4. AdSense policy check — no encouraged clicks messaging
hugo server
# DevTools → Rendering → emulate dark
# DevTools → Request blocking → adsbygoogle.js

Result

Layout bug tickets: 3/month → 0. Ad block rate ~28% on tech blog — grid fix improved mobile readability for those users too.

Tags: HugoDark ModeAd BlockCSS