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);}
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:
Image inside div has extra space below the image
(10 answers)
Why is this inline-block element pushed downward?
(8 answers)
Closed 3 years ago.
Example:
https://codepen.io/229075284/pen/aboQVXZ
.outer{
background-color: pink;
}
.outer::after{
content:'';
background-color: red;
display: inline-block;
font-size: 0;
line-height: 0;
overflow: hidden;
height: 0;
/* display: table; */
}
.inner{
background-color: blue;
height: 300px;
}
<div class="outer">
<div class="inner"></div>
</div>
When I set display of outer::after to inline-block,the outer will have some extra space marked as pink, even if set font-size and line-height to 0. However, when I set display to table,the extra space disappears.
So I am wondering why the extra space appears?
I checked your codepen. It is a combination of both display: inline-block and content: "" on the ::after pseudo element. You are basically telling the browser that right after the outer element you want to reserve an element's place in the DOM.
You could see that if you remove the content: "" although you are using inline-block the extra pseudo div after the .outer element would disappear. That is because although you stated a certain display mode you practically have no content in this element and the browser ignores your element because it has no fixed size in pixels and no actual content within it.
The reason .outer is growing is that its height is set to auto in default, if you would give it a fixed height in pixels it might not show the spare div.
Your question has nothing to do with line-height or `overflow'.
Me personally I prefer not to use pseudo-classes like ::after and ::before in production. I prefer using regular divs and have my code more readable and understandable by other developers, anyway I hope I helped out. Feel free to discuss further if you have more questions.
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/)
I have an HTML page that for the sake of this question looks like this:
<html>
<head>
<style>
div { width: 100%; }
.success { background-color: #ccffcc; }
</style>
</head>
<body>
<div class="success">
<nobr>This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line.</nobr>
</div>
</body>
</html>
Note the "very long line", and the background color of that div.
My problem (and I bet it is a basic one) is that the background-color stops at the edge of the screen. When I scroll out to the right to see the rest of the text, the rest of the text background is white.
Basically I want my div to behave like this:
To have the specified background color
To minimum have the same width as the screen, even if the text within is just a few words
To follow the width of the text, if it is more than the width of the screen
Optionally (and I know this is really a different, follow-up, question), if I have more than one such div, following the first, is there a way to have the two follow the width of the widest div automatically?
Did that make any sense?
Is there any way to do this?
I have set up a test page here, which, if you view this on iPhone, although a small font, shows the problem: http://www.vkarlsen.no/test/test.html
I saw the following questions listed as potential duplicates/suggestions by SO, here's what I noticed when I tried the information within:
iPad background for div blocks not spanning entire width of screen
Tried the suggested <meta ... viewport .../> tag, did not make a difference (it is present in the test page right now.)
Background color stretches accross entire width of ul
<div>s are already block elements
WebKit doesn't paint background-color for entire width of final inline list item
Tried setting the div to display: inline-block; but this did not appear to change anything
black magic:
<style>
body { float:left;}
.success { background-color: #ccffcc;}
</style>
If anyone has a clear explanation of why this works, please comment. I think it has something to do with a side effect of the float that removes the constraint that the body must fit into the page width.
The problem seems to be that block elements only scale up to 100% of their containing element, no matter how big their content is—it just overflows. However, making them inline-block elements apparently resizes their width to their actual content.
HTML:
<div id="container">
<div class="wide">
foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
</div>
<div class="wide">
bar
</div>
</div>
CSS:
.wide { min-width: 100%; display: inline-block; background-color: yellow; }
#container { display: inline-block; }
(The containerelement addresses your follow-up question to make the second div as big as the previous one, and not just the screen width.)
I also set up a JS fiddle showing my demo code.
If you run into any troubles (esp. cross-browser issues) with inline-block, looking at Block-level elements within display: inline-block might help.
.success { background-color: #cffccc; overflow: scroll; min-width: 100%; }
You can try scroll or auto.
The inline-block display style seems to do what you want. Note that the <nobr> tag is deprecated, and should not be used. Non-breaking white space is doable in CSS. Here's how I would alter your example style rules:
div { display: inline-block; white-space: nowrap; }
.success { background-color: #ccffcc; }
Alter your stylesheet, remove the <nobr> tags from your source, and give it a try. Note that display: inline-block does not work in every browser, though it tends to only be problematic in older browsers (newer versions should support it to some degree). My personal opinion is to ignore coding for broken browsers. If your code is standards compliant, it should work in all of the major, modern browsers. Anyone still using IE6 (or earlier) deserves the pain. :-)
It is because you set the width:100% which by definition only spans the width of the screen. You want to set the min-width:100% which sets it to the width of the screen... with the ability to grow beyond that.
Also make sure you set min-width:100% for body and html.
The width is being restricted by the size of the body. If you make the width of the body larger you will see it stays on one line with the background color.
To maintain the minimum width: min-width:100%
Try this,
.success { background-color: #ccffcc; float:left;}
or try this,
.success { background-color: #ccffcc; overflow:auto;}
Here's a question that's been haunting me for a year now. The root question is how do I set the size of an element relative to its parent so that it is inset by N pixels from every edge? Setting the width would be nice, but you don't know the width of the parent, and you want the elements to resize with the window. (You don't want to use percents because you need a specific number of pixels.)
Edit
I also need to prevent the content (or lack of content) from stretching or shrinking both elements. First answer I got was to use padding on the parent, which would work great. I want the parent to be exactly 25% wide, and exactly the same height as the browser client area, without the child being able to push it and get a scroll bar.
/Edit
I tried solving this problem using {top:Npx;left:Npx;bottom:Npx;right:Npx;} but it only works in certain browsers.
I could potentially write some javascript with jquery to fix all elements with every page resize, but I'm not real happy with that solution. (What if I want the top offset by 10px but the bottom only 5px? It gets complicated.)
What I'd like to know is either how to solve this in a cross-browser way, or some list of browsers which allow the easy CSS solution. Maybe someone out there has a trick that makes this easy.
The The CSS Box model might provide insight for you, but my guess is that you're not going to achieve pixel-perfect layout with CSS alone.
If I understand correctly, you want the parent to be 25% wide and exactly the height of the browser display area. Then you want the child to be 25% - 2n pixels wide and 100%-2n pixels in height with n pixels surrounding the child. No current CSS specification includes support these types of calculations (although IE5, IE6, and IE7 have non-standard support for CSS expressions and IE8 is dropping support for CSS expressions in IE8-standards mode).
You can force the parent to 100% of the browser area and 25% wide, but you cannot stretch the child's height to pixel perfection with this...
<style type="text/css">
html { height: 100%; }
body { font: normal 11px verdana; height: 100%; }
#one { background-color:gray; float:left; height:100%; padding:5px; width:25%; }
#two { height: 100%; background-color:pink;}
</style>
</head>
<body>
<div id="one">
<div id="two">
<p>content ... content ... content</p>
</div>
</div>
...but a horizontal scrollbar will appear. Also, if the content is squeezed, the parent background will not extend past 100%. This is perhaps the padding example you presented in the question itself.
You can achieve the illusion that you're seeking through images and additional divs, but CSS alone, I don't believe, can achieve pixel perfection with that height requirement in place.
If you are only concerned with horizontal spacing, then you can make all child block elements within a parent block element "inset" by a certain amount by giving the parent element padding. You can make a single child block element within a parent block element "inset" by giving the element margins. If you use the latter approach, you may need to set a border or slight padding on the parent element to prevent margin collapsing.
If you are concerned with vertical spacing as well, then you need to use positioning. The parent element needs to be positioned; if you don't want to move it anywhere, then use position: relative and don't bother setting top or left; it will remain where it is. Then you use absolute positioning on the child element, and set top, right, bottom and left relative to the edges of the parent element.
For example:
#outer {
width: 10em;
height: 10em;
background: red;
position: relative;
}
#inner {
background: white;
position: absolute;
top: 1em;
left: 1em;
right: 1em;
bottom: 1em;
}
If you want to avoid content from expanding the width of an element, then you should use the overflow property, for example, overflow: auto.
Simply apply some padding to the parent element, and no width on the child element. Assuming they're both display:block, that should work fine.
Or go the other way around: set the margin of the child-element.
Floatutorial is a great resource for stuff like this.
Try this:
.parent {padding:Npx; display:block;}
.child {width:100%; display:block;}
It should have an Npx space on all sides, stretching to fill the parent element.
EDIT:
Of course, on the parent, you could also use
{padding-top:Mpx; padding-bottom:Npx; padding-right:Xpx; padding-left:Ypx;}