(sidebar): size the sidebar to its container, not the window - #306
Conversation
#sidebar and #sidebar-resize-handle were 100vh, but their parent #app-container is the window minus the 22px #status-bar, so both were 22px taller than the box holding them. Any focus or scrollIntoView below the fold made the browser scroll #app-container by exactly that overflow (clientHeight 1078, scrollHeight 1100, scrollTop 22), clipping the top row of sidebar icons; #app-container is overflow: hidden, so there is no scrollbar to scroll back and the clipping survives until a reload. A container-relative height leaves nothing inside #app-container sized to the viewport. The new CSS source test pins that for the whole file: it reads every (min-/max-)height declaration reaching 100vh and fails if its selector matches an element under #app-container in index.html.
devsuitup
left a comment
There was a problem hiding this comment.
Reviewed a4a0c5d. The CSS fix is right: html,body {height:100%}, body flex column, #app-container {flex:1; min-height:0; overflow:hidden} gives the container a definite height, so 100% on #sidebar / #sidebar-resize-handle resolves instead of collapsing; the only remaining vh is the fixed fullscreen overlay, out of the container by design. CI green, no trailers.
One thing in the test, which is the PR's stated deliverable: selectorOf (test/app-container-viewport-height-css.test.js:31-34) takes only the last physical line before {. With the multi-line grouped selectors that dominate style.css (25+ groups), a future
#sidebar,
#unrelated {
height: 100vh;
}
is checked as #unrelated only and passes green — reproduced. Build the selector list from the whole head (head.trim().split(',')) rather than its last line; then a mutation grouping #sidebar with another selector must go red. Note, not an ask: the test resolves against the static index.html, so runtime-created elements are outside its reach — fine today, worth one line in the test header.
Approving on the fix; please land the selectorOf change before merge so the guarantee matches the description.
The defect
#sidebarand#sidebar-resize-handlewereheight: 100vh. Their parent#app-containeris a flex child ofbodythat shares the window with the 22px#status-bar, so both were 22px taller than the box holding them.Measured in a running instance:
#app-containerreportedclientHeight: 1078,scrollHeight: 1100andscrollTop: 22, with the sidebar's first row atgetBoundingClientRect().top === -22— the top row of toolbar icons scrolled above the viewport and was clipped.#app-containerisoverflow: hidden, so no scrollbar exists and the user cannot scroll back; the clipping persists until the window reloads. SettingscrollTop = 0from the console restores it. Any focus orscrollIntoViewon an element below the fold triggers it; it happened twice unprompted in a 30-minute session.The fix
Both rules use
height: 100%, which resolves against#app-containerinstead of the window.#app-container's own sizing is untouched — the status bar's 22px strip is deliberate.Only
.jsonl-screenshot-fullscreen img'smax-height: 95vhstill uses a viewport unit, on aposition: fixed; inset: 0overlay that is pinned to the viewport by design and is not laid out inside#app-container.How it is pinned
test/app-container-viewport-height-css.test.jsasserts the property rather than the literal value: it reads every(min-/max-)heightdeclaration instyle.csswhose value reaches 100vh, resolves each rule's selector againstpublic/index.htmlwith jsdom, and fails if any match lands inside#app-container. A second test pins the premise the invariant rests on —#status-baris a sibling of#app-containerwith a fixed pixel height, and#app-containerisoverflow: hidden, so overflow cannot be scrolled back.Mutation-checked: restoring
height: 100vhon#sidebaralone fails the test, and on both rules the failure names both selectors.Checks
npx eslint .— 0 errors, 333 warnings (identical to the count onc939748in this worktree).npm test— stage 1: 1903 tests / 1900 pass / 1 fail / 2 skipped; stage 2: 120 / 119 / 0 fail / 1 skipped. The single failure is the pre-existing environmental one,test/ipc-path-validator.test.js"allows files under ~/.claude/".