diff --git a/crates/obscura-render/src/dom.rs b/crates/obscura-render/src/dom.rs
index b34c5d7..df6a562 100644
--- a/crates/obscura-render/src/dom.rs
+++ b/crates/obscura-render/src/dom.rs
@@ -10345,6 +10345,57 @@ mod tests {
}
}
+ #[test]
+ fn overflowing_grid_item_auto_margins_use_safe_logical_start() {
+ let tree = parse_html(
+ r#"
+
+
+
+ "#,
+ );
+ let laid = layout_dom(&tree, (800.0, 300.0));
+ let rect = |id: &str| laid.rects[&tree.get_element_by_id(id).unwrap()];
+
+ for (grid_id, item_id, expected_x) in [
+ ("ltr-center-grid", "ltr-center", 0.0),
+ ("ltr-end-grid", "ltr-end", 0.0),
+ ] {
+ let grid = rect(grid_id);
+ let item = rect(item_id);
+ assert!(
+ (item.width - 600.0).abs() < 0.01,
+ "{item_id} lost its min-content floor: {item:?}"
+ );
+ assert!(
+ (item.x - grid.x - expected_x).abs() < 0.01,
+ "{item_id} did not use safe logical-start overflow: grid={grid:?} item={item:?}"
+ );
+ }
+
+ for (grid_id, item_id, expected_x) in [
+ ("absolute-center-grid", "absolute-center", -150.0),
+ ("absolute-end-grid", "absolute-end", -300.0),
+ ] {
+ let grid = rect(grid_id);
+ let item = rect(item_id);
+ assert!(
+ (item.x - grid.x - expected_x).abs() < 0.01,
+ "{item_id} incorrectly used the in-flow auto-margin fallback: grid={grid:?} item={item:?}"
+ );
+ }
+ }
+
#[test]
fn root_and_body_inline_outer_geometry_matches_blockification_rules() {
for display in ["inline-block", "inline-flex", "inline-grid"] {
diff --git a/vendor/taffy/src/compute/grid/alignment.rs b/vendor/taffy/src/compute/grid/alignment.rs
index ae257f4..2a2af3f 100644
--- a/vendor/taffy/src/compute/grid/alignment.rs
+++ b/vendor/taffy/src/compute/grid/alignment.rs
@@ -370,7 +370,20 @@ pub(super) fn align_item_within_area(
};
let overflows = resolved_size + non_auto_margin.sum() > grid_area_size;
- let alignment_keyword = resolve_self_alignment_safety(alignment_style, overflows);
+ // In-flow auto margins take precedence over self-alignment and are always
+ // safe. When the item overflows there is no positive free space for the
+ // auto margins to absorb, so safe alignment falls back to the logical
+ // start edge rather than honoring an authored unsafe center/end alignment.
+ // Absolutely positioned items use their authored self-alignment here;
+ // their auto margins are resolved by the abs-pos constraint equation.
+ let alignment_keyword = if position != Position::Absolute
+ && auto_margin_count > 0
+ && overflows
+ {
+ AlignItemsKeyword::Start
+ } else {
+ resolve_self_alignment_safety(alignment_style, overflows)
+ };
// Compute offset in the axis
let alignment_based_offset = match alignment_keyword {
@@ -612,4 +625,69 @@ mod tests {
);
assert_eq!(content_box_max, 290.0);
}
+
+ #[test]
+ fn overflowing_auto_margins_override_unsafe_self_alignment() {
+ let area = Line { start: 0.0, end: 300.0 };
+ let oversized = 600.0;
+ let margin_cases = [
+ Line { start: None, end: Some(0.0) },
+ Line { start: Some(0.0), end: None },
+ Line { start: None, end: None },
+ ];
+
+ for alignment in [AlignSelf::CENTER, AlignSelf::END] {
+ for margin in margin_cases {
+ let (ltr_start, ltr_margin) = super::align_item_within_area(
+ area,
+ alignment,
+ oversized,
+ Position::Relative,
+ Line { start: None, end: None },
+ margin,
+ 0.0,
+ crate::Direction::Ltr,
+ );
+ assert_eq!(ltr_start, 0.0);
+ assert_eq!(ltr_margin, Line { start: 0.0, end: 0.0 });
+
+ let (rtl_start, rtl_margin) = super::align_item_within_area(
+ area,
+ alignment,
+ oversized,
+ Position::Relative,
+ Line { start: None, end: None },
+ margin,
+ 0.0,
+ crate::Direction::Rtl,
+ );
+ assert_eq!(rtl_start, -300.0);
+ assert_eq!(rtl_margin, Line { start: 0.0, end: 0.0 });
+ }
+ }
+
+ let (absolute_center, _) = super::align_item_within_area(
+ area,
+ AlignSelf::CENTER,
+ oversized,
+ Position::Absolute,
+ Line { start: None, end: None },
+ Line { start: None, end: Some(0.0) },
+ 0.0,
+ crate::Direction::Ltr,
+ );
+ assert_eq!(absolute_center, -150.0);
+
+ let (absolute_end, _) = super::align_item_within_area(
+ area,
+ AlignSelf::END,
+ oversized,
+ Position::Absolute,
+ Line { start: None, end: None },
+ Line { start: None, end: Some(0.0) },
+ 0.0,
+ crate::Direction::Ltr,
+ );
+ assert_eq!(absolute_end, -300.0);
+ }
}