mirror of
https://github.com/servo/servo.git
synced 2025-08-10 07:55:33 +01:00
layout: Let stretch
on flex item cross size stretch to the line (#38526)
We were instead stretching to the containing block, which implied that the behaviors of a `stretch` size and `stretch` alignment weren't consistent. As resolved by the CSSWG, the behavior will now be: - If the cross size of the line is known, stretch to the line. - Otherwise, stretch to the containing block. See https://github.com/w3c/csswg-drafts/issues/11784 This aligns us with Blink, which has already shipped this new behavior. Testing: Improves existing WPT and adds a new test. Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
9866ca7e59
commit
93c9fc14f1
16 changed files with 164 additions and 180 deletions
|
@ -58,9 +58,7 @@ struct FlexContext<'a> {
|
|||
struct FlexItem<'a> {
|
||||
box_: &'a FlexItemBox,
|
||||
|
||||
/// The preferred, min and max inner cross sizes. If the flex container is single-line
|
||||
/// and [`Self::cross_size_stretches_to_line`] is true, then the preferred cross size
|
||||
/// is set to [`Size::Stretch`].
|
||||
/// The preferred, min and max inner cross sizes.
|
||||
content_cross_sizes: Sizes,
|
||||
|
||||
padding: FlexRelativeSides<Au>,
|
||||
|
@ -99,17 +97,10 @@ struct FlexItem<'a> {
|
|||
/// <https://drafts.csswg.org/css-sizing-4/#preferred-aspect-ratio>
|
||||
preferred_aspect_ratio: Option<AspectRatio>,
|
||||
|
||||
/// Whether the preferred cross size of the item stretches to fill the flex line.
|
||||
/// This happens when the size computes to `auto`, the used value of `align-self`
|
||||
/// is `stretch`, and neither of the cross-axis margins are `auto`.
|
||||
/// <https://drafts.csswg.org/css-flexbox-1/#stretched>
|
||||
///
|
||||
/// Note the following sizes are not sufficient:
|
||||
/// - A size that only behaves as `auto` (like a cyclic percentage).
|
||||
/// The computed value needs to be `auto` too.
|
||||
/// - A `stretch` size. It stretches to the containing block, not to the line
|
||||
/// (under discussion in <https://github.com/w3c/csswg-drafts/issues/11784>).
|
||||
cross_size_stretches_to_line: bool,
|
||||
/// The automatic size in the cross axis.
|
||||
/// <https://drafts.csswg.org/css-sizing-3/#automatic-size>
|
||||
automatic_cross_size: Size<Au>,
|
||||
automatic_cross_size_for_intrinsic_sizing: Size<Au>,
|
||||
}
|
||||
|
||||
/// Child of a FlexContainer. Can either be absolutely positioned, or not. If not,
|
||||
|
@ -1543,41 +1534,45 @@ impl InitialFlexLineLayout<'_> {
|
|||
FlexAxis::Column => Direction::Inline,
|
||||
};
|
||||
let layout = &mut item.layout_result;
|
||||
let used_cross_size = if item.item.cross_size_stretches_to_line {
|
||||
let content_size = match cross_axis {
|
||||
Direction::Block => layout.content_block_size,
|
||||
Direction::Inline => layout.containing_block_size.inline,
|
||||
};
|
||||
item.item.content_cross_sizes.resolve(
|
||||
cross_axis,
|
||||
Size::Stretch,
|
||||
Au::zero,
|
||||
Some(Au::zero().max(final_line_cross_size - item.item.pbm_auto_is_zero.cross)),
|
||||
|| content_size.into(),
|
||||
// Tables have a special sizing in the block axis in that handles collapsed rows,
|
||||
// but it would prevent stretching. So we only recognize tables in the inline axis.
|
||||
// The interaction of collapsed table tracks and the flexbox algorithms is unclear,
|
||||
// see https://github.com/w3c/csswg-drafts/issues/11408.
|
||||
item.item.box_.independent_formatting_context.is_table() &&
|
||||
cross_axis == Direction::Inline,
|
||||
)
|
||||
} else {
|
||||
layout.hypothetical_cross_size
|
||||
let get_content_size = || match cross_axis {
|
||||
Direction::Block => layout.content_block_size.into(),
|
||||
Direction::Inline => item
|
||||
.item
|
||||
.inline_content_sizes(flex_context, item.used_main_size),
|
||||
};
|
||||
let used_cross_size = item.item.content_cross_sizes.resolve(
|
||||
cross_axis,
|
||||
item.item.automatic_cross_size,
|
||||
Au::zero,
|
||||
Some(Au::zero().max(final_line_cross_size - item.item.pbm_auto_is_zero.cross)),
|
||||
get_content_size,
|
||||
// Tables have a special sizing in the block axis in that handles collapsed rows,
|
||||
// but it would prevent stretching. So we only recognize tables in the inline axis.
|
||||
// The interaction of collapsed table tracks and the flexbox algorithms is unclear,
|
||||
// see https://github.com/w3c/csswg-drafts/issues/11408.
|
||||
item.item.box_.independent_formatting_context.is_table() &&
|
||||
cross_axis == Direction::Inline,
|
||||
);
|
||||
item_used_cross_sizes.push(used_cross_size);
|
||||
|
||||
// “If the flex item has `align-self: stretch`, redo layout for its contents,
|
||||
// treating this used size as its definite cross size so that percentage-sized
|
||||
// children can be resolved.”
|
||||
let needs_new_layout = item.item.cross_size_stretches_to_line &&
|
||||
match cross_axis {
|
||||
Direction::Block => {
|
||||
SizeConstraint::Definite(used_cross_size) !=
|
||||
layout.containing_block_size.block &&
|
||||
layout.depends_on_block_constraints
|
||||
},
|
||||
Direction::Inline => used_cross_size != layout.containing_block_size.inline,
|
||||
};
|
||||
// However, as resolved in https://github.com/w3c/csswg-drafts/issues/11784,
|
||||
// we do that when the cross size is `stretch`. We also need to do it if the
|
||||
// inline size changes, which may happen with a `fit-content` cross size.
|
||||
let needs_new_layout = match cross_axis {
|
||||
Direction::Block => {
|
||||
(match item.item.content_cross_sizes.preferred {
|
||||
Size::Initial => item.item.automatic_cross_size == Size::Stretch,
|
||||
Size::Stretch => true,
|
||||
_ => false,
|
||||
}) && SizeConstraint::Definite(used_cross_size) !=
|
||||
layout.containing_block_size.block &&
|
||||
layout.depends_on_block_constraints
|
||||
},
|
||||
Direction::Inline => used_cross_size != layout.containing_block_size.inline,
|
||||
};
|
||||
if needs_new_layout {
|
||||
#[cfg(feature = "tracing")]
|
||||
tracing::warn!(
|
||||
|
@ -1759,9 +1754,6 @@ impl FlexItem<'_> {
|
|||
let cross_size = match used_cross_size_override {
|
||||
Some(s) => SizeConstraint::Definite(s),
|
||||
None => {
|
||||
// This means that an auto size with stretch alignment will behave different than
|
||||
// a stretch size. That's not what the spec says, but matches other browsers.
|
||||
// To be discussed in https://github.com/w3c/csswg-drafts/issues/11784.
|
||||
let stretch_size = containing_block
|
||||
.size
|
||||
.block
|
||||
|
@ -1792,22 +1784,12 @@ impl FlexItem<'_> {
|
|||
let cross_size = used_cross_size_override.unwrap_or_else(|| {
|
||||
let stretch_size =
|
||||
Au::zero().max(containing_block.size.inline - self.pbm_auto_is_zero.cross);
|
||||
let get_content_size = || {
|
||||
let constraint_space = ConstraintSpace::new(
|
||||
SizeConstraint::Definite(used_main_size),
|
||||
item_writing_mode,
|
||||
self.preferred_aspect_ratio,
|
||||
);
|
||||
independent_formatting_context
|
||||
.inline_content_sizes(flex_context.layout_context, &constraint_space)
|
||||
.sizes
|
||||
};
|
||||
self.content_cross_sizes.resolve(
|
||||
Direction::Inline,
|
||||
Size::FitContent,
|
||||
Au::zero,
|
||||
Some(stretch_size),
|
||||
get_content_size,
|
||||
|| self.inline_content_sizes(flex_context, used_main_size),
|
||||
is_table,
|
||||
)
|
||||
});
|
||||
|
@ -1841,9 +1823,6 @@ impl FlexItem<'_> {
|
|||
} else if let Some(cross_size) = used_cross_size_override {
|
||||
cross_size.into()
|
||||
} else {
|
||||
// This means that an auto size with stretch alignment will behave different than
|
||||
// a stretch size. That's not what the spec says, but matches other browsers.
|
||||
// To be discussed in https://github.com/w3c/csswg-drafts/issues/11784.
|
||||
let stretch_size = containing_block
|
||||
.size
|
||||
.block
|
||||
|
@ -2050,6 +2029,15 @@ impl FlexItem<'_> {
|
|||
};
|
||||
outer_cross_start + margin.cross_start + self.border.cross_start + self.padding.cross_start
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inline_content_sizes(&self, flex_context: &FlexContext, block_size: Au) -> ContentSizes {
|
||||
self.box_.inline_content_sizes(
|
||||
flex_context,
|
||||
SizeConstraint::Definite(block_size),
|
||||
self.preferred_aspect_ratio,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl FlexItemBox {
|
||||
|
@ -2094,28 +2082,31 @@ impl FlexItemBox {
|
|||
main: padding_border.main,
|
||||
cross: padding_border.cross,
|
||||
} + margin_auto_is_zero.sum_by_axis();
|
||||
let (content_main_sizes, mut content_cross_sizes, cross_size_computes_to_auto) =
|
||||
match flex_axis {
|
||||
FlexAxis::Row => (
|
||||
&content_box_sizes.inline,
|
||||
content_box_sizes.block.clone(),
|
||||
preferred_size_computes_to_auto.block,
|
||||
),
|
||||
FlexAxis::Column => (
|
||||
&content_box_sizes.block,
|
||||
content_box_sizes.inline.clone(),
|
||||
preferred_size_computes_to_auto.inline,
|
||||
),
|
||||
};
|
||||
let cross_size_stretches_to_line = cross_size_computes_to_auto &&
|
||||
item_with_auto_cross_size_stretches_to_line_size(align_self, &margin);
|
||||
if cross_size_stretches_to_line && config.container_is_single_line {
|
||||
// <https://drafts.csswg.org/css-flexbox-1/#definite-sizes>
|
||||
// > If a single-line flex container has a definite cross size, the automatic preferred
|
||||
// > outer cross size of any stretched flex items is the flex container’s inner cross size.
|
||||
// Therefore, set it to `stretch`, which has the desired behavior.
|
||||
content_cross_sizes.preferred = Size::Stretch;
|
||||
}
|
||||
let (content_main_sizes, content_cross_sizes, cross_size_computes_to_auto) = match flex_axis
|
||||
{
|
||||
FlexAxis::Row => (
|
||||
&content_box_sizes.inline,
|
||||
&content_box_sizes.block,
|
||||
preferred_size_computes_to_auto.block,
|
||||
),
|
||||
FlexAxis::Column => (
|
||||
&content_box_sizes.block,
|
||||
&content_box_sizes.inline,
|
||||
preferred_size_computes_to_auto.inline,
|
||||
),
|
||||
};
|
||||
let automatic_cross_size = if cross_size_computes_to_auto &&
|
||||
item_with_auto_cross_size_stretches_to_line_size(align_self, &margin)
|
||||
{
|
||||
Size::Stretch
|
||||
} else {
|
||||
Size::FitContent
|
||||
};
|
||||
let automatic_cross_size_for_intrinsic_sizing = if config.container_is_single_line {
|
||||
automatic_cross_size
|
||||
} else {
|
||||
Size::FitContent
|
||||
};
|
||||
let containing_block_size = flex_axis.vec2_to_flex_relative(containing_block.size);
|
||||
let stretch_size = FlexRelativeVec2 {
|
||||
main: containing_block_size
|
||||
|
@ -2136,7 +2127,7 @@ impl FlexItemBox {
|
|||
let (preferred_cross_size, min_cross_size, max_cross_size) =
|
||||
if let Some(cross_content_size) = tentative_cross_content_size {
|
||||
let (preferred, min, max) = content_cross_sizes.resolve_each(
|
||||
Size::FitContent,
|
||||
automatic_cross_size_for_intrinsic_sizing,
|
||||
Au::zero,
|
||||
stretch_size.cross,
|
||||
|| cross_content_size,
|
||||
|
@ -2145,7 +2136,7 @@ impl FlexItemBox {
|
|||
(Some(preferred), min, max)
|
||||
} else {
|
||||
content_cross_sizes.resolve_each_extrinsic(
|
||||
Size::FitContent,
|
||||
automatic_cross_size_for_intrinsic_sizing,
|
||||
Au::zero(),
|
||||
stretch_size.cross,
|
||||
)
|
||||
|
@ -2210,7 +2201,7 @@ impl FlexItemBox {
|
|||
&pbm_auto_is_zero,
|
||||
content_box_sizes,
|
||||
preferred_aspect_ratio,
|
||||
content_cross_sizes.preferred == Size::Stretch,
|
||||
automatic_cross_size_for_intrinsic_sizing,
|
||||
IntrinsicSizingMode::Size,
|
||||
)
|
||||
.into()
|
||||
|
@ -2279,7 +2270,7 @@ impl FlexItemBox {
|
|||
|
||||
FlexItem {
|
||||
box_: self,
|
||||
content_cross_sizes,
|
||||
content_cross_sizes: content_cross_sizes.clone(),
|
||||
padding,
|
||||
border,
|
||||
margin: config.sides_to_flex_relative(pbm.margin),
|
||||
|
@ -2293,7 +2284,8 @@ impl FlexItemBox {
|
|||
align_self,
|
||||
depends_on_block_constraints: *depends_on_block_constraints,
|
||||
preferred_aspect_ratio,
|
||||
cross_size_stretches_to_line,
|
||||
automatic_cross_size,
|
||||
automatic_cross_size_for_intrinsic_sizing,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2312,12 +2304,12 @@ impl FlexItemBox {
|
|||
// TODO: when laying out a column container with an indefinite main size,
|
||||
// we compute the base sizes of the items twice. We should consider caching.
|
||||
let FlexItem {
|
||||
content_cross_sizes,
|
||||
flex_base_size,
|
||||
content_min_main_size,
|
||||
content_max_main_size,
|
||||
pbm_auto_is_zero,
|
||||
preferred_aspect_ratio,
|
||||
automatic_cross_size_for_intrinsic_sizing,
|
||||
..
|
||||
} = self.to_flex_item(
|
||||
layout_context,
|
||||
|
@ -2344,7 +2336,7 @@ impl FlexItemBox {
|
|||
layout_context,
|
||||
containing_block,
|
||||
&auto_minimum,
|
||||
content_cross_sizes.preferred == Size::Stretch,
|
||||
automatic_cross_size_for_intrinsic_sizing == Size::Stretch,
|
||||
);
|
||||
(sizes, depends_on_block_constraints)
|
||||
},
|
||||
|
@ -2354,7 +2346,7 @@ impl FlexItemBox {
|
|||
&pbm_auto_is_zero,
|
||||
&content_box_sizes_and_pbm.content_box_sizes,
|
||||
preferred_aspect_ratio,
|
||||
content_cross_sizes.preferred == Size::Stretch,
|
||||
automatic_cross_size_for_intrinsic_sizing,
|
||||
IntrinsicSizingMode::Contribution,
|
||||
);
|
||||
(size.into(), true)
|
||||
|
@ -2511,7 +2503,7 @@ impl FlexItemBox {
|
|||
pbm_auto_is_zero: &FlexRelativeVec2<Au>,
|
||||
content_box_sizes: &LogicalVec2<Sizes>,
|
||||
preferred_aspect_ratio: Option<AspectRatio>,
|
||||
cross_size_stretches_to_container_size: bool,
|
||||
automatic_inline_size: Size<Au>,
|
||||
intrinsic_sizing_mode: IntrinsicSizingMode,
|
||||
) -> Au {
|
||||
let content_block_size = || {
|
||||
|
@ -2526,26 +2518,18 @@ impl FlexItemBox {
|
|||
// TODO: This is wrong if the item writing mode is different from the flex
|
||||
// container's writing mode.
|
||||
let inline_size = {
|
||||
let initial_behavior = if cross_size_stretches_to_container_size {
|
||||
Size::Stretch
|
||||
} else {
|
||||
Size::FitContent
|
||||
};
|
||||
let stretch_size =
|
||||
flex_context.containing_block.size.inline - pbm_auto_is_zero.cross;
|
||||
let get_content_size = || {
|
||||
let constraint_space = ConstraintSpace::new(
|
||||
self.inline_content_sizes(
|
||||
flex_context,
|
||||
tentative_block_size,
|
||||
style.writing_mode,
|
||||
preferred_aspect_ratio,
|
||||
);
|
||||
self.independent_formatting_context
|
||||
.inline_content_sizes(flex_context.layout_context, &constraint_space)
|
||||
.sizes
|
||||
)
|
||||
};
|
||||
content_box_sizes.inline.resolve(
|
||||
Direction::Inline,
|
||||
initial_behavior,
|
||||
automatic_inline_size,
|
||||
Au::zero,
|
||||
Some(stretch_size),
|
||||
get_content_size,
|
||||
|
@ -2597,4 +2581,18 @@ impl FlexItemBox {
|
|||
IntrinsicSizingMode::Size => content_block_size(),
|
||||
}
|
||||
}
|
||||
|
||||
fn inline_content_sizes(
|
||||
&self,
|
||||
flex_context: &FlexContext,
|
||||
block_size: SizeConstraint,
|
||||
preferred_aspect_ratio: Option<AspectRatio>,
|
||||
) -> ContentSizes {
|
||||
let writing_mode = self.independent_formatting_context.style().writing_mode;
|
||||
let constraint_space =
|
||||
ConstraintSpace::new(block_size, writing_mode, preferred_aspect_ratio);
|
||||
self.independent_formatting_context
|
||||
.inline_content_sizes(flex_context.layout_context, &constraint_space)
|
||||
.sizes
|
||||
}
|
||||
}
|
||||
|
|
|
@ -993,7 +993,7 @@ impl From<Option<Au>> for SizeConstraint {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub(crate) struct Sizes {
|
||||
/// <https://drafts.csswg.org/css-sizing-3/#preferred-size-properties>
|
||||
pub preferred: Size<Au>,
|
||||
|
|
|
@ -471,7 +471,9 @@ impl ReplacedContents {
|
|||
collapsible_margins_in_children: CollapsedBlockMargins::zero(),
|
||||
content_block_size,
|
||||
content_inline_size_for_table: None,
|
||||
depends_on_block_constraints: false,
|
||||
// The result doesn't depend on `containing_block_for_children.size.block`,
|
||||
// but it depends on `lazy_block_size`, which is probably tied to that.
|
||||
depends_on_block_constraints: true,
|
||||
fragments: self.make_fragments(layout_context, &base.style, size),
|
||||
specific_layout_info: None,
|
||||
}
|
||||
|
|
13
tests/wpt/meta/MANIFEST.json
vendored
13
tests/wpt/meta/MANIFEST.json
vendored
|
@ -172605,6 +172605,19 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"align-self-016.html": [
|
||||
"4b2bc6d2efc9f4b1c68ad33961ec97b5a7e7405b",
|
||||
[
|
||||
null,
|
||||
[
|
||||
[
|
||||
"/css/reference/ref-filled-green-200px-square.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
{}
|
||||
]
|
||||
],
|
||||
"alignment": {
|
||||
"flex-align-baseline-column-rtl-direction.html": [
|
||||
"3be57a2b34bf4c68f0041b874fbfdcecd797a20a",
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
[keyword-sizes-on-flex-item-001.html]
|
||||
[.test 57]
|
||||
expected: FAIL
|
||||
|
||||
[.test 58]
|
||||
expected: FAIL
|
||||
|
||||
[.test 59]
|
||||
expected: FAIL
|
||||
|
||||
[.test 60]
|
||||
expected: FAIL
|
||||
|
||||
[.test 61]
|
||||
expected: FAIL
|
||||
|
||||
[.test 62]
|
||||
expected: FAIL
|
||||
|
||||
[.test 63]
|
||||
expected: FAIL
|
||||
|
||||
[.test 64]
|
||||
expected: FAIL
|
||||
|
||||
[.test 65]
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[flex-line-002.html]
|
||||
[.stretch 3]
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[flex-line-003.html]
|
||||
[.stretch 3]
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[flex-line-004.html]
|
||||
[.stretch 3]
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[flex-line-005.html]
|
||||
[.stretch 1]
|
||||
expected: FAIL
|
|
@ -4,9 +4,3 @@
|
|||
|
||||
[[data-expected-height\] 37]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 21]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 44]
|
||||
expected: FAIL
|
||||
|
|
|
@ -4,9 +4,3 @@
|
|||
|
||||
[[data-expected-width\] 37]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 21]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 44]
|
||||
expected: FAIL
|
||||
|
|
|
@ -10,9 +10,3 @@
|
|||
|
||||
[[data-expected-height\]:not([skip-second-pass\]) 45]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 21]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\]:not([skip-second-pass\]) 44]
|
||||
expected: FAIL
|
||||
|
|
|
@ -10,9 +10,3 @@
|
|||
|
||||
[[data-expected-width\]:not([skip-second-pass\]) 45]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 21]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\]:not([skip-second-pass\]) 44]
|
||||
expected: FAIL
|
||||
|
|
|
@ -16,9 +16,3 @@
|
|||
|
||||
[[data-expected-height\] 46]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 21]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 44]
|
||||
expected: FAIL
|
||||
|
|
|
@ -16,9 +16,3 @@
|
|||
|
||||
[[data-expected-width\] 46]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 21]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 44]
|
||||
expected: FAIL
|
||||
|
|
46
tests/wpt/tests/css/css-flexbox/align-self-016.html
vendored
Normal file
46
tests/wpt/tests/css/css-flexbox/align-self-016.html
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Flexbox: shrink-to-fit item in multi-line column container</title>
|
||||
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#propdef-align-self">
|
||||
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/11784">
|
||||
<link rel="match" href="../reference/ref-filled-green-200px-square.html">
|
||||
<meta assert="
|
||||
#item has `align-self: start`, which sizes it as `fit-content`.
|
||||
Therefore, we initially shrink-to-fit it into the container (100px),
|
||||
thus getting a cross size of 100px and a main size of 200px.
|
||||
However, we have another item which is 200px wide, so the flex line
|
||||
grows to that size.
|
||||
Once we know the final cross size of the line, we shrink-to-fit #item
|
||||
into the line (200px), thus getting a final cross size of 200px.
|
||||
Now both floats fit side by side into these 200px, so vertically they
|
||||
only need 100px, but the main size of #item remains as 200px.
|
||||
">
|
||||
|
||||
<style>
|
||||
#container {
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
width: 100px;
|
||||
border-right: 100px solid red;
|
||||
}
|
||||
#item{
|
||||
align-self: start;
|
||||
background: linear-gradient(to bottom, red 50%, green 50%);
|
||||
}
|
||||
.float {
|
||||
float: left;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: green;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
|
||||
<div id="container">
|
||||
<div id="item">
|
||||
<div class="float"></div>
|
||||
<div class="float"></div>
|
||||
</div>
|
||||
<div style="width: 200px"></div>
|
||||
</div>
|
Loading…
Add table
Add a link
Reference in a new issue