As you can see in this simple example:
<div id="minheight">
<p id="margin">Paragraph with a margin</p>
</div>
<div id="sibling">Sibling div</div>
#minheight {
min-height: 100px;
background: red;
}
#sibling {
background: blue;
}
http://jsfiddle.net/peterbriers/B43th
There is a difference between Chrome (35) and Firefox (29) in how it handles the collapsing margins on a block with a min-height that is larger than the child's margin.
I tried to fully understand the specifications: http://www.w3.org/TR/CSS2/box.html#collapsing-margins , but I'm still unsure which browser handles this correctly. I would say Chrome is in the wrong, but Safari (7) does it the Chrome way too.
Which browser is correct, and how can I file a bug for the one that isn't doing it the right way?
BTW: I'm not asking any fix by adding new block formatting context (adding overflow property)...
OK, so this seems to be a very peculiar case.
If you change min-height to height, the gap disappears in Chrome. Not only does Safari behave the same as Chrome, but so does IE. Firefox's behavior is unique to itself, and its behavior does not change when you make that adjustment to your CSS. This should come as a surprise, as you would not expect min-height and height to behave any differently in your given scenario.
However, the spec has something interesting to say about min-height with respect to margin collapsing:
The following algorithm describes how the two properties influence the used value of the 'height' property:
[...]
These steps do not affect the real computed values of the above properties. The change of used 'height' has no effect on margin collapsing except as specifically required by rules for 'min-height' or 'max-height' in "Collapsing margins" (8.3.1).
Because you have not specified a fixed value for the height property on the same element that has a min-height, the computed value for height remains the default auto, even though the used value is floored to min-height.
Therefore the following text from section 8.3.1 applies, and the margins between the block box and its child should collapse as a result, irrespective of min-height:
Two margins are adjoining if and only if:
both belong to vertically-adjacent box edges, i.e. form one of the following pairs:
...
bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height
Note that it goes on to list some scenarios in which margins may or may not collapse:
Note the above rules imply that:
...
The bottom margin of an in-flow block box with a 'height' of 'auto' and a 'min-height' of zero collapses with its last in-flow block-level child's bottom margin if the box has no bottom padding and no bottom border and the child's bottom margin does not collapse with a top margin that has clearance.
... but it does not state what happens when the block box has height: auto and a non-zero min-height.
Based on this, it would be safe to assume that the spec should be interpreted as I am doing. Therefore it looks like Firefox is not behaving quite correctly, and all other browsers are following the spec to the letter, despite what one might expect from the behavior of height and min-height.
You can file a bug for Firefox here, although it looks like the developers have already made themselves aware of this issue.
Related
While investigating this question about clearing floats, I came across a peculiar situation with margins and clearance with a non-floating box.
According to section 8.3.1 of the spec, margin collapse should not occur when either
at least one of the elements generating the margins is a float, or
clearance is in the way.
But, consider a series of floating boxes, the last of which clears the rest:
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
div.container > div {
float: left;
width: 50px;
height: 50px;
margin: 10px;
}
div.container > div:last-child {
clear: left;
}
As you would expect, both the horizontal and vertical gaps between each box are 20 pixels wide. The vertical margins do not collapse.
However, when the clearing element is not floated, it jumps up by 10 pixels as though its top margin were collapsing with that of the float directly above it.
This behavior completely defies both conditions listed above:
There is clearance.
For clearance to occur, there must be some other float to clear in the first place. The fact that the clearing element itself is not floated shouldn't be relevant.
This behavior also seems to be consistent across all browsers, including less-than-recent versions of IE.
That said, I don't claim to know the CSS float model like the back of my hand, so... Can somebody else explain why this happens?
Never mind, I think I found it myself. Looks like the following assumption in my question was wrong (told you I don't fully grok the CSS float model):
The fact that the clearing element itself is not floated shouldn't be relevant.
In section 9.5.2, which describes the clear property, it says:
Computing the clearance of an element on which 'clear' is set is done by first determining the hypothetical position of the element's top border edge. This position is where the actual top border edge would have been if the element's 'clear' property had been 'none'.
If this hypothetical position of the element's top border edge is not past the relevant floats, then clearance is introduced, and margins collapse according to the rules in 8.3.1.
Then the amount of clearance is set to the greater of:
The amount necessary to place the border edge of the block even with the bottom outer edge of the lowest float that is to be cleared.
The amount necessary to place the top border edge of the block at its hypothetical position.
And further down that section, it says:
When the property is set on floating elements, it results in a modification of the rules for positioning the float. An extra constraint (#10) is added:
The top outer edge of the float must be below the bottom outer edge of all earlier left-floating boxes (in the case of 'clear: left'), or all earlier right-floating boxes (in the case of 'clear: right'), or both ('clear: both').
(Emphasis mine. Note that "outer edge" is synonymous with "margin edge", as described in section 8.1.)
Essentially, this means if the clearing element is not floated and its top margin alone does not push it far enough away from the floats, then the element is pushed just enough for its top border to sit right underneath the bottom margin of the float being cleared. While it would appear as if its top margin was collapsing with the bottom margin of the float, in reality the top margin doesn't have any meaningful effect because it doesn't reach the border edge of the clearing element.
Otherwise if the clearing element is floated, then its top margin is taken into account, so to speak (as consistent with the rules stated in 8.3.1).
And as I write this, I recall that in-flow non-floating elements are positioned as if the floats were never there to begin with, because floats are taken out of the normal flow. In other words, any top margin that is set on a non-floating clearing element does not take into account any floats, regardless of whether it is enough for clearance. For example, when both clear and float are set to none on the last element, it sits flush with the edges of its container in the exact same position as the first floating element, albeit behind it (note that the borders on the container block margin collapse between it and the container).
Lastly, the fact that clearance is introduced is actually not relevant in this specific situation, because clearance blocks margin collapse only when the element's margins would normally have collapsed had its clear property been set to none. Since we're talking about floats here, margin collapse should indeed never happen normally, and so whether or not the last element has clearance isn't relevant (not directly, anyway).
I am not sure if this is a bug or there is some arcane CSS rule at play here.
Basically, a margin setting on a child element will be effectuated outside its parent even when the parent is big enough to accommodate the child and it's margins completely.
Here's a small HTML document that demonstrates this: https://gist.github.com/skid/5048988.
This happens on Chrome 25, but not on Firefox 14.
From #Yosyhi comment :
Top and bottom margins of blocks are sometimes combined (collapsed) into a single margin whose size is the largest of the margins combined into it, a behavior known as margin collapsing.
Margin collapsing occurs in three basic cases:
Adjacent siblings
Parent and first/last child
Empty blocks
I've set up a test here
http://jsfiddle.net/WZyF7/11/
Firefox seems to differ from Chrome and IE7-9 on how to calculate the width. Instead of giving the content as much width as it needs, it makes the div as wide it's widest child element. This stacks the elements vertically in FF, while horizontally in other browsers.
Is there any way to make all browsers handle this the same way without setting a width to the parent element or using JS? And does anyone have information on exactly how this is calculated across browsers? (width:auto; ? )
The relevant spec bit is http://www.w3.org/TR/CSS21/visuren.html#floats where it says:
The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space. They may even make the border box of said element narrower than defined by section 10.3.3. CSS2 does not define when a UA may put said element next to the float or by how much said element may become narrower.
And the part in http://www.w3.org/TR/CSS21/visudet.html#float-width which says:
If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width.
and following. Note that the actual computation of preferred width, which is what matters here, is not all that well defined. So basically, per spec behavior in this situation is undefined.
In any case, what's happening here is that Firefox is giving the overflow: hidden block the width it should have per section 10.3.3 and then clearing it past the float, while Chrome and IE seem to take the "they may even" path. And in particular, it's assuming it will do that when computing the preferred width of the parent.
All that said, I think the Firefox behavior is more correct in this particular narrow case: your "container" is 400px wide. The "parent" has 20px of horizontal padding. The "floated" is 300px wide. The "content" has 20px of horizontal padding. That leaves 60px of width for the text inside "content", but the longest word ("available...") is about 70px wide with my fonts. In Chrome, for example, the only way "content" fits next to the "floated" is because the right padding of the "content" disappears entirely. Firefox will do the same thing if you give a fixed width to the "parent" here.... but then you're forcing a width, instead of asking the browser to pick a reasonable one via the shrink-wrap algorithm, of course.
Your best bet here is to just give the "parent" a specific width if you want it to have that width, instead of relying on shrink-wrapping to produce a width that's actually too small for the content.
Playing with css border, margin, padding and width I came across an extra pixel...
I know that the total width and height of an element is the sum of its width, border, margin and padding.
If you look at this http://jsfiddle.net/Fs8HQ/ , everything seems to work. When you click the button, moving some pixels from the border to the margin create a pseudo-animation.
Now let's set a fixed width and height in http://jsfiddle.net/Fs8HQ/1/ (remove width and height from :active): in Firefox and Chrome there is one extra-height and one extra-width pixels that move all the adjacent elements. in Opera there is one extra-width and two extra-height pixels. Where they come from?
But here http://jsfiddle.net/hJTpY/ moving the pixel from the border to the padding seems to fix everything, but the pseudo-animation is not the same.
In the first two fiddles the borders are reduced approaching to content; in the last one the borders are reduced by the contents that expands.
Why does that happen? I'm missing something?
This is a problem I noticed lately:
The default boxmodel introduced by the W3C is content-box if a proper doctype is declared (in contradiction to the Microsoft boxmodel which can be triggered by using quirks-mode in IEs).
However, lately I noticed that the browsers have UA-styles which declare box-sizing:border-box (for input-elements only?). That is why your trick does not work, because the border is accounted into the width. To fix this, you have to declare box-sizing:content-box. See this question dealing with the same problem.
You problem occurs because when you fixed the width, for instance at 100px, the box with its border will have a width of 100px (due to the box-sizing property), so your increase of margin is not compensated by a shrinking of the box, which occurs when you do not set its width.
With a fixed width, and box-sizing set as border-box, you should not modify the margin property at all to avoid the other box moving.
The easy fix is of course to set back box-sizing at content-box : http://jsfiddle.net/Fs8HQ/7/
For more information about the css box-sizing property, go there.
I've stumbled upon some behavior in CSS that is confusing to me. Let's say there are two block elements, first of them floated to the right (jsfiddle):
If the overflow property is set to hidden on the non-floated element, that element is shrunk in order to accommodate for the floated element width jsfiddle:
I actually don't have a problem with that, but I would like to know why that is happening. What I do have problem with is the following case in which after the overflow is set to hidden, width of the non-floated element is set to 100%. I tested this in IE9, Firefox 14, Opera 12, Chrome 20 and Safari 5 on Win7, and all of them except Firefox show (jsfiddle):
What I wanted and expected, and what Firefox shows, is the same as in the first picture above. So, can anyone shed some light on why all this is happening?
According to definition "If the container element is itself contained by something else, the floated div will sit on the right margin of the container."
Case 1: The .container is covering the total space available. The .content is taking all the space except the .float(the .content is not of shape rectangle here), that's what floating is. Its actually overflowing to cover the space. Its the default behaviour.
Case 2: Now you tell the .content to hide the overflow. So it hides the overflow it was earlier doing as a default behaviour.
Case 3: You tell the .content to take the full width of the parent, i.e. .container, so it ignores the overflow:hidden and just expands to fill the space.
If you are wondering the weird behaviour of overflow:hidden, check this ARTICLE