Re: [css-box] margin-collapse property

On 2014-07-30 16:53, Alan Gresley wrote:
> On 31/07/2014 12:49 AM, Jonathan Rimmer wrote:
>>
>> On 2014-07-30 15:25, Alan Gresley wrote:
>>> On 30/07/2014 11:46 PM, Jonathan Rimmer wrote:
>>>>
>>>> On 2014-07-30 13:14, Alan Gresley wrote:
>>>>> On 30/07/2014 8:15 PM, Jon Rimmer wrote:
>>>>>> The box-sizing property has proven very popular as a way for
>>>>>> developers to control unintuitive default behaviour in CSS, to the
>>>>>> extent that many (most?) CSS frameworks such as Bootstrap include a
>>>>>> global box-sizing: border-box override by default.
>>>>>>
>>>>>> I believe it would be useful to provide a similar switch to control
>>>>>> margin-collapse behaviour. The default behaviour is useful in some
>>>>>> contexts, but in others, particularly collapsing margins between
>>>>>> parents and children, it is often just a pain. To that end, I
>>>>>> propose a new property margin-collapse that controls whether an
>>>>>> element is eligible for margin-collapsing. Between eligible 
>>>>>> elements,
>>>>>> margin collapsing would proceed as per the rules defined in CSS 2.1.
>>>>>>
>>>>>> The margin-collapse property would accept the following values:
>>>>>>
>>>>>> inherit Inherit from parent. Mixing with any other value is invalid.
>>>>>>
>>>>>> all Default value. Eligible for collapse with adjacent, parent and
>>>>>> child elements that are eligible for collapsing. Mixing with any
>>>>>> other value is invalid.
>>>>>>
>>>>>> none Do not collapse with any other element. Mixing with any other
>>>>>> value is invalid.
>>>>>>
>>>>>> adjacent Eligible for collapse with adjacent elements that are
>>>>>> eligible for collapsing.
>>>>>>
>>>>>> parent Eligible for collapse with parent elements that are eligible
>>>>>> for collapsing.
>>>>>>
>>>>>> children Eligible for collapse with first and last child elements
>>>>>> that are eligible for collapsing.
>>>>>>
>>>>>> The final three values would be combinable, e.g.
>>>>>>
>>>>>> .nestable { margin: 1em 0; margin-collapse: parent children; }
>>>>>
>>>>> Ok, why have you got vertical margin in this declaration as a
>>>>> shorthand when vertical margin do not collapse?
>>>> I don't follow. Vertical margins do collapse[1], and in this 
>>>> example the
>>>> elements margin-collapse is configured to be eligible for collapse 
>>>> with
>>>> parent and child elements in the DOM, just not adjacent elements.
>>>
>>> Oh, I should have said horizontal margins. :-/
>>>
>>
>> OK, well I included the horizontal = 0 to emphasise that the margins in
>> question were the vertical ones
>>
>>>>> Secondly, where should my <p> be position in the following test?
>>>>>
>>>>> <style type="text/css">
>>>>>   .wrapper { background: yellow; }
>>>>>   .float {
>>>>>     float: left;
>>>>>     width: 100px;
>>>>>     height: 100px;
>>>>>     background: blue;
>>>>>     margin-bottom: 20px;
>>>>>   }
>>>>>   p { border: 5px solid red; }
>>>>>   p.test1 { margin-collapse: all; }
>>>>>   p.test2 { margin-collapse: none; }
>>>>>   .box, .wrapper { clear: left; }
>>>>> </style>
>>>>>
>>>>> <p>A paragraph</p>
>>>>> <div class="float"></div>
>>>>> <p class="test1">Where should I be positioned with 'margin-collapse:
>>>>> all'?</p>
>>>>>
>>>>> <div class="wrapper">
>>>>>   <div class="float"></div>
>>>>>   <p class="test2">Where should I be positioned with 
>>>>> 'margin-collapse:
>>>>> none'?</p>
>>>>> </div>
>>>>>
>>>> See this illustration: http://i.imgur.com/pBTPefE.png
>>>>
>>>> The first <p> would appear as the first element in the page, with its
>>>> default 1em margin.
>>>> <p.test1> would appear exactly as it does under the current rules: It
>>>> would be flush with the top of the first <div.float>. Its top margin
>>>> would collapse with that of the first <p>.
>>>
>>> What about the <div.float>? It will still be 1em below the first
>>> paragraph?
>>
>> Sure, neither it or the first paragraph have any margin-collapse set, so
>> they are still eligible for margin-collapse, so follow the same
>> behaviour as in CSS 2.1.
>
> I have the following for the first <p>.
>
>  p.test1 { margin-collapse: all; }
>
> I have the following for the second <p>.
>
> p.test2 { margin-collapse: none; }
>
> Now what happens if the second <p> has a margin-top of 2em?
>

In that case p.test2's margin-top wouldn't eligible for collapse, so it 
would get added to whatever margins abut it. E.g. if it was adjacent to 
p1.test, there would be a gap of <p1.test> margin-bottom + <p2.test> 
margin-top between the two.

>>>> <p.test2> is ineligible for collapse, so its top margin would be added
>>>> to that of the first <div.float> above it. It would appear 1em below
>>>> that element.
>>>
>>> Then does that mean that the float is now sitting 1em above it's
>>> containing block?
>>
>> No? Its containing block is <div.wrapper>, not <p.test2>.
>
> Well the containing block for <p.test2> is also <div.wrapper> and the 
> below style prevents it from collapsing.
>
> p.test2 { margin-collapse: none; }
>
> Than means that <p.test2> is 1em below <div.wrapper> since we can not 
> have collapse through. The png here http://i.imgur.com/pBTPefE.png 
> shows that the <div.wrapper> with a yellow background is 1em below the 
> top of the float.

Ah yes, you're right. I didn't notice the yellow background was on the 
wrapper. In that case it should like this: http://i.imgur.com/FHlRhJ0.png

>>>>> Also what happens in this situation?
>>>>>
>>>>> <style type="text/css">
>>>>>   .wrapper { background: yellow; margin-collapse: none; }
>>>>>   p { border: 5px solid red; }
>>>>>   p.test1 { margin-collapse: all; }
>>>>> </style>
>>>>>
>>>>>
>>>>> <div class="wrapper">
>>>>>   <p class="test2">Which margin-collapse win?</p>
>>>>> </div>
>>>>>
>>>> <p.test2>'s margin would not collapse with the wrapper. The
>>>> <div.wrapper> has declared that its margins are ineligible for
>>>> collapsing. The <p.test2> has declared that it is eligible for
>>>> collapsing, but its margins cannot collapse with an ineligible 
>>>> element.
>>>
>>> What about if I swap the style like so?
>>>
>>> <style type="text/css">
>>>   .wrapper { background: yellow; margin-collapse: all; }
>>>   p { border: 5px solid red; }
>>>   p.test1 { margin-collapse: none; }
>>> </style>
>>>
>>
>> Same result. The <div.wrapper>'s margins are now ineligible for
>> collapse, but the <p.test>'s margins aren't. Since both elements
>> involved in a margin collapse have to 'agree' to the collapse, they
>> can't be collapsed here.
>
> So this would mean that there would be a margin of 1em above and below 
> the inner <p.test2>. What happens if I have something like as follows?
>
> #container .wrapper { background: yellow; margin-collapse: all; }
>
> How does specificity work?
>

Well, that rule is more specific that your existing .wrapper rule, but 
applies the same property values to the same elements, so makes no 
difference.

Specificity is handled in exactly the same way as for any other CSS 
property.

I think maybe what you're getting at is the idea that the wrapper could 
somehow override the margin-collapse value of the <p.test1>? That isn't 
how what I'm proposing works. The margin-collapse property only effects 
the eligibility for collapse of the elements that match the rule's 
selector. The .wrapper cannot force child elements to be eligible for 
collapse no matter the specificity of the selector. Both the parent and 
child element have to be eligible for margin collapse for a collapse 
between them to be considered.

>> The idea of the margin-collapse property isn't to say whether an
>> element's margins definitely *will* collapse, just to say that they
>> *can*. E.g. that the user agent's margin collapse algorithm can consider
>> for them for collapse. In each case, *both* elements would have to
>> eligible for collapse before a collapse between their margins was
>> considered. And even if the are both eligibile, they still follow the
>> old rules from CSS 2.1.
>>
>>>>>> There could also be separate properties margin-collapse-top and
>>>>>> margin-collapse-bottom for controlling the collapse behaviour of the
>>>>>> relevant margins.
>>>>>>
>>>>>> The primary use case for this property would be for container
>>>>>> elements that do not want their children's margins to collapse with
>>>>>> their own:
>>>>>
>>>>> That is a used case for a property and value for a 'Block Formatting
>>>>> Context'.
>>>> I don't understand what you're saying here.
>>>
>>> Margins of elements that establish new block formatting contexts (such
>>> as floats and elements with 'overflow' other than 'visible') do not
>>> collapse with their in-flow children [2].
>>
>> Right, yeah, so there are rules in CSS 2.1 around which elements can
>> collapse with each other. The idea of this property wasn't to replace
>> them, just to add a mechanism for a user to say, should this element's
>> margins even be eligible for collapse with other elements? And if so,
>> which elements? Just adjacent DOM nodes? Just parent and children nodes?
>> Etc. I think it is useful to have an explicit way to control this,
>> without the side effects of floating or setting overflow on an element.
>
> Doesn't the following work?
>
> *>*:first-child { margin-top: 0 }
>
> Also Tab has some CSS3 that has 'min-height: contain'.
>

No, the point of the use case is that you want margins on both a parent 
and a child element, not that you don't want a margin on the 
first-child. You just don't want the margins of each to collapse. 
Similarly, it isn't an issue of the parent's height not containing the 
child, it's an issue of their margins being collapsed so that the 
child's margins lie outside of the container, when you really want them 
contained within it.

> Also, why not have a new value in the margin property instead?
>
> margin-top: no-collapse;
>
> margin: 1em auto no-collapse;
>

I'm not precious about the syntax, but I'm also not sure how feasible it 
would be to overload the margin property while also allowing margin 
collapsing values of inherit, none, and combinations like "adjacent 
parent". It seems like it would be easier to read and comprehend as a 
separate property.

>>
>>>> [1] https://developer.mozilla.org/en-US/docs/Web/CSS/margin_collapsing
>>>
>>> 2.
>>> http://www.w3.org/TR/2011/REC-CSS2-20110607/box.html#collapsing-margins
>>>
>>> Alan
>>
>> Jon
>
>
> Alan

Jon

Received on Wednesday, 30 July 2014 17:12:42 UTC