Why this behaviour (on ALL browsers) with margin-top? - html

This is my code :
HTML
<div class='father'>
<div class='son'>Son</div>
</div>
CSS
.father
{
background-color:blue;
}
.son
{
margin-top:50px;
background-color:red;
height:50px;
}
Where is the background-color blue of the father?
I know how to fix this problem (putting padding-top:1px to the father) but I'd like to know why of this behaviour!
For me it doesnt make sense, because on every browsers, not only IE, this is the behaviour.

This is a result of Collapsing Margins. You can read a good article by Eric Meyer on this topic where he illustrates this exact behavior. The following image is from his article.
Here's what the CSS2 specification has to say about it.
8.3.1 Collapsing margins
If the top and bottom margins of a box are adjoining, then it is
possible for margins to collapse through it. In this case, the
position of the element depends on its relationship with the other
elements whose margins are being collapsed.
If the element's margins are collapsed with its parent's top margin, the top border edge of the box is defined to be the same as
the parent's.
Otherwise, either the element's parent is not taking part in the margin collapsing, or only the parent's bottom margin is involved.
The position of the element's top border edge is the same as it
would have been if the element had a non-zero bottom border.
Note that the positions of elements that have been collapsed through
have no effect on the positions of the other elements with whose
margins they are being collapsed; the top border edge position is only
required for laying out descendants of these elements.
Source: http://www.w3.org/TR/CSS2/box.html#collapsing-margins

This is because the div is a block-level element. Certain block-level elements don't contain any padding by default. Divs are one such element. Block-level elements will take up the entire height and width of the container while respecting any padding it may contain.
W3C Visual formatting model
The parent element's height is set to its content's height by default. Once you set a height on the parent, that's no longer the default. Checking up on it, I believe that the padding adds to the height. So, the height is originally determined by the content unless otherwise stated in the CSS. Then, in most cases (IE 6 may be the exception), the padding is added to the height.
Good thing about SO, it helps us be much more detailed in our responses. :)

In CSS, block level elements naturally fills the elements content area, so your "son" div is filling your "father" div completely. Of course, you can bypass this by adding margin/padding/height to your parent div.

You're setting blue explicitly:
.father {
background-color:blue;
}
It's overridden (thanks to the "C" in CSS a.k.a cascading) but the style remains on your parent element (here, appropriately named "father").
If your .father box receives any height at all (check in the Firebug/Chrome dev tools inspector) than the blue is going to show through. I am guessing this is what you're seeing in IE (that or perhaps there's a flash of content before your child element style comes in). I don't think the IE debug tools show bounding boxes but you can test the element for it's height using JavaScript.

Moving outwards from the content, you have padding, border, and margin (as you probably know). Background covers only padding, but not margin.

Related

Behavior of block elements in html

I have two section elements with ids container1,container2 respectively.Both have an ul element each as their first child. section#container1 has a border.
If I set a margin for the ul elements, for section#container1(which
has a border) the margin is inside the container, for
section#container2, which has no child before ul element, the margin
is outside the container.
This happens for any first child of a parent, when the parent does not have its dimensions set.
The jsbin link of the page.
The screenshot of the page.
My question is regarding the behavior of block elements. I understand this is very basic.
If we do not set height or width of a parent block element, the
margin we set for the first child is rendered as if it is set for the
parent.
But if we have a border, then in that case the margin is set inside
the parent container and the container expands.Why is it so ?
Can any one please explain this behavior ? If you have any resource explaining such a basic behavior, please do point to that.There are many such small behaviors present, which is not mentioned in any tutorials. If any one has a list of such small things or something you learned by developing web pages please provide a link or mention in the comments or answers. This would be really helpful for beginners.
I believe you're experiencing "collapsing margins". One of the rules of collapsing margins is that a first child's top and bottom margin will not push the child away from it's container, but rather the margin will be applied to the outside of the container. It's just a rule in CSS. Some of the things you can do to the container to make this rule not apply are
Add a border
Add padding
Add overflow: auto
Read more here https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing

Adding margin-bottom to child of a min-height container has strange effects [duplicate]

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.

Removed margins above and below a <div> element?

I've come across a strange behavior related to the margins of a <div> element. I've added a very simple test case to jsFiddle to show you what I mean.
Interestingly the margins are used correctly when using a border. Is this the default behavior? Does this have something to do with collapsing margins? Is it possible to somehow force the margins without any hacks?
Least ugly solution so far that I thought of:
.cssContainer {
margin:10px;
padding:0.1px;
background-color:#FF0000;
}
But I don't know whether this will work in every browser.
This is another case of adding overflow:auto to the rescue!
jsFiddle example
Just add overflow:auto to your container div and voila, harmony is restored.
.cssContainer {
margin:10px;
padding:0px;
overflow:auto;
background-color:#FF0000;
}
From specs, the reason this works is because a new block formatting context is established by applying overflow other than visible, forcing margins of .cssContainer to not collapse with its in-flow children .cssElement.
From this site
the simplest way to stop the margin collapse from occurring is to add
padding or borders to each element. If we wanted 10px margins on each
element we could simply use a 9px margin and 1px of padding to get the
result we wanted
This is due to the CSS box model. The elements with the red backgrounds will not grow in height to accommodate the top and bottom padding of its children elements, but because the border was specified in the second example and encompasses the padding, the padding will show.
The overflow: auto; property works because the padding overflows its parent element. To illustrate this, in Google Chrome Developer Tools, find and click the HTML row for the green element whose bottom padding will not show. Chrome will highlight the element on the page. Notice how the padding is included in the highlighted element. The padding actually overflows the parent element. The parent element won't show it though because there's no content in or after the padding (no 'bounds').
From the css spec regarding box models:
Adjoining vertical margins collapse, except:
...
Horizontal margins never collapse.
Two margins are adjoining if and only if:
...
both belong to vertically-adjacent box edges, i.e. form one of the following pairs:
top margin of a box and top margin of its first in-flow child
bottom margin of box and top margin of its next in-flow following sibling
bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height
...
Note the above rules imply that:
...
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.
Unfortunately, text-overflow: auto is slightly risky because the spec says:
auto
The behavior of the 'auto' value is user agent-dependent,
but should cause a scrolling mechanism to be provided for overflowing boxes
However, all browsers that I have looked at appear to implement it in the following manner:
The box is expanded to the smaller amount between:
as much as its containing box allows
as much as is necessary to display the content without clipping
Then if clipping must occur, a scrollbar is added.

What is it with the Box Model? Child margin affecting parent

HTML and CSS boggle my mind sometimes.
A DIV with a border shows its background color for the full height of the element and its contents. Why is it that without a border, a DIV will assume (reverse inherit?) its child's margins?
As an example, here is a JSFiddle illustrating the behavior with and without borders.
http://jsfiddle.net/ahNUX
http://jsfiddle.net/ahNUX/1/
Does anyone care to explain how this is a "feature" and not some kind of bug?
Update: adding 1px of padding to the parent is a quick fix.
Sure. In CSS, by default, adjacent top and bottom margins overlap each other. This was a sensible workaround before the adjacent sibling selector (+) was thought of/became well-supported, as it meant that if you wrote h2 {margin-top: 3em;}, you’d have 3ems worth of space above your h2s even if there was a paragraph before it with a bottom margin of 1em.
In your second example, because the <div> doesn’t have any top or bottom padding or borders, its top and bottom margins are adjacent to the <h1>'s default top and bottom margins. Even though the <div>’s margins don’t have any height, they’re still treated as if they exist, and so the <h1>’s margins have to overlap them. As the <div>s margins are by definition outside of the background-color area of the <div>, the <h1>’s margins have to be positioned outside too.
In your first example, because the <div> has a border, its margins are no longer adjacent to the <h1>’s margins, so no overlapping occurs. You can get the same effect by adding top and bottom padding to the <div>: http://jsfiddle.net/ahNUX/7/
(I’m not sure what you mean about the <div> “reverse-inheriting” its child’s padding though. In your examples, neither the <div> nor the <h1> have any padding. The space inside the <div> in your first example is created by the <h1>’s top and bottom margin.)
This is a result of collapsing margins. See http://www.w3.org/TR/CSS2/box.html#collapsing-margins
In a nutshell the top and bottom margin on the <h1> element in your example may have its margin collapse (or overlap) with another element that's above or below it, which would result in a conflict with the background color, so it's not shown. On the other hand, if you have a border, the rules change.
The spec explains it pretty well, albeit in a dry and somewhat technical tone.

Why does CSS padding increase size of element?

I am trying to give my div and textarea some padding. When I do this, it increases the size of the element, instead of shrinking the content area inside of it. Is there any way to achieve what I am trying to do?
You could add box-sizing:border-box to the container element, to be able to specify a width and height that don't vary when you add padding and/or border to the element.
See here (MDN) for specifications.
Update (copied comment to answer)
Right now, the value border-box is supported in all major browsers, according to MDN Specs
Some browsers of course requires proper prefix i.e. -webkit and -moz as you can clearly see here
According to CSS2 specs, the rendered width of a box type element is equal to the sum of its width, left/right border and left/right padding (left/right margin comes into play as well). If your box has a width of '100%' and also has margin, border and padding, they will affect (increase) the width occupied by the object.
So, if your textarea needs to be 100% wide, assign values to width, margin-left/right, border-left/right and padding-left/right in such a way that their sum equals 100%.
In CSS3 we have three box-sizing models. You can use border-box model:
The specified width and height (and respective min/max properties) on
this element determine the border box of the element. That is, any
padding or border specified on the element is laid out and drawn
inside this specified width and height. The content width and height
are calculated by subtracting the border and padding widths of the
respective sides from the specified ‘width’ and ‘height’ properties.
This was a mess on W3C part and various browsers only added to this complexity with their own versions of box models. Personally, instead of thinking which browser or CSS setting will do the trick I just wrap the box' content in yet another DIV statement and use margins on that DIV, instead of using padding, like this:
<div id="container" style="width: 300px; border: 10px solid red;">
<div id="content" style="width: 250px; margin: 25px;">
Some content
</div>
</div>
Although this only works for fixed size containers
It depends on the browser and it's implementation of the box model. What you are experiencing is the correct behavior.
IE traditionally got it wrong: http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug
For a more cross-browser solution, you can avoid this behavior, by wrapping whatever tag that needs padding into another tag with fixed width, and giving it width:auto. This way, if the parent has a width of x, and you add padding to the child, the child will inherit the full width of x, applying the padding correctly without modifying the parent width or its own.
A div by default takes the width of its parent container, so to avoid browser compatibility issues, you could add a child div in the specified div then add the required padding to the child div.
N.B - don't specify width to the child div because it would increase if you add padding