Skip to content

[css-sizing] Stretch size with margins, in block with inline parent #13260

Closed

Description

@Loirooriol

https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing

If this is a block axis size, and the element is in a Block Layout formatting context, and the parent element does not have a block-start border or padding and is not an independent formatting context, treat the element’s block-start margin as zero for the purpose of calculating this size. Do the same for the block-end margin.

In #11044 we didn't consider what happens if the block is inside an inline formatting context.

<!DOCTYPE html>
<style>
section { display: inline-block }
article { width: 100px; height: 100px; margin: 25px }
.border > article { border: solid; }
.outline > article { outline: solid; }
div { margin: 25px; height: stretch; background: cyan; }
</style>
<section class="border">
  <article>
    <div></div>
  </article>
  <article>
    <span>
      <div></div>
    </span>
  </article>
  <article>
    <span style="border: solid magenta">
      <div></div>
    </span>
  </article>
</section>
<script>
let section = document.querySelector("section");
let clone = section.cloneNode(true);
clone.className = "outline";
section.after(clone);
</script>
Blink Servo (Option 3) Option 1
Image Image Image

The Blink behavior follows from the fact that a block-level inside an inline gets wrapped inside an anonymous block. This anonymous block is then the parent and has no border nor padding, and doesn't establish a BFC.

But it seems weird to me, because the stretch size comes from the containing block.

So if the block is inside an inline, I think we should either:

  1. Check the containing block, instead of the inline or anon-block parent
  2. Check the containing block and any inline between the containing block and the element
  3. Never treat the margins as zero

Servo used to do (1), because we split the inline, so the parent was actually the containing block. Now we no longer split inlines but we don't use anon blocks like Blink, so we do (3).

@davidsgrogan

Activity

  1. davidsgrogan commented on Dec 23, 2025

    @davidsgrogan
    Member

    But it seems weird to me, because the stretch size comes from the containing block.

    That inconsistency doesn't seem great, agreed. @bfgeek in case he has any insight into best behavior here.

  2. moved this from Agenda+ FTF to Wednesday morning in CSSWG summer 2026 meeting agendaon Aug 1, 2026
  3. bfgeek commented on Aug 3, 2026

    @bfgeek

    Servo's behaviour seems fine here.

  4. Loirooriol commented on Aug 3, 2026

    @Loirooriol
    ContributorAuthor

    I think that always (*) considering margins like Servo makes more sense than always (*) treating them as 0 like Blink.
    (*): For the purpose of finding the stretch size

    But I have been thinking that ideally, the 2nd row should look like the 1st one, i.e. wrapping things inside a non-styled inline box should be no-op. It's probably fine to not check these inline ancestors for borders or such, because only the fragments before and after the block-level will have them, and they are like uncles in the fragment tree. We already agreed to ignore siblings, so ignoring uncles seems fine.

  5. css-meeting-bot commented on Aug 5, 2026

    @css-meeting-bot
    Member

    The CSS Working Group just discussed [css-sizing] Stretch size with margins, in block with inline parent, and agreed to the following:

    • RESOLVED: Resolve the margin behavior against the same containing block that we resolve percentages against
    The full IRC log of that discussion <emilio> astearns: ian does let's do what servo does
    <emilio> oriol: I'd like something else
    <emilio> ... some context
    <emilio> ... if you have a block level element that's stretching, that doesn't look good if margins collapse
    <emilio> ... we resolved that if the margins would collapse based on some heuristics
    <emilio> ... then we'd treat the margins as 0 for stretch
    <emilio> ... it's not exactly checking for collapsing
    <emilio> ... it doesn't check what happens if the block is inside an inline
    <emilio> ... so blink has an anonymous block for this and blink thinks always the margins will collapse
    <emilio> ... so element stretches to a bigger size that then overflows
    <emilio> ... because the element doesn't stretch against the anon parent but the containing block
    <emilio> ... you can check the issue for test-cases
    <emilio> ... left is using borders which prevent margin-collapsing, right outline which doesn't
    <emilio> ... as you can see in the border case blink overflows
    <emilio> ... what I did in servo was to always consider margins
    <emilio> ... so never treat as zero
    <emilio> ... but if you're using outlines it doesn't fill the block
    <emilio> ... I think the servo behavior makes more sense than Blink's but I don't think it's ideal
    <emilio> ... second row should ideally look the same as the first
    <emilio> ... this would mean that instead of checking the parent we'd check the containing block
    <TabAtkins> Q+
    <emilio> ... there's the question for the inline levels whether they have borders or that
    <emilio> ... I think it's fine not to check them
    <emilio> ... the inline elements would end up fragmented before / after / around the block levels
    <emilio> ... the fragments around won't get padding / border
    <emilio> ... but in the fragment tree they're effectively uncles
    <emilio> ... so if we're ignoring siblings which we resolved already
    <emilio> ... seems fine to ignore uncles too
    <emilio> ... proposed resolution would be option 1 in the issue
    <emilio> ... it'd change the spec to say the conditions would be checked on the containing block rather than the parent box
    <emilio> ... which is what the element is stretching against
    <astearns> ack fantasai
    <emilio> fantasai: which is the same thing we resolve percentages around right?
    <astearns> ack TabAtkins
    <emilio> ... I agree, we should resolve this against the same element
    <emilio> ... that we resolve percents against
    <emilio> TabAtkins: I agree, I think the parent wording might've been a mistake
    <emilio> PROPOSED: Check the containing-block instead of the parent
    <fantasai> PROPOSED: Resolve the margin behavior against the same containing block that we resolve percentages against
    <emilio> +1
    <fantasai> RESOLVED: Resolve the margin behavior against the same containing block that we resolve percentages against
  6. Loirooriol commented on Aug 5, 2026

    @Loirooriol
    ContributorAuthor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions