Skip to content

Implement safe and unsafe overflow-position alignment keywords#952

Open
rit3sh-x wants to merge 5 commits into
DioxusLabs:mainfrom
rit3sh-x:feat/safe-alignment
Open

Implement safe and unsafe overflow-position alignment keywords#952
rit3sh-x wants to merge 5 commits into
DioxusLabs:mainfrom
rit3sh-x:feat/safe-alignment

Conversation

@rit3sh-x
Copy link
Copy Markdown

Summary

Implements the CSS safe / unsafe overflow-position keywords for all alignment properties in Flexbox and CSS Grid. Closes #550.

safe falls back to logical Start when the alignment subject overflows its container, preventing data loss at the start edge. Existing variants are unchanged and remain equivalent to unsafe.

Changes

  • Types: 5 new variants: SafeStart, SafeEnd, SafeFlexStart, SafeFlexEnd, SafeCenter on AlignItems and AlignContent (aliases AlignSelf / JustifyItems / JustifySelf / JustifyContent inherit them). Added is_safe() and position() helpers. AlignContent::reversed() extended for RTL pairing.
  • Parser: hand-rolled FromCss for safe <position> and unsafe <position>. Rejects spec-invalid combinations (safe stretch, safe baseline, safe space-*).
  • Compute: apply_alignment_fallback folds the Safe* modifier into its is_safe flag, so grid-track, flex justify-content, and flex align-content are wired through automatically. Self-alignment paths (align_item_within_area for grid, align_flex_items_along_cross_axis for flex) explicitly apply the Start fallback on overflow, RTL- and wrap-reverse-aware.
  • Docs: new section in docs/style-properties.md.

Tests

  • 16 unit tests (helpers, reversed(), parser).
  • 10 hand-written integration tests covering safe overflow, no-overflow, unsafe regression, RTL fallback, and multi-line flex align-content.
  • 17 gentest fixtures → 68 generated XML expectations. All match the local Chrome render.

4500 tests pass, 0 failures.

Known limitation

The two absolutely-positioned flex paths in compute/flexbox.rs strip Safe* via .position() but do not apply the Start overflow fallback. Marked TODO (safe alignment) in code. Happy to land as a follow-up.

Test plan

  • cargo build --all-features
  • cargo test --all-features
  • cargo doc --all-features --no-deps
  • cargo run -p gentest — 68 new fixtures match Chrome byte-for-byte
  • Confirm Safe*-variants approach over a safe: bool field
  • Confirm CHANGELOG handling (left untouched per release-prep convention)

rit3sh-x added 4 commits May 10, 2026 23:35
Add SafeStart/SafeEnd/SafeFlexStart/SafeFlexEnd/SafeCenter on AlignItems
and AlignContent with is_safe()/position() helpers, RTL-aware reversed()
extension, and a hand-rolled FromCss parser for `safe X` / `unsafe X`
that rejects spec-invalid combinations. apply_alignment_fallback now
folds the safe modifier into its is_safe flag, so content alignment in
grid tracks and flex justify/align-content honor the Start fallback when
overflowing. Self-alignment paths accept the new variants but defer the
overflow fallback to a follow-up commit.
Implement the Start fallback for "safe" overflow-position keywords on
align-self and justify-self in both grid and flex layouts. When an item
overflows its alignment container and the alignment value is one of the
Safe* variants, the offset is anchored to the logical Start edge to
avoid data loss; an item that fits its container keeps its requested
position.

In grid `align_item_within_area`, overflow is detected from the resolved
size and non-auto margins versus the grid area size, and the fallback
respects the container `direction` so RTL anchors at the right edge.

In flex `align_flex_items_along_cross_axis`, the fallback short-circuits
when the cross-axis free space is negative, accounting for
`cross_axis_should_reverse` and `is_wrap_reverse` so the Start edge
matches the underlying writing-mode-relative start.

The three previously-stale `// TODO: Implement safe alignment` comments
at the grid track, flex justify-content, and flex align-content sites
are removed; the modifier-folding inside `apply_alignment_fallback`
already routes Safe* keywords through the Start fallback path on
overflow.

Add ten integration tests covering the new self-alignment behavior, the
content-alignment behavior wired by the previous commit, the no-overflow
case, the unsafe (default) overflow regression, the RTL fallback edge,
and a multi-line flex `align-content` overflow.

The flex absolutely-positioned alignment paths still strip Safe* via
`.position()` without invoking the Start fallback; this is left for a
follow-up commit.
…ow alignment

Add 17 HTML fixtures under test_fixtures/grid/ and test_fixtures/flex/
that exercise the `safe` and `unsafe` overflow-position keywords across
container-level (justify-content, align-content) and item-level
(justify-self, align-self) alignment in both grid and flex layouts. The
fixtures pair overflow and no-overflow geometries so that the Start
fallback path and the normal positional path are both verified, and
include unsafe-end regressions to prove the default behavior is
unchanged for plain end alignment.

Run the gentest pipeline against these fixtures to render each in
headless Chrome and capture the expected layout into 68 generated XML
expectation files (4 variants per fixture: border-box LTR, border-box
RTL, content-box LTR, content-box RTL). Register the new entries in
tests/xml/mod.rs.

The full suite passes — taffy's safe-alignment implementation matches
Chrome byte-for-byte on every fixture.
Add a section to docs/style-properties.md that lists the new Safe*
variants on AlignItems and AlignContent, describes the overflow
fallback to logical Start, and clarifies which position keywords are
valid pairings under the spec.
Copy link
Copy Markdown
Member

@nicoburns nicoburns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rit3sh-x This generally looks quite good.

I feel like the "struct containing enum and separate bool" approach might be better, as it would avoid all the unreachable!'s and extra match cases in the current implementation. Perhaps we could even use an enum AlignmentSafety { Safe, Unsafe } instead of bool, because I think there is also an AlignmentSafety::Auto which we may want to implement at some later point.

There are also a few places in the code that keep around as is_safe constant/parameter that doesn't make sense if is_safe is coming in via a style. But I think they might disappear in a refactor to use a boolean / separate enum anyway.

I'm not too worried about ergonomics for consumers of Taffy, as basically every consumer is a framework/toolkit that's converting from another format. I don't think many people are exposing Taffy types directly to end-users.

Comment thread src/compute/grid/alignment.rs Outdated
Comment thread src/compute/grid/alignment.rs Outdated
- Drop dead `is_safe` parameter from `apply_alignment_fallback`; infer
  it from the alignment style itself.
- In `align_item_within_area` (grid) and `align_flex_items_along_cross_axis`
  (flex), mutate `alignment_style` to `Start` on safe + overflow and
  reuse the existing match, removing a duplicated RTL branch.
- Add `Safe*` arms to `benches/yoga_helpers.rs` so the bench crate builds
  on CI; Yoga has no overflow-position equivalent, so they map to
  `unimplemented!()` like the other unsupported variants.
@rit3sh-x
Copy link
Copy Markdown
Author

@nicoburns I’ve pushed a new commit addressing the concerns you mentioned. Please take a look when you get a chance.

@rit3sh-x rit3sh-x requested a review from nicoburns May 11, 2026 21:33
@rit3sh-x
Copy link
Copy Markdown
Author

@nicoburns any updates?

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.

Implement the "safe" alignment variants

2 participants