I have a problem with the margin-top in a nested div -- when I apply margin-top to the nested div, the margin is applied to the parent div instead of the nested div.
Any ideas?
I get the solution with overflow:auto in the parent div.
Margins will collapse by design. Add 1px of padding as well and it should work fine.
This is how margins work.. the margin is the space between the next element with a margin / padding / similar. It is not necessarily defined as its parent element. Consult the spec.
Here are some things you can do as a workaround
Use Padding Instead
This just means instead of using margin-top: 10px; you use padding-top: 10px;. This is not suitable for every occasion.
Weird Hack I Discovered
I doubt I discovered this initially, but the other day I solved the problem like this. I had a <div id="header" /> that I wanted to give a top margin too, and its top margin was pushing the parent (body element) down as well. So I did this on the body element...
body {
padding-top: 1px;
margin-top: -1px;
}
This made my margin work. You can also try using a border, like border: 1px solid #ccc.
It would also be wise to leave a note in the CSS comments to explain why you have that peculiar pair of rules. I just added /* this is to stop collapsing margins */.
Further Reading
Check out these other questions on Stack Overflow
The reason overflow:auto changes the parent div to allow the nested margin-top is that it creates a new formatting context. Any div that's positioned absolute, fixed, floated or with overflow other than visible creates a new formatting context. The parent div then becomes the root of this new formatting context, and collapsing margins don't apply to root elements.
More in depth:
Formatting contexts can be either inline or block, and only the block formatting contexts collapse their margins. These formatting contexts form the flow of the document.
A block formatting context is simply all the block level elements (e.g. divs, p, table) laid out one after another vertically within a containing block until the end of the document/container or until a new formatting context is established.
In the case of nesting, the margin-top of the child collapses with the margin-top of the parent since both divs are part of a block formatting context. By setting overflow to auto, the parent div becomes the container of the new formatting context, and the child the first block element within it. Thus the two margins are no longer "adjoining" since the parent div is now the root.
Hope that helps.
Box model:
http://www.w3.org/TR/CSS2/box.html#collapsing-margins
Visual formatting model:
http://www.w3.org/TR/CSS2/visuren.html#normal-flow
"Collapsing margins" is your problem. Here you could understand what is and why it's still alive: http://www.sitepoint.com/web-foundations/collapsing-margins/
I read across the web to look for a decent solution, and finally I found this article: http://www.seifi.org/css/understanding-taming-collapsing-margins-in-css.html
In short you have a bunch of methods to resolve your problem:
1) border in parent div (could be transparent)
2) padding in parent div
3) overflow: auto
4) float: left
You should follow the link because it explains in detail all the solutions.
You Can also use position property for inner div to fix this. like:
position:fixed;
Related
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
MDN says:
If there is no border, padding, inline content, or clearance to separate the margin-top of a block with the margin-top of its first child block, or no border, padding, inline content, height, min-height, or max-height to separate the margin-bottom of a block with the margin-bottom of its last child, then those margins collapse. The collapsed margin ends up outside the parent.
I don't understand the last sentence. Why does the collapsed margin end up outside the parent? If it ends up outside the parent, where will it go? I have searched the web and read several tutorials about margin collapsing, but I didn't find anything about this.
I threw together this little demo to help demonstrate the way this works:
http://jsfiddle.net/9pq8bm0o/
As you can see, I've made three elements, all nested within each other. The 2 inner containers both have a top margin value of 20px, and the outermost container has a top border (one of the things that is considered a margin separator).
So what does this mean?
Because there is no separation at the top of the two child elements, there is only 20px of space in between the outermost container and BOTH of the two child elements... the inner-most child has had it's margin collapse. Conversely, that margin that is there exists within the outermost container simply because of that border.. if you remove the border, all three elements will share the same 20px of margin which will be outside of all three containers.
So why is it like this?
The best way to think about margin collapsing is like this:
Asking for a margin on an element will ensure that it has that much margin at it's top, and nothing more (unless it's forced to have more).. So looking at my example, Does the middle .parent element have 20px of space above it? Yes, it does. Does the innermost child .child have 20px of space above it? Yes, it also does... so the margin rule is being applied correctly. It doesn't matter where that space lives, as long as it is there.
Imagine that there was a border around the .parent element, but the margin was still displayed the way it is without, and then ask those same questions.. Does the .parent element have the space? Yes, but does the .child element? No, it no longer would, because there would not be 20px of space in between it and the border that is now sitting above it... So, in reality, the space does not collapse, so that both of those questions can be answered as a "yes".
I hope that helps.. it's a little less of a direct answer to your question, and more of the theory behind how it works, so to put things a bit more plainly:
tl;dr
Margin, unlike padding, is meant to add space outside of elements. Because of this, margin will always collapse to the highest parent element whenever possible, to ensure that space is always "outside". Because it is outside of the element, it can count towards multiple different elements, as they all share that "outside" space.
Heres the fiddle
When I set #two to inline-block it subtracts the 16 px of top/bottom margin from the <p> and adds it to the divs content box height so it becomes 52px instead of 20px .. why is this the case?
What you're seeing is one of the stranger cases of margin collapsing.
If the parent and children are block elements and there's nothing (padding, a border, etc.) separating their vertical margins, then those margins will collapse. Collapsed margins are when two neighboring margins aren't added (as you might expect), but instead the larger of the two is displayed. In the parent-child case, the collapsed margin ends up outside the parent. You can read more details under the section Parent and first/last child in the above link.
Setting the parent to inline-block, or float:left;ing it or a number of other things (refer to the link for a more complete list) will stop the margins from collapsing. This leads to the behavior we're used to: the child's margin will appear inside the parent, adding to its total height, and the parent's margin will also be displayed.
To elaborate, and expand on the existing answers..
This behavior is known as collapsing margins.
8.3.1 Collapsing margins
In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.
To work around this, you need to establish a new block formatting context:
9.4.1 Block formatting contexts
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.
Therefore a few different ways to establish a new block formatting would be to..
Change the overflow property of the parent element to something other than the default value, visible - (updated example)
Change the display of the element to inline-block - (updated example)
Float the element - (updated example)
This has already been answered and accepted, still I'd like to point out that clearfixing it would have prevented margin collapse thus normalizing its behaviour
I'd add:
.two:before,
.two:after {
content: " ";
display: table;
}
.two:after {
clear: both;
}
See this fiddle .
Here's the Nicholas Gallagher clearfix I've used.
Paragraphs have margins built in (in most browsers).
Try this:
p
{
margin: 0px;
}
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.
Can someone explain to me why overflow has the following effect.
In the jsfiddle below I have a Div floated to the left with a width and height set.
Next I have a Content div. You could think about this as a left navigation and a content of a site layout.
Inside the content I have two Divs which are identical apart from one has overflow:auto the other doesn't. The one with overflow:auto currently respects the floated div and shortens its width to not clash with it. Were as the other one simply keeps its full width and runs underneth the floated div.
Although the overflow:auto gives a very userful behaviour I do not understand why it cares about the floated item. I thought if a element has a certain width and the content inside that cannot fit, then it will do your requested behaviour but this is sort of applying the behaviour to the element itself
http://jsfiddle.net/9bEDj/1/
Can someone clarify this for me and explain why this is the behaviour or if it shouldn't actually be doing this and its a quirk!
Here is a fabulous description on the float/overflow magic
http://colinaarts.com/articles/the-magic-of-overflow-hidden/
It's the intended behaviour that elements with overflow other than visible should respect the floats, so you can use it with not causing any fuzz
It happens because setting overflow establishes a new block formatting context, and block formatting contexts do not overlap floats.