AOY
TR EN
← Writing

What broke the mobile layout was a decorative glow

3 September 2026· 4 min read· Front end

The familiar feeling of hunting horizontal overflow: text cut off on the right and no idea which element is doing it. I measured my way to all three, and two were not where I expected.

This site’s home page had been converted from a design tool’s output and contained no media queries at all. On a phone the page scrolled sideways and text was cut off on the right.

The first job was to measure. At 375px wide:

documentElement.clientWidth  → 375
documentElement.scrollWidth  → 738

The document was twice the viewport. Which means a single element was stretching everything, and the whole page was laying out in a 738px world.

Finding the culprit

A small script that lists everything sticking out to the right was enough:

const vw = document.documentElement.clientWidth;
[...document.querySelectorAll('body *')]
  .map((el) => ({ el, r: el.getBoundingClientRect() }))
  .filter(({ r }) => r.width > 0 && r.right > vw + 1)
  .sort((a, b) => b.r.right - a.r.right);

Top of the list:

position: absolute;
top: -320px;
left: 50%;
transform: translateX(-50%);
width: 1100px;
height: 760px;
background: radial-gradient(...);
pointer-events: none;

The decorative green glow behind the headline. It is not even visible as an object — pointer-events: none, fully transparent at the edges.

Absolutely positioned does not mean harmless

The common assumption is that an absolutely positioned element is out of flow and therefore does not affect layout. That is not true for scrollable overflow. If the element sticks out to the right it enlarges the scrollable area, and the document grows.

Here the 1100px box is placed at 187px by left: 50% and pulled 550px left by translateX(-50%): left edge −362, right edge 738. Overflow on the left does not enlarge the scroll area (wrong direction); overflow on the right does. That was the document width, exactly.

Decision · not putting overflow on the body

The obvious fix is body { overflow-x: hidden }. I did not use it: turning the body into a scroll container risks breaking the position: sticky header above.

Instead the glow itself was constrained — width: 100% on small screens. Fixing a problem at its source is cheaper than clipping the symptom.

Second trap: the selectors missed silently

The entire layout lived in inline style attributes and the elements had no classes. Inline styles always beat stylesheet rules, so the media query needed !important — that part was expected. For targeting, I used attribute selectors:

[style*="grid-template-columns:340px 1fr"] {
  grid-template-columns: 1fr !important;
}

The rule never applied. And it did not complain either.

The reason: the page’s reveal-on-scroll script writes el.style.opacity and el.style.transform. The moment JavaScript writes any style property, the browser reserialises the entire style attribute:

grid-template-columns:340px 1fr     ← what I wrote in the HTML
grid-template-columns: 340px 1fr    ← after JS touched it

A space after the colon. The substring match breaks, the selector matches nothing, and the CSS quietly does nothing.

Lesson

[style*="…"] is a fragile targeting method and its failure is invisible. Adding real classes to the layout elements took five minutes and removed the problem entirely.

Third trap: the verification tool lied

After switching to classes I took a screenshot and the page still looked broken. The command was:

chrome --headless=new --window-size=390,2400 --screenshot=out.png ...

Yet measuring in a real browser gave scrollWidth 375 and zero overflowing elements. Both could not be true.

The explanation: on Windows there is a minimum window width. Headless Chrome cannot honour the requested 390px as a window size, the content lays out wider, but the screenshot is still captured at the requested 390px. The result is a fixed page that looks broken.

So the verification tool was telling me that the thing I had fixed was not fixed. Taking the measurement in a real browser with scrollWidth and getBoundingClientRect() settled it.


What to take from it

  • Do not hunt horizontal overflow by eye — enumerate it. A three-line script that ranks the elements sticking out ends the “which div is it” tour.
  • An absolutely positioned element enlarges the scroll area. Being invisible and unclickable does not change that.
  • Try constraining the source before clipping the symptom. overflow: hidden works and silently breaks other things, like position: sticky.
  • Do not target with [style*="…"]. The moment JavaScript touches any style property the attribute text changes and the selector misses without a word.
  • Verify that your verification actually measures. “The screenshot still looks broken” and “the page is still broken” are not the same sentence.

More writing

all of it