Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

- Block/Flexbox/Grid: a container's own end-side padding (right padding for LTR, left padding for RTL, and bottom padding) is now only included in its `content_size` when the container is a scroll container (i.e. has `overflow` other than `visible`/`clip` in either axis). Per the [CSS Overflow spec](https://www.w3.org/TR/css-overflow-3/#scrollable), boxes that are not scroll containers do not extend their scrollable overflow region by their own padding, so overflowing content within an ordinary padded box no longer propagates spuriously enlarged content sizes to ancestor scroll containers

- Leaf: `compute_leaf_layout` now follows the same convention as block/flexbox/grid for its `content_size`: the node's own end-side padding (right padding for LTR, left padding for RTL, and bottom padding) is only included when the node is a scroll container. Previously both the start and end padding were included unconditionally, over-reporting the content size of ordinary padded leaves whose measured content overflows

- Grid: the first baselines of grid items which are scroll containers are now clamped to the item's border box (matching the existing flexbox behaviour, per the [CSSWG resolution](https://github.com/w3c/csswg-drafts/issues/7660))

- Flexbox: items with `align-self: baseline` and an `auto` cross-axis margin no longer participate in baseline alignment, per [CSS Flexbox §8.3](https://www.w3.org/TR/css-flexbox-1/#baseline-participation). Previously such items were still counted when deciding whether a line performs baseline alignment, had their baselines measured, and could affect the container's own first baseline
Expand Down
17 changes: 16 additions & 1 deletion src/compute/leaf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,25 @@ where
};
let size = size.maybe_max(padding_border.sum_axes().map(Some));

// A scroll container's own padding at the end of the content is part of its scrollable
// overflow region, so it is included in the content size. Boxes that are not scroll
// containers do not extend their overflow region by their own padding.
#[cfg(feature = "content_size")]
let content_size = {
let is_scroll_container = style.overflow().x.is_scroll_container() || style.overflow().y.is_scroll_container();
let is_rtl = style.direction().is_rtl();
let start_padding = if is_rtl { padding.right } else { padding.left };
let end_padding = if is_rtl { padding.left } else { padding.right };
Size {
width: start_padding + measured_size.width + if is_scroll_container { end_padding } else { 0.0 },
height: padding.top + measured_size.height + if is_scroll_container { padding.bottom } else { 0.0 },
}
};

LayoutOutput {
size,
#[cfg(feature = "content_size")]
content_size: measured_size + padding.sum_axes(),
content_size,
baselines: Baselines::NONE,
top_margin: CollapsibleMarginSet::ZERO,
bottom_margin: CollapsibleMarginSet::ZERO,
Expand Down
41 changes: 40 additions & 1 deletion tests/hand_written/scroll_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use taffy::geometry::Point;
use taffy::prelude::*;
use taffy::style::{BoxSizing, Display, Overflow};
use taffy_test_helpers::new_test_tree;
use taffy_test_helpers::{new_test_tree, test_measure_function, TestNodeContext};

const CONTENT: f32 = 1000.0;
const CONTAINER: f32 = 200.0;
Expand Down Expand Up @@ -130,6 +130,45 @@ fn content_size_excludes_the_own_padding_of_a_non_scroll_container() {
}
}

fn measured_leaf(overflow: Overflow, padding: Rect<LengthPercentage>) -> Layout {
let mut tree = new_test_tree();
let node = tree
.new_leaf_with_context(
Style {
box_sizing: BoxSizing::BorderBox,
size: Size { width: length(300.0), height: length(CONTAINER) },
padding,
overflow: Point { x: overflow, y: overflow },
..Default::default()
},
TestNodeContext::fixed(100.0, CONTENT),
)
.unwrap();

tree.compute_layout_with_measure(node, Size::MAX_CONTENT, test_measure_function).unwrap();
*tree.layout(node).unwrap()
}

#[test]
fn leaf_content_size_includes_the_containers_own_padding() {
for (top, bottom) in [(PADDING, 0.0), (0.0, PADDING), (PADDING, PADDING), (0.0, 0.0)] {
let layout = measured_leaf(Overflow::Scroll, edge(top, bottom));

assert_eq!(layout.content_size.height, top + CONTENT + bottom, "Leaf with padding {top}/{bottom}");
}
}

#[test]
fn leaf_content_size_excludes_the_own_padding_of_a_non_scroll_container() {
for (top, bottom) in [(PADDING, 0.0), (0.0, PADDING), (PADDING, PADDING), (0.0, 0.0)] {
let layout = measured_leaf(Overflow::Visible, edge(top, bottom));

// A box that is not a scroll container does not extend its scrollable overflow
// region by its own padding: only the content contributes.
assert_eq!(layout.content_size.height, top + CONTENT, "Leaf with padding {top}/{bottom}");
}
}

#[test]
fn scroll_height_accounts_for_the_containers_own_padding() {
for display in [Display::Block, Display::Flex, Display::Grid] {
Expand Down