Why does <p> put space outside of <div>? - html

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.

Related

Adding a border "pushes down" contents [duplicate]

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.

Webkit Extra Space at the top of the 'body' element when setting a margin-top on a descendant element

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.

margin on h1 element inside a div

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;
}

Unexpected behavior of css float

Here is my jsFiddle
I just have 3 divs. The 2nd div is floated to the right, and 3rd div appears just below the 2nd.
In the 3rd div, I am setting margin-top property, and this property does not have any effect on the layout.
Question: Can someone explain me understanding this behavior of float?
HTML
<div class="header">
</div>
<div class="sidebar">
</div>
<div class="footer">
</div>
CSS
.header {
width: 100%;
height: 80px;
background-color: #abcdef;
}
.sidebar {
margin-top: 15px;
float: right;
width: 200px;
height: 200px;
background-color: #abcdef;
display: block;
}
.footer {
clear: both;
margin-top: 20px;
width: 100%;
height: 60px;
background-color: #000000;
}
This is not unexpected at all. The .sidebar is removed from regular flow layout by its float property, as such it doesn't take up any space anymore. The .footer has a clear rule, so it is forced underneath any floats, but that automatically puts it 215px (margin+height of the sidebar) behind the last element that is part of the flow layout. As such its margin requirement of 20px is completely satisfied, and it appears at its logical current position. You can verify this by setting the top margin to 220px instead, it will appear 5px (220-215) below the sidebar.
You can easily achieve the effect you desire by putting margin-bottom:20px on the sidebar since it will then be required to keep that distance to the footer, pushing it down.
The issue is related to the clear rule.
W3C - An element that has had clearance applied to it never
collapses its top margin with its parent block's bottom margin.
Baiscally, if you want to use clear, the general rule is to add an element between the two floated divs to ensure you can correctly space them.
The top margin of the footer div is being collapsed, http://www.w3.org/TR/CSS21/box.html#collapsing-margins
If you add margin-bottom to the sidebar instead of the top of the footer it will work.
This is caused by the fact that floated elements aren't really there with respect to margin calculations. Your .footer is below whatever unfloated elements are above it, (with a margin of 20px). This issue is caused because margins with respect to floats are calculated relative to other floats, (not all other elements).
So to get the desired effect add a margin-bottom element to .sidebar, have a meaningless float added to the .footer, or add a
<div style="clear:both"></div>
between the .footer and .sidebar

unexpected margin with very simple html

I have a very simple html. The red div is inside the blue div and has a 10 px top margin. On non-ie browsers, the blue box is 10 px apart from the top of viewport and the red div is at the very top of the blue div. What I expect is the ie behavior: red div must be 10 px apart from the top of the blue div. Why does non-ie browsers render like this? (I suppose the wrong behavior is the IE's but why?)
And, what is the correct way to do this?
why blank? http://img92.imageshack.us/img92/7662/blankmr7.jpg
<html>
<head>
<style>
body { margin:0; padding:0; }
.outer
{
background-color: #00f;
height: 50px;
}
.inner
{
height: 20px;
width: 20px;
background-color: #f00;
margin: 10px 0 0 10px;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
</div>
</div>
</body>
</html>
As much as strager's answer already explains about as much as you need to know as to why it happens – namely that it happens the way it does in browsers other than IE because the specs say so – I think he picked the wrong quote from the section of the CSS 2.1 specification about collapsing margins.
The point he quoted explains how margins can collapse, not how they can "move" to a parent element.
This is rather what explains it:
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.
Or, in slightly more human-readable form in the Mozilla developer documentation:
Parent and first/last child:
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.
As for how to fix it, I'd probably go for the overflow: auto solution Chris Lloyd suggested (as much as that may have side-effects).
But then that really depends on what exactly the rest of your code looks like. In this simple example you could easily just change the margin on the child element to a padding on the parent element.
Or you could float the child element, or absolutely position it...
Or how about an inverse clearfix if you want to get really fancy:
.outer:before {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
The margins are being merged. The output produced by IE is probably incorrect.
In the specifications (which are down for me at the moment):
Two or more adjoining vertical margins of block boxes in the normal flow collapse. The resulting margin width is the maximum of the adjoining margin widths.
You can use borders instead of margins, with border-color set to transparent.
There is a pretty fitting answer to this question: overflow: auto;
<html>
<head>
<style>
body { margin:0; padding:0; }
.outer
{
background-color: #00f;
height: 50px;
overflow: auto;
}
.inner
{
height: 20px;
width: 20px;
background-color: #f00;
margin: 10px 0 0 10px;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
</div>
</div>
</body>
</html>
Could it be IE sees the DOM as div.inner having div.outer as it's parent node(and calculates offset from it),
and that other browsers instead has both of them answering to the body element?
Ok, solution without overflow auto:
<html>
<head>
<style>
body { margin:0; padding:0; }
.outer
{
background-color: #00f;
height: 50px;
border: 1px solid transparent;
}
.inner
{
height: 20px;
width: 20px;
background-color: #f00;
margin: 10px 0 0 10px;
padding: 0;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
</div>
</div>
</body>
</html>
The inner element is wanting something to push against, and providing a boder (or forcing the browser to consider the overflow) does this.