This question already has answers here:
CSS: Margin-top when parent's got no border
(7 answers)
Impact of border property on top margin
(3 answers)
Why does this CSS margin-top style not work?
(14 answers)
Margin on child element moves parent element
(18 answers)
CSS margin terror; Margin adds space outside parent element [duplicate]
(7 answers)
Closed 5 years ago.
I have a p element with a paragraph of text inside a div element. Without a border on the div element, the p element is positioned in the top-left corner, but if I add a border to the div element it "pushes down" the paragraph from the top edge (not the left edge, however).
Why does this occur?, and is there a method of preventing this?
html,
body {
height: 100%;
}
div {
min-width: 300px;
max-width: 500px;
min-height: 200px;
max-height: 450px;
height: 100%;
background-color: Pink;
}
div.first {
border-width: 2px;
border-style: solid;
border-color: Black;
}
p {
width: 75%;
height: 75%;
background-color: Black;
color: White;
}
<div class="first">
<p class="one">Paragraph one text...</p>
</div>
<div class="second">
<p class="two">Paragraph two text...</p>
</div>
UPDATE:
You can prevent this movement by adding margin: 0; to the style of your p tag. See below for an explanation of how and why this happens.
The reason your p tag gets pushed down is because of margin collapsing (or, rather, margins not collapsing when you set a border).
See this page for a more in-depth explanation of how it works. From that page:
The top and bottom margins of blocks are sometimes combined (collapsed) into a single margin whose size is the largest of the individual margins (or just one of them, if they are equal), a behavior known as margin collapsing. Note that the margins of floating and absolutely positioned elements never collapse.
Basically, your margins are getting collapsed by the browser when you don't have a border set, yet they are calculated when you do set that border.
For ways to prevent the browser from collapsing margins, see this question. From that question (first part originally quoted from this other question):
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;
}
This is related to margin collapse.
The margin on the <p> element collapses with it's parent.
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.
Note that:
Adjoining vertical margins collapse... if and only if... no line boxes, no clearance, no padding and no border separate them.
In order to prevent margin collapse on both of your examples, you can use methods other than border. For example, overflow:auto:
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.
html,
body {
height: 100%;
}
div {
min-width: 300px;
max-width: 500px;
min-height: 200px;
max-height: 450px;
height: 100%;
background-color: Pink;
overflow: auto;
margin: 0 0 1em;
}
div.first {
border-width: 2px;
border-style: solid;
border-color: Black;
}
p {
width: 75%;
height: 75%;
background-color: Black;
color: White;
}
<div class="first">
<p class="one">Paragraph one text...</p>
</div>
<div class="second">
<p class="two">Paragraph two text...</p>
</div>
See also:
Mastering margin collapsing.
What You Should Know About Collapsing Margins.
Related
This question already has answers here:
CSS margin terror; Margin adds space outside parent element [duplicate]
(7 answers)
Why does this CSS margin-top style not work?
(14 answers)
How do I uncollapse a margin? [duplicate]
(5 answers)
Closed 4 years ago.
HTML
<div class='parent'>
<div class='child'>
Hi
</div>
</div>
CSS
.parent {
background-color: #e5e5e5;
}
.child {
background-color: #999999;
margin: 20px;
}
When this renders, the top and bottom margin on the child div is missing.
After applying the following styles to the .parent class, margins reappear. Why is this?
.parent {
margin: -1px;
padding: 1px;
}
https://jsfiddle.net/trxek0kc/2/
In some cases, top and bottom margins are collapsed. You can read more about it here. What's happening is this:
If there is no border, padding, inline part, block formatting context created, or clearance to separate the margin-top of a block from the margin-top of its first child block, [...] then those margins collapse. The collapsed margin ends up outside the parent.
Hey If I understand correctly, You have to add padding to parent element rather than giving margin to the child element. Then you will get your desired result.
.parent {
background-color: #e5e5e5;
padding: 20px;
}
.child {
background-color: #999999;
}
or you can add add overflow property to parent element
.parent {
background-color: #e5e5e5;
overflow: hidden;
}
it's not missing but it's applied to the body,
see more details here : collapsing margins
In simple terms, this definition indicates that when the vertical margins of two elements are touching, only the margin of the element with the largest margin value will be honored,
I was playing around with making my page occupy the full viewport with this basic
html {
height: 100%;
}
body {
min-height: 100%;
}
but I noticed that when I added a block element with a margin, the page sizing was off by the amount of the margin. To demonstrate, try this html in a webkit browser:
<html style="height: 100%; margin: 0; padding: 0;">
<body style="min-height: 100%; margin: 0; padding: 0;">
<h1 style="margin-top: 100px;">Box Sizing</h1>
</body>
</html>
You will notice that the body always overflows the html element, causing it to scroll. Does anybody know why this is overflowing?
This is known as collapsing margins. The vertical margin on the h1 element is collapsing with the body element, which causes the adjoining margins to combime and form a single margin, thereby resulting in the body element being shifted down (as though it has a margin-top of 100px.
According to section 8.3.1 of the relevant spec, the following rule(s) prevent the margins from collapsing:
Margins of inline-block boxes do not collapse (not even with their in-flow children).
Therefore you could simply set the display of the element to inline-block and then add width: 100%. You could also float the element as well:
Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
In the updated example below, I simply set the display of the h1 element to inline-block so that the margins no longer collapse.
html {
height: 100%;
}
body {
min-height: 100%;
margin: 0;
}
h1 {
margin-top: 100px;
display: inline-block;
width: 100%;
}
<h1>Box Sizing</h1>
See the spec I linked to for a more detailed explanation along with additional workarounds and rules that prevent the margins from collapsing.
As you can see in the demo below, margin: auto; centers the blue div horizontally, but not vertically. Why not?
.box {
border: 1px solid red;
width: 100px;
height: 100px;
}
.center {
background: blue;
width: 50px;
height: 50px;
margin: auto;
}
<div class="box">
<div class="center"></div>
</div>
My question is not asking for workarounds.
As mentioned, this behavior is specified in section 10.6.2 of CSS2.1, and has remained unchanged from CSS2.
Block boxes are stacked vertically from top to bottom in normal flow. Furthermore, vertical margins may collapse, and only do so under certain circumstances (in your demo, the border on the parent element will prevent any margins on the child element from collapsing with its own). If you only have one such block box, and the height of the containing block is auto, then its top and bottom margins will be zero anyway. But if you have more than one block box in the same flow, or even out-of-flow boxes affecting the layout of in-flow boxes (in the case of clearance for example), how would you expect auto margins to resolve for those in-flow boxes?
This is why auto left and right margins are likewise zeroed out for inline elements (including atomic inlines) and floats (though horizontal margins never collapse). Inline-level boxes are laid along line boxes, and floats too obey unique layout rules.
Absolutely positioned boxes are a different story: since they are never aware of any other boxes in the same positioning context as themselves, auto top and bottom margins can be calculated for them with respect to their containing blocks without having to worry about any other boxes ever interfering.
Flexbox is also a different story: what sets flex layout apart from block layout is that flex items are by definition always aware of other flex items in the same flex formatting context, including the fact that there are none. In particular, neither can floats intrude into the flex container, nor can you float flex items to subvert this (although you can still remove a child element from flex layout completely with absolute positioning). Margins behave very differently with flex items due in part to this. See sections 4.2, 9.5 and 9.6.
Why...because the W3C spec says so.
If 'margin-top', or 'margin-bottom' are 'auto', their used value is 0.
As to the actual "why"...the query should really be addressed there.
It doesn't center the element vertically because it is a block-level element in the normal flow. Thus, the following rule applies:
If margin-top, or margin-bottom are auto, their used value is 0.
It's also worth pointing out that the rule above also applies to the following elements as well: (see points 10.6.2 and 10.6.3 for more information and conditions).
Inline replaced elements
Block-level replaced elements in normal flow
inline-block replaced elements in normal flow
Floating replaced elements
Block-level non-replaced elements in normal flow when overflow computes to visible
With that being said, absolutely positioned, non-replaced elements that don't have top, height, and bottom values of auto are an exception to this rule. The following applies from point 10.6.4:
If none of the three top, height, and bottom are auto and if both margin-top and margin-bottom are auto, solve the equation under the extra constraint that the two margins get equal values.
See the example below demonstrating how an absolutely positioned element is vertically centered using margin: auto. It works because none of the three properties top, height, and bottom have a value of auto:
.box {
border: 1px solid red;
width: 100px;
height: 100px;
position: relative;
}
.center {
background: blue;
width: 50px;
height: 50px;
margin: auto;
position: absolute;
top: 0; right: 0;
bottom: 0; left: 0;
}
<div class="box">
<div class="center"></div>
</div>
In addition, it's probably worth pointing out the following rule as well:
If one of margin-top or margin-bottom is auto, solve the equation for that value. If the values are over-constrained, ignore the value for bottom and solve for that value.
This means that if the absolutely positioned element has a margin-top value of auto and a margin-bottom value of 0 (i.e., margin: auto auto 0), the element would be absolutely positioned at the bottom relative to the parent like in the example below:
.box {
border: 1px solid red;
width: 100px;
height: 100px;
position: relative;
}
.center {
background: blue;
width: 50px;
height: 50px;
margin: auto auto 0;
position: absolute;
top: 0; right: 0;
bottom: 0; left: 0;
}
<div class="box">
<div class="center"></div>
</div>
Why doesn't margin:auto work vertically?
Actually, it does – just not for every display value.
If display is flex, margin: auto centers both vertically and horizontally.
The same applies to display: inline-flex, display: grid and display: inline-grid.
.box {
border: 1px solid red;
width: 100px;
height: 100px;
display: flex; /* new */
}
.center {
background: blue;
width: 50px;
height: 50px;
margin: auto;
}
<div class="box">
<div class="center"></div>
</div>
It's because of the actual possibility of knowing the true height of the element in which you want to center vertically in. To understand that, first think about how auto horizontal centering works. You have a div which you've given it a width (fixed or percentage). The width can be calculated to certain degree. If it's fixed width, great. If it's flexible or responsive (percentage) at least you have a range that the width will cover before it hits the next breakpoint. You take that width, minus whatever it's inside and split the remainder on both sides.
Now, with that information, how could the browser calculate the infinite amount of variations in which your div will grow vertically? Keep in mind the size of the element, wrapping of text, paddings, and responsiveness will also alter the width and force the text to wrap further, and on, and on it goes.
Is it an impossible task? Not really, has CSS spent time and effort covering this? Not worth their time, I guess.
And that is basically the answer I tell my students.
But....fret not! Bootstrap v4 alpha has figured out vertical centering!
EDIT
Sorry to edit this late but I thought you may want to consider this solutions to center vertically and it is pretty simple by making use of the calc function
<div class="foo"></div>
.foo {
background-color: red;
height: 6em;
left: calc(50% - 3em);
position: absolute;
top: calc(50% - 3em);
width: 6em;
}
See it HERE
Ok, we can clearly see that there is a space between the top and the <div>. Now, I know this is cause by the margin/padding of the <p> element, but why does it appear outside of the <div> and not inside of it?
body{
margin: 0px;
padding: 0px;
background-color: #808080;
}
#top-wrapper{
background-color: #ffffff;
margin: 0px;
padding: 0px;
}
<body>
<div id="top-wrapper">
<p>hello</p>
</div>
</body>
This is due to margin collapsing.
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.
To (prevent this and) provide the behaviour you anticipate, add overflow: auto; to the div, or alternatively overflow:hidden; This enforces the block formatting context
Demo Fiddle
A block formatting context is a part of a visual CSS rendering of a
Web page. It is the region in which the layout of block boxes occurs
and in which floats interact with each other.
body {
margin: 0px;
padding: 0px;
background-color: #808080;
}
#top-wrapper {
background-color: #ffffff;
margin: 0px;
padding: 0px;
overflow: auto;
}
<body>
<div id="top-wrapper">
<p>hello</p>
</div>
</body>
This is the expected behavior. This is because the top margin of paragraph collapsed with the top margin of its parent div (and likewise for bottom margin). This causes the div to appear as if it has a margin.
Margin collapsing is described here:
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.
I have a div container which has a h1 element within it:
<div id="header">
<h1>Enlighten Designs</h1>
</div>
I have applied a margin-top,a margin-left and a margin-right to the header element.
However the margin-top is not being applied to the header element box wrt to the containing div.
Instead the top margin is being applied to the containing div.
The left and right margins of the header are being applied to the header element box wrt the containing div.
The style rules for the div and header are as follows:
#header {
background: blue;
height: 150px;
}
h1{
background: orange;
margin-top:30px;
margin-left: 10px;
margin-right: 10px;
}
What is the reason for this behavior?
Your 'problem' is that margins in CSS will collapse onto eachother.
Read this awesome article explaining the concept, management summary:
In simple terms, this definition indicates that when the vertical
margins of two elements are touching, only the margin of the element
with the largest margin value will be honored, while the margin of the
element with the smaller margin value will be collapsed to zero.
In your case, specifically read the section "Collapsing Margins Between Parent and Child Elements" a few pages down. In your case, the following CSS 2.1 rule applies:
The top margin of an in-flow block element collapses with its first
in-flow block-level child's top margin if the element has no top
border, no top padding, and the child has no clearance.
Well, the solution is to add overflow: hidden; property to your header element.
Here JsFiddle.
#header {
background: blue;
height: 150px;
position:absolute;
}
h1{
background: orange;
margin-top:30px;
margin-left: 10px;
margin-right: 10px;
position:relative;
}