From 57b63e9ecc111ce2c2434fbe886abdfcf98055d0 Mon Sep 17 00:00:00 2001 From: Pierre Le Fevre Date: Sun, 22 Mar 2026 07:54:29 +0100 Subject: [PATCH] Fix gap direction for column flex containers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per CSS Box Alignment §8, row-gap applies between rows and column-gap between columns. In a column flex container the main axis is vertical, so the gap between items should use row-gap (not column-gap) and the gap between flex lines should use column-gap (not row-gap). Introduces main_gap/cross_gap variables that swap based on flex direction. Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/layout/src/lib.rs | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/crates/layout/src/lib.rs b/crates/layout/src/lib.rs index 25671f3..5905ae5 100644 --- a/crates/layout/src/lib.rs +++ b/crates/layout/src/lib.rs @@ -897,9 +897,6 @@ fn layout_flex_children(parent: &mut LayoutBox, viewport_height: f32, font: &Fon let justify_content = parent.justify_content; let align_items = parent.align_items; let align_content = parent.align_content; - let row_gap = parent.row_gap; - let column_gap = parent.column_gap; - let container_main_size = match flex_direction { FlexDirection::Row | FlexDirection::RowReverse => parent.rect.width, FlexDirection::Column | FlexDirection::ColumnReverse => { @@ -928,6 +925,16 @@ fn layout_flex_children(parent: &mut LayoutBox, viewport_height: f32, font: &Fon FlexDirection::RowReverse | FlexDirection::ColumnReverse ); + // Per CSS Box Alignment §8, row-gap applies between rows and column-gap + // between columns. In a row flex container the main axis is horizontal + // (column-gap between items, row-gap between lines). In a column flex + // container the axes are swapped. + let (main_gap, cross_gap) = if is_row { + (parent.column_gap, parent.row_gap) + } else { + (parent.row_gap, parent.column_gap) + }; + if parent.children.is_empty() { parent.rect.height = 0.0; return; @@ -1070,7 +1077,7 @@ fn layout_flex_children(parent: &mut LayoutBox, viewport_height: f32, font: &Fon let gap = if current_line.is_empty() { 0.0 } else { - column_gap + main_gap }; if !current_line.is_empty() && line_main_size + gap + item_outer > container_main_size { @@ -1079,7 +1086,7 @@ fn layout_flex_children(parent: &mut LayoutBox, viewport_height: f32, font: &Fon } if !current_line.is_empty() { - line_main_size += column_gap; + line_main_size += main_gap; } line_main_size += item_outer; current_line.push(i); @@ -1098,7 +1105,7 @@ fn layout_flex_children(parent: &mut LayoutBox, viewport_height: f32, font: &Fon for line in &lines { // Total hypothetical main sizes + gaps. let total_gaps = if line.len() > 1 { - (line.len() - 1) as f32 * column_gap + (line.len() - 1) as f32 * main_gap } else { 0.0 }; @@ -1229,7 +1236,7 @@ fn layout_flex_children(parent: &mut LayoutBox, viewport_height: f32, font: &Fon // Step 6: Position items on main and cross axes. let total_cross_gaps = if lines.len() > 1 { - (lines.len() - 1) as f32 * row_gap + (lines.len() - 1) as f32 * cross_gap } else { 0.0 }; @@ -1254,7 +1261,7 @@ fn layout_flex_children(parent: &mut LayoutBox, viewport_height: f32, font: &Fon // Main-axis justification. let total_main_gaps = if line.len() > 1 { - (line.len() - 1) as f32 * column_gap + (line.len() - 1) as f32 * main_gap } else { 0.0 }; @@ -1378,9 +1385,9 @@ fn layout_flex_children(parent: &mut LayoutBox, viewport_height: f32, font: &Fon // Add gap between items (not after last). if item_pos < line_items.len() - 1 { if is_reverse { - main_cursor -= column_gap; + main_cursor -= main_gap; } else { - main_cursor += column_gap; + main_cursor += main_gap; } } @@ -1394,7 +1401,7 @@ fn layout_flex_children(parent: &mut LayoutBox, viewport_height: f32, font: &Fon } } - cross_cursor += line_cross + row_gap + ac_between_offset; + cross_cursor += line_cross + cross_gap + ac_between_offset; } // Set parent height based on children. @@ -1412,7 +1419,7 @@ fn layout_flex_children(parent: &mut LayoutBox, viewport_height: f32, font: &Fon .map(|&i| items[i].target_main + items[i].outer_main) .sum(); let gaps = if line.len() > 1 { - (line.len() - 1) as f32 * column_gap + (line.len() - 1) as f32 * main_gap } else { 0.0 }; -- 2.51.2