refactor(html): name the boxes a frame anchors against, not every element - #685
Merged
Conversation
…ment
`*{position:relative}` made every element a containing block, so an
absolutely positioned frame or shape resolved against its direct parent
by accident. Three boxes were doing that work - the page for a slide's
and a drawing's shapes, a paragraph or a cell for a text document's
frames - so they state it, and the blanket rule goes.
Being a containing block is also what a page-anchored frame has to get
past to reach its page, which no element can while every ancestor is
one.
`*{margin:0}` goes with it: of the elements this sheet reaches, only
`body` carries a margin from the browser's own sheet, and `body{margin:0}`
already covers it.
Rendering is unchanged - htmlcmp compares 332 public and 1062 private
outputs, generated from one build and rendered against either sheet, with
no mismatch.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QVkpzsGS6YASMqm3NwmWib
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #684, now rebased on main.
*{position:relative}in the shipped stylesheet made every element a containing block, so every absolutely positioned frame and shape resolved against its direct parent by accident rather than against the box the file actually anchors it to.Auditing all 1144 reference-output pages for absolutely positioned elements with no positioned ancestor in their own markup, exactly three boxes were doing that work:
.odr-page-outertdx-pThose three state it; the blanket rule goes. Two things it turned out not to be holding up:
.odr-sheet-sort, whose header is alreadyposition:sticky(the comment claiming otherwise is corrected here), and the PDF frontend, which links nodocument.cssand declares.p{position:relative}itself.*{margin:0}goes with it. Of the elements this sheet reaches —div,table/tr/td/th/col,img,svg,x-p,x-s,mark,span,br/wbr— onlybodycarries a margin from the browser's own sheet, andbody{margin:0}on the next line already covers it. (<p>/<h1>appear only infont_file.cpp, which writes its own inline<style>.)Being a containing block is also what a page-anchored frame has to get past to reach its page:
frame_anchor_typereads all four ODF anchor types, buttranslate_frame_propertiesonly branches onas_char, so a page-anchored frame lands against its paragraph. That stays unfixable while every ancestor is an anchor, and becomes fixable now.Verification
Rendered both sides of the whole public corpus in Chrome and compared pixels.
Correction to an earlier claim in this PR. I first verified with
htmlcmp, which reported all 332 + 1062 files matching. That result was empty:compare-htmlshort-circuits byte-identical files without rendering them, and this PR changes only CSS, so every html file was identical and nothing was ever rendered. CI's compare step has the same blind spot. Both were re-run with a renderer that screenshots each page from either tree regardless.Of 228 public pages, 226 are pixel-identical. Two differ:
docx/sample1.docx/document.html— 2943 pxdocx/sample3.docx/document.html— 1891 pxBoth are one line of text moving exactly 1 pixel down (ink centroid dx +0.000, dy +0.999, ink identical to the byte). Layout is unchanged: every element's top and height match to 0.01px. Injecting the two dropped rules back one at a time isolates the cause to
*{position:relative}alone (*{margin:0}has no effect) — a line whose baseline falls on a fractional pixel snaps to a different whole pixel when its spans are positioned boxes. The new result is consistent with every other unpositioned line on the page.Reproduced across repeated runs with identical bounding boxes, and a control rendering the same tree twice shows the pdf/xls pages are nondeterministic while these two are not.
🤖 Generated with Claude Code