fix: typing-in-header scroll jump — global scroll-padding-top made Chrome's per-keystroke caret reveal walk the page to 0; offset moved to anchor targets (main [id] scroll-margin-top)

Chrome re-scrolls the focused editable into view on every keystroke and
honours the viewport's scroll-padding-top while ignoring the editable's
own scroll-margin (crbug.com/41492445) — so the sticky-header search
field, which sits above the 76px line and can never be scrolled below
it, dragged the page toward 0 one keystroke at a time, and the previous
negative-scroll-margin counter could not work. CDP harness bisection:
of all suspects (smooth scroll, sticky header, overflow clip,
animations, ambient layer, suggest siblings) only removing the global
scroll-padding stops the jump. TOC/skip anchor offset now lives as
scroll-margin-top on the in-content targets; harness confirms scrollY
constant while typing and anchors still land below the header.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jWfn3RwPfFGTtBddm36Uy
This commit is contained in:
ctao/demo
2026-07-25 23:56:05 +02:00
co-authored by Claude Fable 5
parent 694b7d2003
commit 0bb378e0cc
+12 -8
View File
@@ -107,14 +107,18 @@
} }
* { box-sizing: border-box; } * { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 76px; /* sticky header + anchor jumps */ } html { -webkit-text-size-adjust: 100%; }
/* Chrome re-scrolls the focused editable into view on EVERY keystroke and /* Anchor jumps (TOC, skip link) must land below the 76px sticky header. That
honours scroll-padding-top while doing it. Inputs inside the sticky header offset used to be a global `html { scroll-padding-top: 76px }` — but Chrome
live above that 76px line by definition, so each typed character triggered re-scrolls the focused editable into view on EVERY keystroke and honours
a corrective scroll-to-top. Negative scroll-margin cancels the padding for scroll-padding-top while doing it (crbug.com/41492445: the reveal also
exactly these fields (root cause, not a workaround — the padding exists for ignores the editable's own scroll-margin, so a negative scroll-margin on
in-content anchors, never for header chrome). */ the header inputs could not cancel it). The header search fields sit above
.nav-search input, .search-pop input { scroll-margin-top: -76px; } the 76px line by definition and, being sticky, can never be scrolled below
it — so each typed character walked the page toward 0. Scoping the offset
to the in-content anchor targets fixes typing and keeps every jump
(TOC headings, skip link → #main) landing below the header. */
main, main [id] { scroll-margin-top: 76px; }
/* Guard, not a solution (DESIGN.md): every wide element is contained at its own /* Guard, not a solution (DESIGN.md): every wide element is contained at its own
level (tables scroll in their box, long words wrap); clip only catches level (tables scroll in their box, long words wrap); clip only catches
regressions so one offender can never remove the page gutters. `clip`, unlike regressions so one offender can never remove the page gutters. `clip`, unlike