Skip to content

render: resolve functional flex-basis against the containing block - #749

Open
alexskinner wants to merge 1 commit into
h4ckf0r0day:mainfrom
alexskinner:fix/functional-flex-basis
Open

render: resolve functional flex-basis against the containing block#749
alexskinner wants to merge 1 commit into
h4ckf0r0day:mainfrom
alexskinner:fix/functional-flex-basis

Conversation

@alexskinner

Copy link
Copy Markdown
Contributor

What changed

flex-basis: calc(100% - 314px) (longhand, or as the third token of flex:) was evaluated context-free at parse time through dimension_value, so the 100% became 0 and the basis a negative length that taffy clamped to 0. With a definite zero basis and flex-grow: 0 the item sat at its min-content width, and any specified width was — correctly, per spec — irrelevant. That made the failure look like a dropped width declaration (only an inline style.flexBasis could move the element), which is how it was first reported in #737 alongside a Wikipedia case that turns out to be a separate table-sizing issue.

width/height/min-*/max-* already defer functional expressions in size_expressions and resolve them in layout_dom's top-down pass; this gives flex-basis the same treatment:

  • LayoutStyle::flex_basis_expression: Option<String> (lib.rs)
  • the flex-basis longhand and flex shorthand store the expression; keyword forms clear it (style.rs)
  • the flex shorthand tokenises with split_top_level(value, ' ') so flex: 0 0 calc(100% - 314px) is one basis token instead of three
  • resolved with resolve_contextual_length against inh.cb_width next to the existing width/height resolution (dom.rs)

Related to #737 (fixes the readymembership.com half of it; the en.wikipedia.org infobox there is a table min-content-width problem, not this).

Validation

  • New test functional_flex_basis_resolves_against_the_containing_block in crates/obscura-render/tests/layout_test.rs: longhand and shorthand calc() bases in a 1200px flex row both lay out at 886px (were 26px, the item's min-content width).
  • cargo test -p obscura-render --test layout_test: 97 passed / 11 failed, the same 11 failures as main before this change (font/environment related, unrelated files).
  • Live check through an embedding host: https://readymembership.com/ at 1400×900, .main-nav-holder went from 145px (nav stacked vertically over the hero) to 1046px with the nav laid out horizontally. width: calc(100% - 314px) on the same item already produced 886px in the fixture before the change, confirming the deferred path is the right one.

Rendering

Layout only. Fixture, viewport 1400×900, DSF 1:

<div style="display:flex;width:1200px">
  <div style="flex:0 0 300px">a</div>
  <div style="flex-basis:calc(100% - 314px)">nav</div>
</div>

Second item before: 26px wide. After: 886px (Chrome: 886px).

Performance

No expected impact: one extra Option<String> per style, populated only when a flex-basis/flex value contains (, and one extra expression evaluation per such node in the existing per-node resolution pass.

Checklist

  • The change is focused and does not remove existing behavior without justification.
  • Tests cover the failure or feature.
  • Existing tests pass, including render and no-render configurations when affected. (Same pre-existing failure set as main.)
  • I checked for CPU, latency, and memory regressions.
  • Public API or user-facing behavior changes are documented. (New public field on LayoutStyle, doc-commented.)

`flex-basis: calc(100% - 314px)` was evaluated context-free at parse time
through `dimension_value`, so the `100%` became 0 and the basis a negative
length that taffy clamped to 0. With a definite zero basis and
`flex-grow: 0` the item sat at its min-content width, and any specified
`width` was (correctly, per spec) irrelevant — which made the failure look
like a dropped width declaration. readymembership.com's header nav stacked
vertically because of exactly this rule.

`width`/`height`/`min-*`/`max-*` already defer functional expressions in
`size_expressions` and resolve them in the layout pass; give `flex-basis`
the same treatment via a `flex_basis_expression` slot resolved against the
containing-block width. The `flex` shorthand now tokenises at paren depth
0 so `flex: 0 0 calc(...)` yields one basis token instead of three.
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