I'm having a problem with the page elements moving when I add a border in a HTML 5 document.
I expected the containing header element (grey) to appear at the top of the screen, but it seems to take the margin from the inner div (red). However if I add a border to the header it appears where I expect and the red inner div only moves slightly!
(1st image: without border; 2nd image: with border)
I have tried setting relative or absolute positioning, using a div instead of the header element, setting margins & padding to 0, using a HTML4 doctype etc. The HTML validates. This is the HTML stripped of everything and still doesn't work. Its happening in latest Chrome & FF.
HELP!! What have I missed?? Or any workarounds (other than keeping the border)?
HTML:
<!DOCTYPE HTML>
<html>
<head>
<title>Test</title>
</head>
<body>
<header><div id="mydiv"></div></header>
<div id="content"><p>hello</p></div>
</body>
</html>
CSS:
header {background-color:#CCCCCC; width:960px; height:430px;}
#mydiv {width:960px; height:320px; margin:80px 0px 0px 0px; background-color:#CC0000; }
The issue comes from something called "margin collapsing". It's simple: 2 adjoining margins collapse to the highest of the two (I say two, but it could be more).
In your case, '#mydivs' margin-top - 80px - is touching the 'header's margin-top - 0px. They're adjoining - there's no element between them, nor padding, nor border.
The margins collapse, therefore, to the highest of the two (80px), and it is then applied on the highest of the elements in the parent-child hierarchy - that's the header in this case.
One solution to this problem is to put something between the margins; either of some padding, or a border on the header works fine.
header {
border-top: 0.1em solid rgba(0,0,0,0);
}
A second solution (my preferred one), is to make the parent element create a new block formatting context. That way, its margins simply won't collapse with that of its child.
How do you create a block formatting context?
There are four possible ways.
by floating it.
"position absoluting it".
adding one of these displays: “table-cell”, “table-caption”, or “inline-block".
adding an overflow other than visible.
To prevent the margins from collapsing you could do any of these 4. I usually go for number 4) - set overflow to auto, as it's only side affect... well it's improbably likely to become a problem.
header {
overflow: auto;
}
That's basically it for parent-child margin collapsing. There's also margin collapsing between siblings and the rule is pretty much the same: 2 adjoining margins collapse to the highest of the two. It's the solutions that are not.
Here's a great explanation of margin-collapsing - http://www.howtocreate.co.uk/tutorials/css/margincollapsing
This is known as collapsing margins. They can be overcome by adding padding to the parent element (in this case, the <header>).
Code (with padding, without padding):
Notice the padding:0.001em;. This makes the margins no longer collapse, but doesn't add any space to the <header>.
header {padding:0.001em; background-color:#CCCCCC; width:960px; height:430px;}
#mydiv {width:960px; height:320px; margin:80px 0px 0px 0px; background-color:#CC0000; }
The link to collapsing margins in bfrohs answer helped me find a solution that will work for me, and it may help anyone else who gets this problem.
Absolutely positioned divs don't collaspe so making the header element relative and the inner div absolute gives the correct positioning without adding space with padding or margins.
Working example:
http://jsfiddle.net/8QPGJ/
(Without the positioning: http://jsfiddle.net/8QPGJ/1/)
Related
This question already has answers here:
Why does this CSS margin-top style not work?
(14 answers)
Closed 2 years ago.
My css margins doesn't behave the way I want or expect them to. I seems like my header margin-top affect the div-tags surrounding it.
This is what I want and expect:
...but this is what I end up with:
Source:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Margin test</title>
<style type="text/css">
body {
margin:0;
}
#page {
margin:0;
background:#FF9;
}
#page_container {
margin:0 20px;
}
h1 {
margin:50px 0 0 0;
}
</style>
</head>
<body>
<div id="page">
<div id="page_container">
<header id="branding" role="banner">
<hgroup>
<h1 id="site-title"><span>Title</span></h1>
<h2 id="site-description">Description</h2>
</hgroup>
</header>
</div>
</div>
I have exaggerated the margin in this example. Default browser margin on h1-tag is somewhat smaller, and in my case I use Twitter Bootstrap, with Normalizer.css which sets default margin to 10px. Not that important, main point is; I can not, should not, want not change the margin on the h1-tag.
I guess it is similar to my other question; Why does this CSS margin-top style not work?. Question is how do I solve this specific issue?
I have read a few threads on similar problems, but haven't found any real answers and solutions. I know adding padding:1px; or border:1px; solves the problem. But that only adds new problems, since I do not want a padding nor a border on my div-tags.
There must be a better, best practice, solution? This must be pretty common.
Add overflow:auto to your #page div.
jsFiddle example
And check out collapsing margins while you're at it.
Add any one of the following rules:
float: left/right;
position: absolute;
display: inline-block;
overflow: auto/scroll/hidden;
clear: left/right/both;
This is caused by collapsing margins. See an article about this behavior here.
According to the article:
The W3C specification defines collapsing margins as follows:
“In this specification, the expression collapsing margins means that adjoining margins (no non-empty content, padding, or border areas, or clearance separate them) of two or more boxes (which may be next to one another or nested) combine to form a single margin.”
This is also true for parent-child elements.
All the answers include one of the possible solutions:
There are other situations where elements do not have their margins collapsed:
floated elements
absolutely positioned elements
inline-block elements
elements with overflow set to anything other than visible (They do not collapse margins with their children.)
cleared elements (They do not collapse their top margins with their parent block’s bottom margin.)
the root element
Problem was the parent not taking into account children for height. Adding display:inline-block; did it for me.
Full CSS
#page {
margin:0;
background:#FF9;
display:inline-block;
width:100%;
}
See Fiddle
Just add border-top: 1px solid transparent; to your #page element.
From w3.org
Two margins are adjoining if and only if:
- no line boxes, no clearance, no padding and no border separate them
Add the following rule:
overflow: hidden;
This is caused by collapsing margins. See an article about this behavior here.
According to the article:
If a parent element does not have any top padding or less top margin then its first child, then elements are rendered in a way that makes the parent element appear to have the child element's margin. So this can happen anywhere on a page where these conditions are met, but it tends to be most obvious at the top of a page.
The solutions in the other answers didn't work for me. Transparent borders, inline-block, etc., all caused other problems. Instead, I added the following css to my ancestor element:
parent::after{
content: "";
display: inline-block;
clear: both;
}
Depending on your situation, this may cause its own problems because it adds extra space after the last child element.
My approach when I was making styles for XenForo 2.1, but it should be useful for you:
(Please replace those LESS variables to your actual values. Also, the absolute value of minor margins shall be as same as the height of before-after pseudo elements.)
// The following two lines are to avoid top & bottom fieldset borders run out of the block body.
// (Do not tweak the CSS overflow settings, otherwise the editor menu won't be float above the block border.)
&:before {content: "\a0"; display: block; width: auto; margin-bottom: floor(-1 * #xf-lineHeightDefault * #xf-fontSizeSmall - #xf-borderSizeMinorFeature);}
&:after {content: "\a0"; display: block; width: auto; margin-top: floor(-1 * #xf-lineHeightDefault * #xf-fontSizeSmall - #xf-borderSizeMinorFeature);}
This question already has answers here:
Why does this CSS margin-top style not work?
(14 answers)
Closed 2 years ago.
My css margins doesn't behave the way I want or expect them to. I seems like my header margin-top affect the div-tags surrounding it.
This is what I want and expect:
...but this is what I end up with:
Source:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Margin test</title>
<style type="text/css">
body {
margin:0;
}
#page {
margin:0;
background:#FF9;
}
#page_container {
margin:0 20px;
}
h1 {
margin:50px 0 0 0;
}
</style>
</head>
<body>
<div id="page">
<div id="page_container">
<header id="branding" role="banner">
<hgroup>
<h1 id="site-title"><span>Title</span></h1>
<h2 id="site-description">Description</h2>
</hgroup>
</header>
</div>
</div>
I have exaggerated the margin in this example. Default browser margin on h1-tag is somewhat smaller, and in my case I use Twitter Bootstrap, with Normalizer.css which sets default margin to 10px. Not that important, main point is; I can not, should not, want not change the margin on the h1-tag.
I guess it is similar to my other question; Why does this CSS margin-top style not work?. Question is how do I solve this specific issue?
I have read a few threads on similar problems, but haven't found any real answers and solutions. I know adding padding:1px; or border:1px; solves the problem. But that only adds new problems, since I do not want a padding nor a border on my div-tags.
There must be a better, best practice, solution? This must be pretty common.
Add overflow:auto to your #page div.
jsFiddle example
And check out collapsing margins while you're at it.
Add any one of the following rules:
float: left/right;
position: absolute;
display: inline-block;
overflow: auto/scroll/hidden;
clear: left/right/both;
This is caused by collapsing margins. See an article about this behavior here.
According to the article:
The W3C specification defines collapsing margins as follows:
“In this specification, the expression collapsing margins means that adjoining margins (no non-empty content, padding, or border areas, or clearance separate them) of two or more boxes (which may be next to one another or nested) combine to form a single margin.”
This is also true for parent-child elements.
All the answers include one of the possible solutions:
There are other situations where elements do not have their margins collapsed:
floated elements
absolutely positioned elements
inline-block elements
elements with overflow set to anything other than visible (They do not collapse margins with their children.)
cleared elements (They do not collapse their top margins with their parent block’s bottom margin.)
the root element
Problem was the parent not taking into account children for height. Adding display:inline-block; did it for me.
Full CSS
#page {
margin:0;
background:#FF9;
display:inline-block;
width:100%;
}
See Fiddle
Just add border-top: 1px solid transparent; to your #page element.
From w3.org
Two margins are adjoining if and only if:
- no line boxes, no clearance, no padding and no border separate them
Add the following rule:
overflow: hidden;
This is caused by collapsing margins. See an article about this behavior here.
According to the article:
If a parent element does not have any top padding or less top margin then its first child, then elements are rendered in a way that makes the parent element appear to have the child element's margin. So this can happen anywhere on a page where these conditions are met, but it tends to be most obvious at the top of a page.
The solutions in the other answers didn't work for me. Transparent borders, inline-block, etc., all caused other problems. Instead, I added the following css to my ancestor element:
parent::after{
content: "";
display: inline-block;
clear: both;
}
Depending on your situation, this may cause its own problems because it adds extra space after the last child element.
My approach when I was making styles for XenForo 2.1, but it should be useful for you:
(Please replace those LESS variables to your actual values. Also, the absolute value of minor margins shall be as same as the height of before-after pseudo elements.)
// The following two lines are to avoid top & bottom fieldset borders run out of the block body.
// (Do not tweak the CSS overflow settings, otherwise the editor menu won't be float above the block border.)
&:before {content: "\a0"; display: block; width: auto; margin-bottom: floor(-1 * #xf-lineHeightDefault * #xf-fontSizeSmall - #xf-borderSizeMinorFeature);}
&:after {content: "\a0"; display: block; width: auto; margin-top: floor(-1 * #xf-lineHeightDefault * #xf-fontSizeSmall - #xf-borderSizeMinorFeature);}
I want to know the real height of an element no matters what it have inside. That's easy. The problem began when I put away the borders of the element and notice an strange behavior, see it here:
http://jsfiddle.net/LypZR/
First div: 122px: OK (children height 100px, children margins 20px, border 2px)
.bordered {
border: 1px solid #000;
}
Second div: 120px: OK (children height 100px, children margins 20px)
.display-inline-block {
display: inline-block;
}
Thirth div: 100px: What? where are the margins?
I solved it using display: inline-block that works just fine for me (in this particular case). But I really want to know what is exactly happening.
I think you're getting surprised by margin collapsing.
The two cases that margins collapse are between adjacent sibling elements and between parent and child elements.
In your case, it's the parent/child collapse that's causing you grief: If you have nothing interesting between the top margin of your parent and the (top margin of its first child|bottom margin of its last child), the parent margin collapses. The transparent border hack is commonly-used in these cases.
You probably noted that it didn't change the actual layout values--the p tag's margin kept the visible elements from collapsing into each other. But I admit it's counterintuitive.
That's called the margin collapsing.
When the child element is given margin and parent element don't have any content in it, this happens.
add this class and its done.
.no-bordered{
overflow:auto;
}
Fiddle : http://jsfiddle.net/LypZR/3/
you can see real height without any collapse if you use the right css selector for all the elements *, so:
* {
height: 100px;
margin: 10px;
}
Like you did it's like a quirk behave for me because I don't know .element selector, and if you look inside the consolle could you see that no margin is applied in the styles tab, but only a computed height is calculated, perhaps for some strange behavior it isn't suppouse to work right. till I know only height width and padding are considerate for real element dimensions.
margins should not be considerate for real element dimensions, this is only an IE issue who do such calc adding margin to real element dimensions. jsfiddle
This page I have is super simple, this should be a breeze but I'm stumped.
I have two DIVs, one inside the other. In the first DIV, I have the margins set so that it lays at the top of the page, centered. The second DIV should lay inside the first, centered, but with a 50px margin at top. However, the 50px margin is being applied to the parent DIV and not the child. If I add a border to the parent DIV, it behaves like I expect it to, but not without.
Can anyone offer me any insight to this? Thanks in advance.
<div id="pageWrapper">
<div id="mainWrapper">
<p>foo</p>
</div>
</div>
*{
margin:0px;
padding:0px;
}
body{
background-color:#034375;
}
#pageWrapper{
width:960px;
margin:0px auto 0px auto;
background:url('i/blue-gradient.jpg') top left no-repeat;
}
#mainWrapper{
width:500px;
margin:50px auto 0 auto;
border:1px solid #000000;
background-color:#eeeeee;
}
This issue has to do with the CSS spec on rendering adjacent margins. Essentially, because there's nothing "in between" the margins of the containing div and the margins on the inner div, the larger value is used for both.
You'll see this mainly in Firefox, and although the behavior seems to follow the letter of the law, I'm not sure this particular case behaves as intended by the spec writers.
Fortunately, it's easy to fix -- put something "between" the margins. You've already noticed that putting a border on the parent div works. You can make this border transparent, and reduce the inner margin by 1px, and it will appear functionally the same as your above case. Another option is to apply one pixel of padding-top to the parent div. A third option is to use padding-top: 50px on the parent div instead of applying a top margin to the child div.
More information on collapsing margins.
You don't say which browser you're seeing this in. For me it works as expected in Firefox. However, I suspect you're seeing the issue in Internet Explorer. This is probably because the inner div doesn't have hasLayout applied - this is usually the cause of IE styling bugs. Try adding zoom:1 to the mainWrapper CSS declaration and see if that works.
You probably want to set the padding of mainWrapper instead of margin.
padding:50px 0 0 0;
Check out this description of the box model to see how margins and padding differ.
What is the difference between margin and padding in CSS?
In what kind of situations:
both work.
only margin is appropriate.
only padding is appropriate.
TL;DR: By default I use margin everywhere, except when I have a border or background and want to increase the space inside that visible box.
To me, the biggest difference between padding and margin is that vertical margins auto-collapse, and padding doesn't.
Consider two elements one above the other each with padding of 1em. This padding is considered to be part of the element and is always preserved.
So you will end up with the content of the first element, followed by the padding of the first element, followed by the padding of the second, followed by the content of the second element.
Thus the content of the two elements will end up being 2em apart.
Now replace that padding with 1em margin. Margins are considered to be outside of the element, and margins of adjacent items will overlap.
So in this example, you will end up with the content of the first element followed by 1em of combined margin followed by the content of the second element. So the content of the two elements is only 1em apart.
This can be really useful when you know that you want to say 1em of spacing around an element, regardless of what element it is next to.
The other two big differences are that padding is included in the click region and background color/image, but not the margin.
div.box > div { height: 50px; width: 50px; border: 1px solid black; text-align: center; }
div.padding > div { padding-top: 20px; }
div.margin > div { margin-top: 20px; }
<h3>Default</h3>
<div class="box">
<div>A</div>
<div>B</div>
<div>C</div>
</div>
<h3>padding-top: 20px</h3>
<div class="box padding">
<div>A</div>
<div>B</div>
<div>C</div>
</div>
<h3>margin-top: 20px; </h3>
<div class="box margin">
<div>A</div>
<div>B</div>
<div>C</div>
</div>
Margin is on the outside of block elements while padding is on the inside.
Use margin to separate the block from things outside it
Use padding to move the contents away from the edges of the block.
The best I've seen explaining this with examples, diagrams, and even a 'try it yourself' view is here.
The diagram below I think gives an instant visual understanding of the difference.
One thing to keep in mind is standards compliant browsers (IE quirks is an exception) render only the content portion to the given width, so keep track of this in layout calculations. Also note that border box is seeing somewhat of a comeback with Bootstrap 3 supporting it.
There are more technical explanations for your question, but if you want a way to think about margin and padding, this analogy might help.
Imagine block elements as picture frames hanging on a wall:
The photo is the content.
The matting is the padding.
The frame moulding is the border.
The wall is the viewport.
The space between two frames is the margin.
With this in mind, a good rule of thumb is to use margin when you want to space an element in relationship to other elements on the wall, and padding when you're adjusting the appearance of the element itself. Margin won't change the size of the element, but padding will make the element bigger1.
1 You can alter this behavior with the box-sizing attribute.
MARGIN vs PADDING :
Margin is used in an element to create distance between that element and other elements of page. Where padding is used to create distance between content and border of an element.
Margin is not part of an element where padding is part of element.
Please refer below image extracted from Margin Vs Padding - CSS Properties
From https://www.w3schools.com/css/css_boxmodel.asp
Explanation of the different parts:
Content - The content of the box, where text and images appear
Padding - Clears an area around the content. The padding is transparent
Border - A border that goes around the padding and content
Margin - Clears an area outside the border. The margin is transparent
Live example (play around by changing the values):
https://www.w3schools.com/css/tryit.asp?filename=trycss_boxmodel
It's good to know the differences between margin and padding. Here are some differences:
Margin is outer space of an element, while padding is inner space of an element.
Margin is the space outside the border of an element, while padding is the space inside the border of it.
Margin accepts the value of auto: margin: auto, but you can't set padding to auto.
Tip: You can use the trick to make elements centered inside their parents (even vertically). See my other answer for example.
Margin can be set to any number, but padding must be non-negative.
When you style an element, padding will also be affected (e.g. background color), but not margin.
Here is some HTML that demonstrates how padding and margin affect clickability, and background filling. An object receives clicks to its padding, but clicks on an objects margin'd area go to its parent.
$(".outer").click(function(e) {
console.log("outer");
e.stopPropagation();
});
$(".inner").click(function(e) {
console.log("inner");
e.stopPropagation();
});
.outer {
padding: 10px;
background: red;
}
.inner {
margin: 10px;
padding: 10px;
background: blue;
border: solid white 1px;
}
<script src="http://code.jquery.com/jquery-latest.js"></script>
<div class="outer">
<div class="inner" style="position:relative; height:0px; width:0px">
</div>
</div>
The thing about margins is that you don't need to worry about the element's width.
Like when you give something {padding: 10px;}, you'll have to reduce the width of the element by 20px to keep the 'fit' and not disturb other elements around it.
So I generally start off by using paddings to get everything 'packed' and then use margins for minor tweaks.
Another thing to be aware of is that paddings are more consistent on different browsers and IE doesn't treat negative margins very well.
The margin clears an area around an element (outside the border), but the padding clears an area around the content (inside the border) of an element.
it means that your element does not know about its outside margins, so if you are developing dynamic web controls, I recommend that to use padding vs margin if you can.
note that some times you have to use margin.
One thing to note is when auto collapsing margins annoy you (and you are not using background colours on your elements), something it's just easier to use padding.
Advanced Margin versus Padding Explained
It is inappropriate to use padding to space content in an element; you must utilize margin on the child element instead. Older browsers such as Internet Explorer misinterpreted the box model except when it came to using margin which works perfectly in Internet Explorer 4.
There are two exceptions when using padding is appropriate to use:
It is applied to an inline element which can not contain any child elements such as an input element.
You are compensating for a highly miscellaneous browser bug which a vendor *cough* Mozilla *cough* refuses to fix and are certain (to the degree that you hold regular exchanges with W3C and WHATWG editors) that you must have a working solution and this solution will not effect the styling of anything other then the bug you are compensating for.
When you have a 100% width element with padding: 50px; you effectively get width: calc(100% + 100px);. Since margin is not added to the width it will not cause unexpected layout problems when you use margin on child elements instead of padding directly on the element.
So if you're not doing one of those two things do not add padding to the element but to it's direct child/children element(s) to ensure you're going to get the expected behavior in all browsers.
First let's look at what are the differences and what each responsibility is:
1) Margin
The CSS margin properties are used to generate space around elements.
The margin properties set the size of the white space outside the
border. With CSS, you have full control over the margins. There are
CSS properties for setting the margin for each side of an element
(top, right, bottom, and left).
2) Padding
The CSS padding properties are used to generate space around content.
The padding clears an area around the content (inside the border) of
an element. With CSS, you have full control over the padding. There
are CSS properties for setting the padding for each side of an element
(top, right, bottom, and left).
So simply Margins are space around elements, while Padding are space around content which are part of the element.
This image from codemancers shows how margin and borders get togther and how border box and content-box make it different.
Also they define each section as below:
Content - this defines the content area of the box where the actual content like text, images or maybe other elements reside.
Padding - this clears the main content from its containing box.
Border - this surrounds both content and padding.
Margin - this area defines a transparent space that separates it from other elements.
I always use this principle:
This is the box model from the inspect element feature in Firefox. It works like an onion:
Your content is in the middle.
Padding is space between your content and edge of the tag it is
inside.
The border and its specifications
The margin is the space around the tag.
So bigger margins will make more space around the box that contains your content.
Larger padding will increase the space between your content and the box of which it is inside.
Neither of them will increase or decrease the size of the box if it is set to a specific value.
Margin
Margin is usually used to create a space between the element itself and its surround.
for example I use it when I'm building a navbar to make it sticks to the edges of the screen and for no white gap.
Padding
I usually use when I've an element inside a border, <div> or something similar, and I want to decrease its size but at the time I want to keep the distance or the margin between the other elements around it.
So briefly, it's situational; it depends on what you are trying to do.
Margin is outside the box and padding is inside the box