◉CLAUDE LABJP
●2.1.302 — Fork subagents are now on by default in claude -p, the Agent SDK and the desktop app. Turn them off with CLAUDE_CODE_FORK_SUBAGENT=0 (10/16)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 43 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.302 — Fork subagents are now on by default in claude -p, the Agent SDK and the desktop app. Turn them off with CLAUDE_CODE_FORK_SUBAGENT=0 (10/16)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 43 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/Claude Code
⟐ Claude Code/2026-10-19Intermediate

The Page Was 90px Too Wide at 375px, and the Culprit Never Showed Up in querySelectorAll

When a pseudo-element causes horizontal overflow on phones, scanning elements finds nothing. A probe script that confirms the culprit by diff, and overflow fixes that keep sticky intact, with measurements.

Claude Code267CSSDebuggingResponsivePlaywright

✦ Premium Article

I opened my site's billing page at phone width (375px), and the theme switch and menu at the right end of the header had slid off the screen.

document.documentElement.scrollWidth read 465px. The page was 90px wider than the screen, a factor of 1.24 (465 ÷ 375). A menu falling off-screen on the billing page, the one leading into checkout, hurts conversion directly.

I scanned every element for a right edge beyond the viewport. The scan returned zero hits.

The culprit was the ::after of a decoration I had attached to the first section of every page: a golden glow 540px wide. Pseudo-elements appear in neither querySelectorAll nor getBoundingClientRect.

Here I rebuild the same symptom on a small page, write a probe script that pins the cause down to one element including pseudo-elements, and compare fixes. overflow-x: hidden looks like it works, then breaks sticky somewhere else.

A minimal page that reproduces it

Before touching the production page, I rebuilt the structure in about 20 lines. The trigger was a rule that decorates "the first section of every page".

<!doctype html><html lang="en"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body{margin:0;font:16px/1.7 sans-serif}
header{display:flex;justify-content:space-between;align-items:center;padding:12px 15px;border-bottom:1px solid #ccc}
header button{width:40px;height:40px}
main>div{padding:0 15px}
section{position:relative;padding:24px 0}
/* decoration applied to the first section of every page */
main > div > section:first-child::after{
  content:"";position:absolute;top:0;left:50%;width:540px;height:200px;
  transform:translateX(-50%);background:radial-gradient(closest-side,gold,transparent);
  pointer-events:none;z-index:-1}
</style></head><body>
<header><span>Site</span><button id="menu">≡</button></header>
<main><div>
<section><h1>Membership</h1><p>The first section.</p></section>
<section><h2>Plan</h2><p>The second section.</p></section>
</div></main></body></html>

The section is 345px wide (375px minus 15px of padding on each side). Centering a 540px glow on its midpoint at 187.5px puts the right edge at 187.5 + 270 = 457.5px.

Measured in headless Chromium at 375×800, scrollWidth was 458px. Production read 465px; the difference comes from section width and padding, and the structure is the same.

The element scan returns zero

The first thing most of us write is a loop that looks for elements whose right edge sits beyond the viewport.

const vw = document.documentElement.clientWidth;
[...document.body.querySelectorAll('*')]
  .filter(el => el.getBoundingClientRect().right > vw + 0.5);
// → [] (zero hits on the repro page and in production)

::after is not a DOM element, so this loop never visits it. The result says "nothing overflows", and the investigation stalls with no cause in sight.

This is where I lost the most time. When the result is empty, I now suspect "something exists that the scan cannot reach" before I suspect my measuring method.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦You can run a probe script on your own page that pins down a horizontal-overflow culprit to one element, pseudo-elements (::before / ::after) included
✦You can decide between overflow-x hidden, clip, and a root-level rule without breaking sticky elements
✦You can hand Claude Code the measured facts instead of just saying 'it overflows', and skip several rounds of guess-and-patch
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⟐ Claude Code2026-10-19
If You Wrote MCP Allow Rules as Just `mcp__servername` — Three Lines to Recheck After v2.1.299
Claude Code v2.1.299 changed MCP allow rules to match only the server they name. Here is how to audit older entries in settings.json, with a short Python script that does it.
⟐ Claude Code2026-10-18
I Added the allow Rule and the Prompt Still Appears — Reading Six Layers from /permissions
When an allow rule is in your settings and the same approval prompt keeps coming back, something else decided first. Starting from what /permissions shows, here are six layers you can verify against the official permissions docs: ask and deny precedence, where settings.local.json is read, Cowork's shell tool, and more.
⟐ Claude Code2026-10-15
The Hook That Was Meant to Guard My Japanese Folder Never Blocked Anything — Python Was Reading stdin as cp932
A PreToolUse hook guarding folders like 経理 or 議事録 silently lets edits through when Python's stdin defaults to cp932. How I reproduced it, the three-line fix, and one command to check your own hooks.