Skip to content

fix(js): clientWidth is the padding box, scrollWidth the scrolling area - #294

Merged
tannevaled merged 1 commit into
mainfrom
js-scroll-client-size
Oct 18, 2026
Merged

tannevaled merged 1 commit into
mainfrom
js-scroll-client-size

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Problem

<h1 style="white-space:nowrap;width:10px">Short text here</h1>: scrollWidth returned 10. All of client* and scroll* returned the border box.

Spec read

  • CSSOM View scrollWidth: return the width of the element's scrolling area (0 with no box; the root uses the viewport). clientWidth: 0 for no box or an inline box; otherwise the width of the padding edge, minus any scrollbar.
  • CSS Overflow 3 §3.3, the scrollable overflow area, is the union of: the padding box; the line boxes it contains; the border boxes of the boxes it is the containing block for; and descendants' scrollable overflow, clipped when overflow is not visible.

Root cause

js/dom.go mapped clientWidth/Height and scrollWidth/Height to borderW/borderH, the border box.

Change

js.BoxMetrics is an optional Metrics extension (ClientSize, ScrollSize) the binder uses for client* and scroll*. Without it they fall back to the border box, as before. The engine's metrics implement it from the box tree:

  • client = padding box, 0 for an inline or box-less element;
  • scroll = union of the padding box, its line boxes and their items, and descendants' border boxes (descending only into non-clipping ones), measured from the padding box's top-left. An inline element reports its border box.

Each read goes through the forced synchronous layout from #293. Not modelled: the root/body viewport cases of the spec, and end-side alignment padding.

Tests

  • TestScrollAndClientSize (engine, RenderHTML with JS): nowrap overflow; a 5px-border/2px-padding box with an overflowing 200×100 child → client 54, scroll 202×102; no overflow → padding box. Failed on main (false,10,64,64,64,34,56,26).
  • TestSessionBoxMetrics (js): values come from BoxMetrics; unknown node → 0.

🤖 Generated with Claude Code

client* and scroll* both returned the border box. CSSOM View defines
clientWidth/Height as the padding edge (no borders, minus a scrollbar
this engine never draws; 0 for an inline box) and scrollWidth/Height as
the size of the element's scrolling area - its scrollable overflow area
(CSS Overflow 3 §3.3): the padding box united with the line boxes and
inline content it holds and its descendants' border boxes, a descendant
being entered only when it does not clip its own overflow. So
<h1 style="white-space:nowrap;width:10px">Short text here</h1> reported
scrollWidth 10, the very measurement a fitting heading needs.

js.BoxMetrics is a second optional Metrics extension the binder uses for
client* and scroll*; the engine's metrics implement it from the box tree
(after the same forced synchronous layout as every other read).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 76f0508 into main Oct 18, 2026
7 checks passed
@tannevaled
tannevaled deleted the js-scroll-client-size branch October 18, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant