I am trying to wrap a div called content with another div that has a different background.
However, when using "margin-top" with the content div, it seems like the wrapping DIV gets the margin-top instead of the content div.
Code:
<!DOCTYPE html>
<html>
<head>
<style>
html {
background-color:red;
}
#container-top {
background-color: #ccc;
overflow: hidden;
padding-top: 10px;
border-bottom: 1px solid #000;
height:30px;
}
#container-bottom {
background-color: #F1F4F2;
}
#content {
margin-top:20px;
}
</style>
</head>
<body>
<div id="container-top">
</div>
<div id="container-bottom">
<div id="content">
Hello
</div>
</div>
</body>
</html>
So in the example, the div container-bottom gets the margin-top instead of the content div.
I found out that if I add a char inside container-bottom it fixes the issue.
<div id="container-bottom">
**A**
<div id="content">
Hello
</div>
But of course that is not a good solution...
Thanks,
Joel
What's happening is called margin-collapsing.
If two margins (top & bottom only, not right or left) of 2 elements are touching (or in your case, the top-margin of the inner div is touching the top-margin of the outer div), the max between them is used (in your case max(0, 20) = 20) and placed as far as possible from the touching elements (in your case outside the container div (the outermost element)).
To break this behavior, you have to place something between the 2 margins -> a padding at the top of the container div will do.
#container-bottom {
background-color: #F1F4F2;
padding-top: 1px;
}
#content {
margin-top:19px;
}
other solution (works, but may not suit your needs):
you can simply put a padding-top of 20 px in the container div:
#container-bottom {
background-color: #F1F4F2;
padding-top: 20px;
}
#content {
}
for more informations, this page explains it very well: Margin Collapsing
You could try adding a non-breaking space to the #container-bottom:
<div id="container-bottom">
<div id="content">
Hello
</div>
</div>
This is a suitable solution as it is often used to let a browser know that an element is not empty (some browsers ignore empty elements).
Margin-top is a mysterious creature because of its collapsing properties. I have found the easiest fix to this problem is to apply a 1px padding-top to the container-bottom div and change the content margin-top to 19px.
Related
After about 15 years writing CSS, I'm still discovering things I don't understand...
Below is a simple page with an h1 element that is 2000px wide. As expected, this causes the page to have a horizontal scrollbar.
But the problem is, the parent div.wrapper does not expand to the width of its contents – its yellow background only extends as far as the width of the viewport. (Run the below snippet and scroll horizontally to see the problem.)
body { margin: 0; }
.wrapper { background: yellow; }
h1 {
width: 2000px;
border: 2px solid red;
}
<!doctype html>
<html>
<body>
<div class="wrapper">
<h1>Hello</h1>
<p>More content</p>
</div>
<p>More content outside wrapper</p>
</body>
</html>
Here's the weird thing: Try adding body { position: absolute } to the above CSS and it fixes it. The div.wrapper now extends to the width of its contents – the yellow goes all the way to the right of the document.
Questions:
Why does setting body { position: absolute } fix the problem?
Are there any better (more intuitive) ways to fix the problem?
Constraints: I do not always know the width of the inner contents, I just want the wrapper to always extend so its background color goes all the way to the right of the contents.
Let's start with this:
But the problem is, the parent div.wrapper does not expand to the
width of its contents – its yellow background only extends as far as
the width of the viewport.
By default a div is a block element and a block element takes up the whole width of it's parent container so your wrapper in this case has the width of the body which is the width of the screen. In addition to this we are facing an overflow as the child content width is bigger than the parent width and by default:
Content is not clipped and may be rendered outside the padding boxref
This explain why the background doesn't cover the h1 as this one is rendred outside.
To change this behavior we have two solutions:
We change the behavior of overflow by specifing a value different from visible (the default one). By doing this you will also notice some changes to margin because you are also facing a margin collapsing (margin of h1 and p are collpasing with the margin of div.wrapper).
body {
margin: 0;
}
.wrapper {
background: yellow;
margin:10px 0;
}
h1 {
width: 2000px;
border: 2px solid red;
}
<div class="wrapper" style="overflow: auto;">
<h1>Hello</h1>
<p>More content</p>
</div>
<div class="wrapper" style="overflow: hidden;">
<h1>Hello</h1>
<p>More content</p>
</div>
<div class="wrapper" style="overflow: scroll;">
<h1>Hello</h1>
<p>More content</p>
</div>
<p>More content outside wrapper</p>
We change the display property of the element to something else than block. We can for example use inline-block or inline-flex and in this case the wrapper will fit the content of its element and he will overflow the body
body {
margin: 0;
}
.wrapper {
background: yellow;
display: inline-block;
}
h1 {
width: 2000px;
border: 2px solid red;
}
<div class="wrapper">
<h1>Hello</h1>
<p>More content</p>
</div>
<p>More content outside wrapper</p>
Concerning this:
Why does setting body { position: absolute } fix the problem?
We all know what position:absolute means but the intresting part is this one:
Most of the time, absolutely positioned elements that have height and
width set to auto are sized so as to fit their contents. However,
non-replaced, absolutely positioned elements can be made to fill the
available vertical space by specifying both top and bottom and leaving
height unspecified (that is, auto). They can likewise be made to fill
the available horizontal space by specifying both left and right and
leaving width as auto. ref
You haven't told the div how to handle the overflow caused by the width of the inner element. Add overflow: auto.
body { margin: 0; }
.wrapper { background: yellow; overflow: auto; }
h1 {
width: 2000px;
border: 2px solid red;
}
<!doctype html>
<html>
<body>
<div class="wrapper">
<h1>Hello</h1>
<p>More content</p>
</div>
<p>More content outside wrapper</p>
</body>
</html>
I do not believe that there is an obvious reason why adding position: absolute to the body fixes this. It does take body out of the document flow, but body is the container for all the content. So I would describe it as a quirk.
We could describe body as being the initial constraint for the width of the content, the .wrapper. Being absolute removes this constraint. Actually, it likely remove the width constraint for any further elements on the page, so they will probably all expand to contain any inner content.
Yeah, you can use width: fit-content;
MDN describes it as;
fit-content
The larger of:
the intrinsic minimum width
the smaller of the intrinsic preferred width and the available width
It works as expected; the containing element expands. But, as usual, IE lags behind and doesn't support it...
EDIT To be clear; this specification is still in Working Draft status, and as such should not be used in production environments (except if you don't care about Internet Explorer).
http://optimalpages.de/DrupalMusi/
How can I position the main content div in the middle without it collapsing to the left, when left sidebar is shorter than the content? Is that possible? I don't want to use a fixed height for the navigation, but can I somehow say "sidebarleft height = content height", or is there an easier way?
Thanks!
Actually you are floating only elements to the left without any wrapper element, so what happens is this..
Instead, wrap the other 2 elements inside a wrapper element and than float it to the left
.left_wrap {
float: left;
width: 30%;
}
.right_wrap {
float: left;
width: 70%;
}
.right_wrap > div {
border: 3px solid #ff0;
height: 100px;
}
<div class="main">
<div class="left_wrap">
Hello
</div>
<div class="right_wrap">
World
<div></div>
<div></div>
</div>
</div>
Demo
Better Demo
If you want even a better one, I would suggest you to wrap the boxes inside the parent containers, and instead of floating the child elements, float the parent.
Demo
Also, don't forget to clear your floated elements, just make sure you clear them, you can use a self clearing parent CSS like
.clear:after {
content: "";
clear: both;
display: table;
}
And call the above class on the element containing floated elements as their children, where in this case, it's <div class="main"> so it should be now
<div class="main clear">
<!-- Floated Elements -->
</div>
I'm not quite sure if this is what you mean but try:
#node-29{
float: right;
clear: left;
margin-left: 0;
}
This will position the div's next to each other and keep the main content to the right.
This can be quite complex depending on your existing theme.
I wrote this page a while back to shows you how you can do that.
http://linux.m2osw.com/3columns
More or less you need a first div that encompasses the left column and the content. That div is the one that gets centered.
To make it simpler you can set a specific width to the div and you get something like this:
div.page
{
width: 900px;
margin: 0 auto;
}
That will center the main div.
For the column and the content, both are float: left; div's. In order to "close" the lot, you want another div just before closing the main div. That one has a style that ensures that the main div has the correct size: clear: both;.
we can use margins to set the div position .we can either specify fixed margins or we can give percentage value ,so that it will based on the total size of the screen.
<!DOCTYPE html>
<html>
<head>
<style>
#main
{
background-color:yellow;
}
#main
{
margin-top:100px;
margin-bottom:100px;
margin-right:50px;
margin-left:50px;
}
</style>
</head>
<body >
<div id="main">
this is how we can display main div in centre
</div>
</body>
</html>
I'm trying to brush up on my HTML and CSS again and I was trying to make a simple layout. Here is the HTML/CSS for my simple site.
<!DOCTYPE html>
<HTML>
<HEAD>
<TITLE>My website</TITLE>
<META CHARSET="UTF-8">
<style type="text/css">
* {
padding: 0px;
margin: 0px
}
html, body {
margin:0;
padding:0;
height:100%;
border: 0px;
}
#TopBar {
width:100%;
height:15%;
border-bottom:5px solid;
border-color:#B30000;
}
#MidBar {
background-color:black;
height:70%;
width:70%;
margin-left:auto;
margin-right:auto;
}
#BottomBar {
position:absolute;
bottom:0;
width:100%;
height:15%;
border-top:5px solid;
border-color:#B30000;
}
h1 {
font-family: sans-serif;
font-size: 24pt;
}
#HEADER {
text-align:center;
}
li {
display:inline;
}
#copyright {
text-align: center;
}
</style>
</HEAD>
<BODY>
<DIV ID="TopBar">
<DIV ID="HEADER">
<HEADER>
<H1>My website</H1>
<NAV>
<UL>
<LI>About me
<LI>Contact me
<LI>My blog
<LI>My portfolio
</UL>
</NAV>
</HEADER>
</DIV>
</DIV>
<DIV ID="MidBar">
<DIV ID="PhotoSlideshow">
test
</DIV>
</DIV>
<DIV ID="BottomBar">
<FOOTER>
<P ID="copyright">Name here ©
<?PHP DATE("Y") ECHO ?> </P>
</FOOTER>
</DIV>
</BODY>
</HTML>
Given the heights I've applied to my div elements I expected everything to line up nicely however it appears that the bottom div is higher than the intended 15% and overlaps onto the middle div, see here demonstrated by the red border at the bottom...
Where am I going wrong? I'm sure it's something simple.
You should understand how the box model works... You are using borders which are counted outside the element, so for example if your element is 200px in height, and has a 5px border, the total element size will be 210px;
So considering this as the concept, what you are having elements which sums up to 100%, and you are using borders too, so that is exceeding the viewport which will result in vertical scroll...
Also you don't have to use position: absolute;, you are making it absolute, just to avoid scrolls but that's a wrong approach. Absolute element is out of the document flow, and will give weird results if you didn't wrapped inside a position: relative; element.
Demo
Few Tips :
Use lowercase tags
Avoid Uppercase ID's unless required
Using 100% vertically is very rare, designers generally use width: 100%; for making the layouts responsive. So if you don't have any specific reason to go for 100% vertical elements, don't go for it..
Solution:
Still if you want to stick with the vertical layout spanning to 100% in height, you should use box-sizing: border-box; property...
What box-sizing will do here?
Well, using the above property, it will change the default behavior of the box-model, so instead of counting the borders, paddings etc outside the element, it will count inside it, thus it will prevent the viewport to be scrolled.
I will provide you an example, which I had made for another answer.
Demo 2 (Updated, had forgot to normalize the CSS)
Explanation for the above demo, if you look at the CSS, I am using
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
which will make every element paddings, borders etc to be counted inside the element and not outside, if you mark, am using a border of 5px; and still, the window won't get a scroll bar as the border is counted inside the element and not outside.
There are many things a bit off with your code, however the straight forward answer is that borders are part of the box model, therefore part of the height calculation. So the height of your div is 15% of the height + the width of your borders, thus it is oversized.
Please see this explanation of the box model:
http://css-tricks.com/the-css-box-model/
I think it has to do with your borders (each of which is 5px). Since you have your TopBar, MidBar, and BottomBar have percentage heights that add up to %100, WITH additional borders, you have a problem of having an effective height of greater than %100, and then, because you have BottomBar with an absolute position at the bottom, it doesn't force the page to scroll, but simple induces some overlap between the MidBar and BotomBar divs.
Remove "Position: absolute" from: #BottomBar. That should do the trick.
For example, if you look at Facebook, they have a short blue bar on top that extends the entire width of the browser. I thought about using width:100%; but I know that it needs to have a parent element to be able to do that.
One way:
<div style="position:absolute;left:0px;right:0px;height:20px"> </div>
The document itself acts as a parent element. Divs, by default, are 100% of their parent's width.
What you probably need to do is set no margin or padding on the body element.
<html>
<style>
body { margin: 0; padding: 0; }
#strip { background: #89f; padding: 5px; }
</style>
<body>
<div id="strip">This is a nav strip</div>
</body>
</html>
Demo at http://www.coffeepowered.net/projects/navstrip.html
If you use a CSS reset, then this should Just Work.
Hi I have a container which has a width of 1150px. Now I have this other mainmenu, with width: 100% that I want to place inside the container. But then ofcourse it only get 100%(1150px) but I want it full width from side to side, so it should ignore the setted width only for .mainmenu
I tried position: absolute which made it all wrong and weird
#mainmenu
{
height: 37px;
width: 100%;
margin: 0px auto;
background-image: url(../images/mainmenu_bg5.jpg);
}
Why is the menu in the container in the first place? If you want the menu to span the full width yet the contents of the container are only 1150px I think it is by definition not right to put the menu in the container. Consider restructuring your document. This is an example, I do not have your full code:
<body>
<div id="page">
<div id="header" style="background:Blue;">
header header header
</div>
<div id="mainmenu" style="background:Green;">
menu menu menu menu
</div>
<div id="container" style="width:1150px;margin:auto;background:Red;">
container container container
</div>
</div>
</body>
And if you want the contents of the header and menu to span no farther than 1150px which I think is what you want then consider this:
<head>
<style type="text/css">
.pagewidth {
width: 1150px;
margin: auto;
}
</style>
</head>
<body>
<div id="page">
<div id="header" style="background:Blue;">
<div class="pagewidth">
header header header
</div>
</div>
<div id="mainmenu" style="background:Green;">
<div class="pagewidth">
menu menu menu menu
</div>
</div>
<div id="container" class="pagewidth" style="background:Red;">
container container container
</div>
</div>
</body>
If your container is fixed-width, but you want a menu which has a background at full page-width, then you can have the menu background as a positioned background of html, and maintain the same HTML code. This will make the menu's background "bar" cover the whole page width.
Example of this method: http://templates.arcsin.se/demo/freshmade-software-website-template/index.html
How to do this: use positioned backgrounds:
http://www.w3schools.com/css/pr_background-position.asp
css is below, but sometime it depend from the content inside:
#mainmenu
{
height: 37px;
width: 100%;
margin: 0px;
position: relative;
background-image: url(../images/mainmenu_bg5.jpg);
}
This is a jQuery solution:
$('#mainmenu').width() == $('#container').width();
To get a background image to simulate the menubar spanning the entire width of the page you need to apply the #mainmenu background to the body or a container div like so:
body {
background: url(YOURIMAGE) repeat-x left 64px;
}
The 64px needs to be how far the #mainmenu is from the top.
If the body already has a background image then you will need another div just inside the body containing everything else. If you have no control over the HTML then using javascript to insert a div that will either wrap all the content or get rendered behind it (using position and z-index.)
position:absolute is the best way to get this while keeping the background in #mainmenu. In fact, it's the only one I can think of off the top of my head. Without javascript, of course. Everything else will require changing HTML or moving the background property to a different place.
#mainmenu
{
position:absolute;
left:0;top:??px;
width:100%;
height:37px;
background-image: url(../images/mainmenu_bg5.jpg);
}
Because #mainmenu's width:100% then will become 100% of the viewport rather than the containing block. (Unless a parent is position:relative or overflow:hidden)
So when you say it "got all weird", I assume that's because of other things on the page. Both absolute and float take items out of the normal document flow. So things below the menu can & will end up underneath it.
#mainmenu
{
position:absolute;
left:0;top:??px;
width:100%;
height:37px;
background-image: url(../images/mainmenu_bg5.jpg);
}
#mainmenu + *
{
padding-top:37px;
}
/* Exact selector not recommended due to poor browser support */
The solution to that is, basically, applying 37px of margin or padding to the first thing after #mainmenu. You'll also be unable to center absolutely positioned elements using margin:0 auto, but if you want it spanning the full width of the viewport, that shouldn't be a concern...If you want to center the live sections of the menu, of course, you'll need some sort of descendant to center:
#mainmenu
{
position:absolute;
left:0;top:??px;
width:100%;
height:37px;
background-image: url(../images/mainmenu_bg5.jpg);
}
#mainmenu > *
{
margin:0 auto;
}
/* Exact selector not recommended due to poor browser support */
/* & more properties needed if descendant is list with floated <li>s */
#mainmenu + *
{
padding-top:37px;
}
/* Exact selector not recommended due to poor browser support */
But there are lots of things you'll see change in relation to other things on the page with position:absolute. So to troubleshoot that I really need to know more about the other things on the page.
You may find another solution, but if you don't -- post a page I can look at & I may be able to help you with the weirdness you experienced with absolute positioning. That is, if it will work with this particular layout.