fix(layout): keep-with-next page breaks, column flex fit-content, flex automatic minimum + page-break guide - #382
Conversation
…o minimum Fixes from the 2026-09-30 visual review of the NetPdf-tester corpus. - break-after: avoid / break-before: avoid now keep a block with its next sibling (12-terms-and-conditions heading left alone at the page bottom). The greedy resolver ignores the avoid cost, so BlockLayouter adds a keep-with-next lookahead at all four block break sites and the mid-split entry. Chains up to three; never moves the first block on a page; dropped when both can't share a fresh page. - A non-stretched auto-width item in a column flex container is sized fit-content (11-course-completion-certificate ID was placed 0 wide). - A flex item's own text no longer re-applies its percentage width (06-travel-voucher li width:50% wrapped at 25%). - min-width:auto on row flex items is the CSS Flexbox 4.5 automatic minimum size (01-cruise email overlapped its label). Measured lazily, only when a line shrinks; shared by emission and the pre-measure. - The overflow shorthand now expands to overflow-x / overflow-y. Tests: 9 new fragmentation conformance cases, 13 keep-with-next facade tests, flex unit and production tests, overflow shorthand tests. Docs: new docs-site/page-breaks.md guide, README page-break section, compatibility matrix, deferrals, CHANGELOG. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Flex sizing, forced-break precedence, shorthand validation, and documentation contain unresolved correctness issues.
Review effort: Balanced
Findings: 4
Open (5)
Reject CSS-wide keywords in multi-component overflow shorthands · New Avoid double-subtracting chrome from nested content-box widths · New Treat overflow: clip as non-scrollable for automatic minimum sizing · New Clamp fit-content size to min-width and max-width · New Remove per-paragraph orphans and widows from missing support · New
What changed in this PR
Improves pagination and flex sizing fidelity based on corpus visual regressions, with corresponding tests and documentation.
Changes:
- Adds keep-with-next pagination for avoided sibling breaks.
- Fixes flex sizing, automatic minimums, and overflow shorthand expansion.
- Adds regression coverage and a page-break guide.
| File | Description |
|---|---|
tests/NetPdf.W3cConformance/README.md |
Updates fragmentation results. |
tests/NetPdf.W3cConformance/FragmentationCases.cs |
Adds keep-with-next cases. |
tests/NetPdf.UnitTests/Rendering/KeepWithNextPaginationTests.cs |
Tests pagination behavior. |
tests/NetPdf.UnitTests/Rendering/CorpusVisualReviewTests.cs |
Covers corpus regressions. |
tests/NetPdf.UnitTests/Phase3/FlexLayouterTests.cs |
Tests automatic flex minimums. |
tests/NetPdf.UnitTests/Phase3/FlexLayouterProductionTests.cs |
Tests production flex geometry. |
tests/NetPdf.UnitTests/Css/Parser/CssParserAdapterPreprocessTests.cs |
Tests overflow expansion. |
src/NetPdf.Layout/Layouters/FlexLayouter.cs |
Implements flex sizing fixes. |
src/NetPdf.Layout/Layouters/BlockLayouter.cs |
Implements keep-with-next and width handling. |
src/NetPdf.Css/Parser/Preprocessing/OverflowShorthandExpander.cs |
Expands overflow shorthand. |
src/NetPdf.Css/Parser/Preprocessing/CssPreprocessor.cs |
Registers overflow recovery. |
README.md |
Expands page-break guidance. |
docs/deferrals.md |
Updates implementation status. |
docs/compatibility-matrix.md |
Documents fragmentation support. |
docs-site/toc.yml |
Adds the guide to navigation. |
docs-site/page-breaks.md |
Adds the page-break guide. |
docs-site/compatibility.md |
Links the new guide. |
CHANGELOG.md |
Records fixes and documentation. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2eed7f69f8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- overflow shorthand: a CSS-wide keyword is valid only as the whole value (`overflow: inherit hidden` is rejected). - Flex automatic minimum: `overflow: clip` is not a scroll container, so it keeps the content-based minimum; only hidden / scroll / auto opt out. - Column flex fit-content width is clamped by the item's min-/max-width, and the BlockLayouter column pre-measure uses the same fit-content width. - A padded inline-only flex item's text was laid out at border box minus twice its chrome: the nested root-inline dispatch subtracts the item's border + padding itself (the grid / abspos contract), so flex now hands it the border box (ItemContentLayoutInlineSize), in emission and both pre-measures. - A forced break at the same boundary overrides keep-with-next. - deferrals.md: per-paragraph orphans/widows are not "missing". Tests: overflow CSS-wide cases, clip keeps the minimum, fit-content min/max clamp, padded fit-content and row items keep one line, forced break overrides a keep (W3C 22/22). All fail without the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>


Fixes from the 2026-09-30 visual review of the NetPdf-tester corpus, plus a user guide for page breaks.
Fixes
h2 { break-after: avoid }left alone at the page bottomBlockLayouter(all four block break sites + the mid-split entry). The greedy resolver never weighed the avoid flag.width: 50%, wrapping at 25%. The item-content pass no longer re-applies the item's width / min / max.min-width: autoon row flex items is now the CSS Flexbox §4.5 automatic minimum (min-content), measured lazily only when a line shrinks. The value now overflows the row (browser behavior) instead of overlapping.overflow: hiddenignoredoverflowshorthand now expands tooverflow-x/overflow-y(AngleSharp.Css keeps it unexpanded; beta.144 did too). Needed for the §4.5 opt-out.Keep-with-next rules: chains up to three avoids; the first block on a page never moves; dropped when the two can't share a fresh page (no wasted page). The "next piece" follows how the next sibling actually paginates (text block whole; split-able container chrome + first child; table / grid / flex ≈ two lines). AnonymousBlock children don't inherit the parent's
break-*.08-sales-report's "Highlights" is a
div.section-titlewith no break rule — a browser leaves it at the page bottom too. The fix is in the HTML (.section-title { break-after: avoid; }), now documented.Docs
docs-site/page-breaks.md("Controlling page breaks"): how NetPdf picks each break, forced / avoided breaks and their limits, recipes, troubleshooting. Added to the site TOC; linked from README (ships in the NuGet package) and the site compatibility page.h1…h6 { break-after: avoid }, explains the paragraph behavior.docs/compatibility-matrix.md,docs/deferrals.md(fragmentation-control + flex entries), CHANGELOG[Unreleased].Tests
break-before/ legacy alias / kept first child of a section / split-able next section / fresh-page fallback / page-start guard.KeepWithNextPaginationTests(13, real fonts): paragraph, list, table, wrapper, chain, limits, anonymous-block guard, and a 40-section document where no page ends with a heading.CorpusVisualReviewTests(8, real fonts) + flex production / §9.7 unit tests + overflow shorthand tests.src/changes, 21/27 flex + corpus tests, 7/13 keep-with-next tests and 6/9 new W3C cases fail; the rest are control cases.terms-50page50 → 51 (headings now kept with their text; no page ends with a heading).Follow-ups logged separately
PAGINATION-FORCED-OVERFLOW-001fires on every page for wrapped documents.🤖 Generated with Claude Code