debug_ghosts_pt2

Debug Ghosts, Part II

December 27, 2025

Sometimes the most frustrating bugs aren’t caused by bad code — they’re caused by correct code that the browser hasn’t fully acknowledged yet.

This is the story of a CSS splash screen that refused to fit the viewport, even though every rule was correct — and why simply opening browser DevTools made it work instantly.


The Problem: A Splash Screen That Wouldn’t Fit the Viewport

I was implementing a session-based splash screen for theFocusOnLife (TFOL). The requirements were straightforward:

  • Show a splash image on first visit only

  • Fill the entire browser viewport

  • Prevent scrolling

  • Clicking the image navigates into the site

But the result was off:

  • Only about 70% of the image height was visible

  • The rest appeared only after scrolling

  • Scrollbars were present

  • A header sometimes appeared beneath the splash

The confusing part?
The CSS and JavaScript were correct.


The Usual Suspects (and Why They Weren’t the Cause)

Like most front-end developers, I worked through the obvious possibilities.

Viewport Units

  • 100vh vs 100dvh

  • Desktop vs mobile behavior

  • Incorrect <meta viewport> settings (including fixing an invalid initial-scale)

Layout & Stacking Context

  • position: fixed

  • Aggressive z-index values

  • Hiding headers and navigation during the splash

  • Dealing with the reCAPTCHA badge overlay

Scroll Locking

  • overflow: hidden on body

  • overflow: hidden on html

  • Locking both

  • Ultimately freezing the page using position: fixed

CSS Overrides

  • Global img { height: auto; } rules

  • Container constraints

  • Margin resets

  • Strategic (and justified) use of !important

Each change improved something — but the splash image still rendered at roughly 70% height.


The Breakthrough: DevTools “Fixes” the Bug

Then something unexpected happened.

I opened Chrome DevTools.

Instantly:

  • The image snapped to full viewport height

  • Scrollbars disappeared

  • Letterboxing appeared correctly on the sides

  • Everything behaved exactly as intended

No code change.
No reload trick.
Just opening DevTools.

That’s when it became clear: this wasn’t a CSS bug.
It was a viewport recalculation issue.


Why Opening DevTools Works

Modern browsers aggressively optimize layout calculations. On initial page load, they may defer a full recalculation of:

  • Viewport units (vh, dvh)

  • Fixed-position elements

  • Scroll-locked pages

Opening DevTools forces:

  • A viewport resize event

  • A layout reflow

  • Recalculation of viewport-based CSS

  • Re-evaluation of position: fixed constraints

In short:

DevTools didn’t fix the layout — it forced the browser to recognize that the layout was already correct.


The Real Fix: Forcing a Viewport Recalculation

Once I understood the cause, the solution was clean and intentional.

After displaying the splash screen, I explicitly triggered a resize event:

requestAnimationFrame(() => {
  window.dispatchEvent(new Event('resize'));
});

This mimics the recalculation DevTools triggers automatically and ensures that:

  • 100vh / 100dvh resolves correctly

  • Fixed overlays size properly on first load

  • The splash image fills the viewport immediately

No hacks.
No timeouts.
No guesswork.


The Final Result

With that change in place:

  • The splash image fills the viewport vertically

  • No scrolling is possible while it’s visible

  • The header is hidden during the splash

  • Side filler appears instead of cropping

  • The splash shows once per browser session

  • The layout works on cold loads, fresh tabs, and normal navigation


The Takeaway

Some bugs aren’t logic errors.

They’re assumption errors.

  • The CSS was right

  • The JavaScript was right

  • The layout was right

The browser just hadn’t finished recalculating the viewport.

If opening DevTools magically fixes your layout, don’t ignore it.
Ask why.

There’s almost always a deeper explanation — and usually a cleaner solution — hiding underneath.


 

Posted in ghost-stories by TFOL BLOG

Comments