Title!
Paragraph
I have a div
(parent) that contains another div
(child). Parent is the first element in body
with no particular CSS style. When I set
.child
{
margin-top: 10px;
}
The end result is that top of my child is still aligned with parent. Instead of child being shifted for 10px downwards, my parent moves 10px down.
My DOCTYPE
is set to XHTML Transitional
.
What am I missing here?
edit 1 My parent needs to have strictly defined dimensions because it has a background that has to be displayed under it from top to bottom (pixel perfect). So setting vertical margins on it is a no go.
edit 2 This behaviour is the same on FF, IE as well as CR.
Found an alternative at Child elements with margins within DIVs You can also add:
.parent { overflow: auto; }
or:
.parent { overflow: hidden; }
This prevents the margins to collapse. Border and padding do the same. Hence, you can also use the following to prevent a top-margin collapse:
.parent {
padding-top: 1px;
margin-top: -1px;
}
2021 update: if you're willing to drop IE11 support you can also use the new CSS construct display: flow-root
. See MDN Web Docs for the whole details on block formatting contexts.
Update by popular request: The whole point of collapsing margins is handling textual content. For example:
h1, h2, p, ul { margin-top: 1em; margin-bottom: 1em; outline: 1px dashed blue; } div { outline: 1px solid red; }
Paragraph
Paragraph
Because the browser collapses margins, the text would appear as you'd expect, and the <div>
wrapper tags don't influence the margins. Each element ensures it has spacing around it, but spacing won't be doubled. The margins of the <h2>
and <p>
won't add up, but slide into each other (they collapse). The same happens for the <p>
and <ul>
element.
Sadly, with modern designs this idea can bite you when you explicitly want a container. This is called a new block formatting context in CSS speak. The overflow
or margin trick will give you that.
This is normal behaviour (among browser implementations at least). Margin does not affect the child's position in relation to its parent, unless the parent has padding, in which case most browsers will then add the child's margin to the parent's padding.
To get the behaviour you want, you need:
.child {
margin-top: 0;
}
.parent {
padding-top: 10px;
}
.parent {border: solid 1px;}
Although all of the answers fix the issue but they come with trade-offs/adjustments/compromises like
floats, You have to float elements
border-top, This pushes the parent at least 1px downwards which should then be adjusted with introducing -1px margin to the parent element itself. This can create problems when parent already has margin-top in relative units.
padding-top, same effect as using border-top
overflow: hidden, Can't be used when parent should display overflowing content, like a drop down menu
overflow: auto, Introduces scrollbars for parent element that has (intentionally) overflowing content (like shadows or tool tip's triangle)
The issue can be resolved by using CSS3 pseudo elements as follows
.parent::before {
clear: both;
content: "";
display: table;
margin-top: -1px;
height: 0;
}
https://jsfiddle.net/hLgbyax5/1/
margin-top: -1px
seems to be unnecessary. But I like this.
margin-top: -1px
and height: 0
seems unnecessary. Tested in Chrome. But best solution.
.parent:after...
add style display:inline-block
to child element
the parent element has not to be empty at least put
before the child element.
This is what worked for me
.parent {
padding-top: 1px;
margin-top: -1px;
}
.child {
margin-top:260px;
}
To prevent "Div parent" use margin of "div child": In parent use these css:
Float
Padding
Border
Overflow
Neat CSS-only solution
Use the following code to prepend a contentless first-child to the unintentionally moving div:
.parent:before
{content: '';position: relative;height: 0px;width: 0px;overflow: hidden;white-space: pre;}
The advantage of this method is that you do not need to change the CSS of any existing element, and therefore has minimal impact on design. Next to this, the element that is added is a pseudo-element, which is not in the DOM-tree.
Support for pseudo-elements is wide-spread: Firefox 3+, Safari 3+, Chrome 3+, Opera 10+, and IE 8+. This will work in any modern browser (be careful with the newer ::before
, which is not supported in IE8).
Context
If the first child of an element has a margin-top
, the parent will adjust its position as a way of collapsing redundant margins. Why? It's just like that.
Given the following problem:
<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
</style>
<div class="parent"><!--This div moves 40px too-->
<div class="child">Hello world!</div>
</div>
You can fix it by adding a child with content, such as a simple space. But we all hate to add spaces for what is a design-only issue. Therefore, use the white-space
property to fake content.
<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
.fix {position: relative;white-space: pre;height: 0px;width: 0px;overflow: hidden;}
</style>
<div class="parent"><!--This div won't move anymore-->
<div class="fix"></div>
<div class="child">Hello world!</div>
</div>
Where position: relative;
ensures correct positioning of the fix. And white-space: pre;
makes you not having to add any content - like a white space - to the fix. And height: 0px;width: 0px;overflow: hidden;
makes sure you'll never see the fix.
You might need to add line-height: 0px;
or max-height: 0px;
to ensure the height is actually zero in ancient IE browsers (I'm unsure). And optionally you could add <!--dummy-->
to it in old IE browsers, if it does not work.
In short, you can do all this with only CSS (which removes the need to add an actual child to the HTML DOM-tree):
<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
.parent:before {content: '';position: relative;height: 0px;width: 0px;overflow: hidden;white-space: pre;}
</style>
<div class="parent"><!--This div won't move anymore-->
<div class="child">Hello world!</div>
</div>
overflow: hidden;
for the parent.
I find out that, inside of your .css >if you set the display property of a div element to inline-block it fixes the problem. and margin will work as is expected.
Play with display of parent
.parent{
display: inline-block;
width: 100%;
}
or
.parent{ display: flex; }
The margin
of the elements contained within .child
are collapsing.
<html>
<style type="text/css" media="screen">
#parent {background:#dadada;}
#child {background:red; margin-top:17px;}
</style>
<body>
<div id="parent">
<p>&</p>
<div id="child">
<p>&</p>
</div>
</div>
</body>
</html>
In this example, p
is receiving a margin
from the browser default styles. Browser default font-size
is typically 16px. By having a margin-top
of more than 16px on #child
you start to notice it's position move.
I had this problem too but preferred to prevent negative margins hacks, so I put a
<div class="supercontainer"></div>
around it all which has paddings instead of margins. Of course this means more divitis but it's probably the cleanest way to do get this done properly.
interestingly my favorite solution to this problem isn't yet mentioned here: using floats.
html:
<div class="parent">
<div class="child"></div>
</div>
css:
.parent{width:100px; height:100px;}
.child{float:left; margin-top:20px; width:50px; height:50px;}
see it here: http://codepen.io/anon/pen/Iphol
note that in case you need dynamic height on the parent, it also has to float, so simply replace height:100px;
by float:left;
An alternative solution I found before I knew the correct answer was to add a transparent border to the parent element.
Your box will use extra pixels though...
.parent {
border:1px solid transparent;
}
Using top
instead of margin-top
is another possible solution, if appropriate.
Success story sharing
<h2>
,<p>
,<ul>
won't get strange gaps or "double" margins this way.margin: 5px 10px;
id expect 2 divs 5 px from the top and 20px between them not 5 px from the top and 10px between them. if i wanted 10 px between them id have specifiedmargin: 5px 5px;
. i honestly wish there was a root rule i could place that would stop all margin collapsing. i hate that i have to double the size of the margins on paper to get them to actually do what the heck i want on screen. and this top thing... what a disaster