Suppose I have three <div>s in my page,:
<div id="left" class="test" style="float:left;"></div>
<div id="right" class="test" style="float:right;"></div>
<div id="footer">footer</div>
with this css:
.test{ background:black;height:200px;width:200px;}
#footer{ background:yellow;margin:20px 0 0 0;}
What I want is:
let the "#left" float to left
let the "#right" float to right
change nothing about the "#footer", just set it to margin: 20px;
The result is below:
But I wonder why the floated divs also have the same margin as the #footer. They are floated, so they're independent of the other elements, why would the #footer could affect them?
as well as clear:both on the footer, just adding a container "wrapper" div around the the elements will stop this happening - example
actually adding clear: both; on the footer won't give you a 20px gap between the floats and the footer either, you would actually need to add the 20px bottom margin to the floats - the reasons are all linked.. to clearance or non clearance and it's interaction with Collapsing Margins
Why?
You said you wanted to know why this is happening, in your OP scenario it's because of Collapsing Margins.
You have no clearance involved in the original example, so yes the floats are removed, So the footer margin is still adjoining, therefore collapsing with, the body element, so the body element is the one getting the margin, and then because the floats are still actually inside the body they get the margin too.
As I mentioned above creating a wrapper div to "contain" the floats stops this happening because the rules of collapsing too. However you choose to contain the floats, either with overflow:hidden, or by floating the "wrapper" stops this interaction because .. from the section on collapsing margins:
Vertical 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.
you see that both of the properties, float and 'overflow other than visible' are the means to "contain floated children" - actually they're establishing a new block formatting context, but in easy speak most know it as "containing floats" ;)
Now once you have that, that fixes your first bit but then if you decide to introduce clear:both on the footer, the modern browsers will not put a 20px margin between the floats and the footer.. this is actually correct.. from the section on the clear property (my bold):
Then the amount of clearance is set to
the greater of:
The amount necessary to place the border edge of the block even with
the bottom outer edge of the lowest
float that is to be cleared.
The amount necessary to place the top border edge of the block at
its hypothetical position.
In order to place the top edge of the footer below the floats (in your example) the browser has to introduce 200px of clearance, which is far more than 20px so it follows rule 1. If your top margin on the footer was 220px, the margin would be greater than the any clearance needed, so it would follow rule 2.
So, if you did actually want the footer to be 20px below the floats no matter what their heights are, you would put the 20px as a bottom margin onto the two floats, so it [the footer] would clear, via clearance rule 1, the floats with the required gap/margin, no matter which was float the longest.
PS: Don't test the above in IE7 or below - and I hope it wasn't too boring ;)
Add a clear: both to the #footer CSS. That should make the footer render below the floating divs with the margin you want.
Try this and this may solve your problem:
<div id="right" class="test" style="float:right;"></div>
<div id="left" class="test"></div>
<div id="footer">footer</div>
CSS remaining unchanged.
I made a test before finding this page that has two boxes, with the right-floated one being affected by the left block one (which comes after it) here: http://jsfiddle.net/4r75s/
The overflow trick that prevents parent divs collapsing when they only contain floated content seems to work here, that is setting overflow to hidden, auto or scroll. I wrapped them in a containing div to do it and it works: http://jsfiddle.net/4r75s/1/
#container {
overflow: hidden;
}
Related
I want a full screen bar in the upper part of my site that has a list in the left and a right part(whatever elements). Why this doesn't work?
#upperline{
background:brown;
width:100%;}
#upperline ul{
float:left;}
#upperline p{
float:right;}
<div id="upperline">
<ul>
<li>our team</li>
<li>help</li>
<li>contact</li>
</ul>
<p>log in</p>
</div>
i am so confused
Put an overflow:hidden; on the parent of floating elements to make it works
See it here
#upperline{
background:brown;
width:100%;
overflow: hidden;}
From this post and adapted to your case :
div is a block-level element (they stretch to 100%
of the parent width).
Now in your example the div contains only floated elements. This makes
it collapse to a height of 0px (It still has 100% width though as you
can see in the example).
Now declaring overflow (any value other than visible) establishes a
new block formatting context, which makes the div contains its
children. Suddenly the div "reappears", not having size 0px anymore.
The reason that your code does't work is that in CSS, putting float: left or float: right makes that element no longer affect its parents height. This means that if you put a float rule on all elements in a container, the container will not have any height. There are a few ways of getting around this.
As Vincent G suggested is putting overflow: hidden on the container div. This works because setting the overflow to hidden (or auto) makes the browser do a different kind of check to see what the height should be. This has a pretty serious downside though. overflow: hidden means that any element that is inside the container that can expand (drop down menu for example) will be cut off.
The second way (and in my opinion the best way) is to place a div with the CSS rule clear:both at the very bottom of the container. This div can be empty so you will not see it. clear: both will put this element below any sibling elements. As long as you don't put a float rule on this element the parent element will be resized to include it.
Here is an example of the second version: https://jsfiddle.net/8ewr89jw/
I have three divs and am floating the first left. The other two wrap around it to the right fine if only the floated element has a width set. But if I set a width for the other 2 divs too, they no longer wrap around the first, just stack up below as in normal flow fashion.
I understand I would need to add the same float class to divs 2 and 3 to get them to float inline, but I was curious as to why this behavoir occuers if all three have widths (even if the widths add up to less than the available broswer window width). Here is the code:
<!DOCTYPE html>
<html>
<head>
<style>
.one {
background-color: steelblue;
padding: 10px;
width: 200px;
}
.two {
background-color: orange;
padding: 10px;
width: 200px;
}
.three {
background-color: red;
padding: 10px;
width: 200px;
}
.float {
float: left;
}
</style>
</head>
<body>
<div class="one float">
<p>I am paragraph one</p>
</div>
<div class="two">
<p>I am paragraph two</p>
</div>
<div class="three">
<p>I am paragraph three</p>
</div>
</body>
</html>
This might be best explained with a few pictures. First let’s get rid of your third div as it really isn't needed to explain what’s going on.
When you float your first div and don’t give the second div a width, you get this:
The first (floated) div is taken from the normal flow and placed along the left side of its container, where text and inline elements will wrap around it, as floats are supposed to do. What actually then happens is the second div acts like it’s placed behind the first div as you can see when you inspect the document:
Notice how the second div doesn't start at the right edge of the first div – it actually exists in the same space as the first div (appearing as if it was behind it); however the text in the second div begins where the first div ends. The second div then proceeds to take up 100% of the width of its container since it's a block level element. Only the text inside the div is being manipulated by the first floated div.
Now, what happens if we then set a width on the second div? Well you get the following:
So the question is, why does something as simple as setting the width on the second div appear to nullify the float rule on the first div? Well, it’s not. Here’s what’s going on. Just like in the first example, the second div appears to exist behind the first div, however this time you’re explicitly limiting the amount of room the text has to exist. Again if we highlight the second div in the document you’ll see the space it occupies:
Since in this case you’re explicitly setting a width of 200px, there is no space to the right of the floated div for the text to exist, so it gets pushed down below the floated div. Here’s an image that might make it all clearer. Let’s say we increase the width of the second div from 200px to 250px. We then get this:
Now that there’s room to the right of the first div, the text will begin next to it, and drop down below it once it runs out of room horizontally. Continue to increase the width of the second div and you’ll end up with the text of both divs existing next to each other horizontally.
What you want to take away from this is that setting a width on the second div doesn't kill the float rule of the first div, it just limits the amount of room for content to exist.
To quench your curiosity....div's are by default, block level elements....since you haven't clear'ed the float after the 1st block, they still have the effect on the container....
and since block-level-elements occupy the whole width,and the float effect still exist you have them wrapping around the floated div...
clear the divs and u'll see a different version quench your curiosity here
you can do
div {
display: inline-block;
}
Currently they are display block by default. And the default width of a block is 100% so thats why they appear below each other
Simple CSS question, I've been wondering for a while and I'd like to understand exactly how this works.
Let's say I have the following:
<div>
<p>some text</p>
<p style="float: left">some text</p>
</div>
If I remove the float: left from a given <p> element, the element and its previous sibling are stacked closer.
Why floating an element causes this increased margin at its top?
The reason for the difference is a behaviour known as collapsing margins.
Note that paragraphs have, by default, a user-agent defined top and bottom margin.
When the second paragraph does not have float: left, the bottom margin of the first paragraph and the top margin of the second paragraph are adjoining and so collapse into each other.
When the second paragraph has float: left, those two margins will no longer collapse into each other; they are no longer considered adjoining because:
Two margins are adjoining if and only if:
both belong to in-flow block-level boxes that participate in the same block formatting context
[...]
Following the "block formatting context" link reveals that:
Floats [...] establish new block formatting contexts for their contents.
The spec goes on to say:
Note the above rules imply that:
Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
[...]
This doesn't occur for me on Chrome19.. but this would occur because of your browser's default stylesheet. If you want to prevent against this happening, use margin: 0; padding: 0; on the floated element.
I've captured an illustration of a CSS two-column layout I've set up, while using the following rule for the orange containers:
.embedded_post{
float: left;
width: 46%;
margin-right: 20px;
padding: 10px;
display: inline-block;
}
As can be seen, the second orange container on the right column is preventing the second orange container on the left column from floating up to the top left box.
This happens apparently since float:left automatically grants the element with a block level flow.
How can I get the second box on the left column to be positioned under the first one?
can you wrap your columns in another pair of divs, so that floating in the right column won't affect floating in the left?
<div id='left_column'>
<div class='embedded_post'></div>
<div class='embedded_post'></div>
</div>
<div id='right_column'>
<div class='embedded_post'></div>
<div class='embedded_post'></div>
<div class='embedded_post'></div>
</div>
css:
#left_column, #right_column {
float:left;
}
you've answered it yourself, there are a couple of options:
trick yourself by granting the div elements with an inline level flow, i.e. specifying display: inline (not recommended).
update the markup to be more semantic and alter the layout to conform to the desired result, e.g. replacing the divs with spans (preferred).
The second div on the left has less width than the rest of the divs, this might have something to do with it. Also, the combination with your (desired) structure and the margin-right isn't how I would do it. In fact, the margin-right may, depending on the with of the parent div of the embedded_post divs, screw up your structure and cause postioning problems.
It works fine when I try it.
p.s. keep in mind that in Firefox, the padding adds to the width/height of the div while this doesn't happen in other browsers.
I am having a hard time grasping the concept of vertical margins collapsing in nested elements. I came an article at http://www.howtocreate.co.uk/tutorials/css/margincollapsing explaining how it works however am confused by its explanation. So in its example it cites that there are 2 elements as follows
<div style="margin-top:10px">
<div style="margin-top:20px">
A
</div>
</div>
Seeing that the inner div has a margin of 20px, that is what will be applied for the entire block of code. What confuses me is everything after that and not yet looking about issues with Internet Explorer 7. Would someone be able to explain it for a complete newbie to CSS in a simplified manner?
Two-ish rules to remember:
If margins touch, they collapse.
Nested items "snuggle" if only margin separates them.
Elements outside the "Flow" behave differently. That is, this behavior does not apply the same to floated, or position:fixed, or position:absolute elements.
So for this HTML (nested divs) :
<div id="outer">
<div id="inner">
A
</div>
</div>
and this initial CSS:
#outer {
margin-top:10px;
background:blue;
height: 100px;
}
#inner {
margin-top:20px;
background:red;
height: 33%;
width: 33%;
}
The margin collapses to the max of the touching margins and the nested div "snuggles" to the start of the container, like so: (See it at jsFiddle.)
But, the moment the two margins are separated -- by a border or by preceding content in the container, for example -- the margins no longer touch, so they no longer collapse.
EG, just a little, non-breaking white-space , like so:
<div id="outer">
<div id="inner">
A
</div>
</div>
kills the collapse : (See that at jsFiddle.)
Using a border, instead of leading text : (Fiddle)
A diagram may help:
In case it wasn't obvious: blue = outer div, red = inner div; I've drawn them with constant height and horizontal positioning. You can work out what happens if the height is fitted to the contents etc.
The "Before collapsing" column shows what you get if the margins aren't considered adjacent, e.g. if you draw the border of the blue/outer div; but if there is no border, then you get the "After collapsing" column. The top row switches the two margins around from the example, because I think the behaviour in this case is more intuitive; the bottom one shows the example at howtocreate and is consistent with the top row.
Two-ish rules to remember:
If margins touch, they collapse. Nested items "snuggle" if only margin separates them. Elements outside the "Flow" behave differently. That is, this behavior does not apply the same to floated, or position:fixed, or position:absolute elements.
Brock Adams is correct, but I also wanted to add that "overflow:hidden" can also prevent nested margins from collapsing.