<div style="float: left;">Left</div>
<div style="float: right;">Right</div>
<div style="clear: both; margin-top: 200px;">Main Data</div>
Why is the margin:top for 'Main Data' not working in the code above?
You could put the two floated divs into another one that's got "overflow: hidden" set:
<div style='overflow:hidden'>
<div style="float: left;">Left</div>
<div style="float: right;">Right</div>
</div>
<div style="clear: both; margin-top: 200px;">Main Data</div>
edit — To add a bit to this 5-year-old answer: I think the cause of the confusing behavior is the somewhat complicated process of margin collapse. A good trick with the original HTML from the OP is to add a CSS rule like this:
div { border: 1px solid transparent; }
Poof! Now (without my additional <div>) it works fine! Well, except for that extra pixel from the borders. In particular, I think it's a combination of the way that clear: both works and the margin collapse rules that result in the unexpected layout from the code in the OP.
edit again — For the complete (and, I think, completely accurate) story, see Mark Amery's excellent answer. The details have some complexity that this answer glosses over.
While Pointy shows how you can wrap the floats in a div, alternatively you can insert an empty div between the floats and the main data section. For example:
<div style="float: left;">Left</div>
<div style="float: right;">Right</div>
<div style="clear: both;"></div>
<div style="margin-top: 200px;">Main Data</div>
This might prove useful in cases where adding a div wrapper around some HTML is not desirable.
The logic behind this in the spec is mind-bending, and involves a complicated interaction of the rules for clearance and collapsing margins.
You're probably familiar with the conventional CSS box model, in which the content box is contained within a padding box contained within a border box contained within a margin box:
For elements with clear set to something other than none, an additional component may be introduced to this model: clearance.
Values other than 'none' potentially introduce clearance. Clearance inhibits margin collapsing and acts as spacing above the margin-top of an element.
In other words, the box model in those cases really looks more like this:
But when is clearance introduced, and how big should it be? Let's start with the first of those questions. The spec says:
Computing the clearance of an element on which 'clear' is set is done by first determining the hypothetical position of the element's top border edge. This position is where the actual top border edge would have been if the element's 'clear' property had been 'none'.
If this hypothetical position of the element's top border edge is not past the relevant floats, then clearance is introduced, and margins collapse according to the rules in 8.3.1.
Let's apply this logic to the question asker's code. Remember, we're trying to explain the position of the third div in the code below (backgrounds added to aid in visualisation):
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: both; margin-top: 200px; background: blue;">Main Data</div>
Let us imagine, as the spec asks us to, that clear is set to none on the third div, instead of both. Then what would the snippet above look like?
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: none; margin-top: 200px; background: blue;">Main Data</div>
Here, the third div is overlapping the two floated divs. But wait; why is this so? Sure, it's allowable for floated elements to overlap block-level ones (per the Floats spec, "Since a float is not in the flow, non-positioned block boxes created before and after the float box flow vertically as if the float did not exist."), but our third div has loads of margin-top on it, and comes after the two floated divs; shouldn't the two floated divs appear at the top of the body, and the third div appear 200px down, well below them?
The reason this doesn't occur is that the margin of the third div collapses into the margin of the divs' parent (in this case, the body - but the same behaviour happens if you wrap all three divs in a parent div). The Collapsing margins spec (quoted below with several irrelevant details omitted) tells us that:
Adjoining vertical margins collapse...
Two margins are adjoining if and only if:
both belong to in-flow block-level boxes that participate in the same block formatting context
no line boxes, no clearance, no padding and no border separate them ...
both belong to vertically-adjacent box edges, i.e. form one of the following pairs:
top margin of a box and top margin of its first in-flow child
...
The third div in our example certainly isn't the body's first child, but it is its first in-flow child. Note that per https://www.w3.org/TR/CSS22/visuren.html#positioning-scheme:
An element is called out of flow if it is floated, absolutely positioned, or is the root element. An element is called in-flow if it is not out-of-flow.
Since the first and second div in our example are floated, only the third div is in-flow. Thus its top margin adjoins the top margin of its parent, and the margins collapse - pushing down the entire body, including the two floated elements. Thus the third div overlaps its siblings despite having a large margin-top. Consequently - in this hypothetical case, where the third element's clear is set to none - we satisfy the condition that:
the element's top border edge is not past the relevant floats
Thus:
clearance is introduced, and margins collapse according to the rules in 8.3.1
How much clearance? The spec gives browsers two options, with a couple of clarifying notes:
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.
Alternatively, clearance is set exactly to 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.
Note: Both behaviors are allowed pending evaluation of their compatibility with existing Web content. A future CSS specification will require either one or the other.
Note: The clearance can be negative or zero.
Before we can start applying these rules, we immediately hit a complication. Remember that collapsing margin that we had to take into account in the hypothetical case where clear was none? Well, it doesn't exist in this non-hypothetical case where we're calculating the clearance to use, because the existence of the clearance inhibits it. Recall the collapsing margin rules from 8.3.1, quoted earlier, dictate that margins are only adjoining if:
no line boxes, no clearance, no padding and no border separate them
(emphasis added). As such, the third div's top margin and the top margin of its parent are no longer adjoining. We can simulate this pre-clearance scenario in our example snippet by keeping clear: none but adding padding-top: 1px to the body, which also disables margin collapse, per the rule quoted above.
body {
padding-top: 1px;
}
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: none; margin-top: 200px; background: blue;">Main Data</div>
Now, unlike when the margins were collapsed, our third div is comfortably below its two floated siblings. But we have already decided, based upon a hypothetical scenario where the margins did collapse, that clearance must be added; all that remains is to choose the amount of clearance, in order to:
place the border edge of the block even with the bottom outer edge of the lowest float that is to be cleared
And so we have no choice but to apply a negative clearance to the third div, in order to drag its top border edge up to touch the bottom outer edge (also known as margin edge) of the floated elements above it. As such, if the floated elements are each 10px high and the third div has 200px of top margin, -190px of clearance will be applied. That, at last, gets us to the final result seen by the question asker:
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: both; margin-top: 200px; background: blue;">Main Data</div>
(Note that if you inspect the third div in the snippet above using your browser's dev tools, you will still be able to see the 200px of top margin above the div, going way out above all the rest of the content - it's just that the entire margin box has been hauled upwards by the large negative clearance.)
Simple!
Pointy and Randall Cook have excellent answers. I thought I'd show one more solution.
<div style="float: left;">Left</div>
<div style="float: right;">Right</div>
<div style="float: left; clear: both; margin-top: 200px;">Main Data</div>
If you make the 3rd element "float: left;" AND "clear: both;", it should have the desired effect of giving the 3rd element a 200 pixel margin. Here's a link to an example.
This also might affect other followup elements as to whether they need to be floats or not. However, it might also have the desired effect.
Alternative solution:
You can actually put a margin-bottom on the floated elements to push
DOWN the element underneath that has clear: both.
http://jsfiddle.net/9EY4R/
Note: Having made this suggestion I have to immediately retract it as not generally a good idea, but in some limited situations may appropriate;
<div class='order'>
<div class='address'>
<strong>Your order will be shipped to:</strong><br>
Simon</br>
123 Main St<br>
Anytown, CA, US
</div>
<div class='order-details'>
Item 1<br>
Item 2<br>
Item 3<br>
Item 4<br>
Item 5<br>
Item 6<br>
Item 7<br>
Item 8<br>
Item 9<br>
Item 10<br>
</div>
<div class='options'>
<button>Edit</button>
<button>Save</button>
</div>
</div>
The panel with items is called order-details with this css
.order-details
{
padding: .5em;
background: lightsteelblue;
float: left;
margin-left: 1em;
/* this margin does take effect */
margin-bottom: 1em;
}
In the above fiddle - the yellow panel has a margin-top, but unless it is greater than the tallest floated item then it won't do anything (of course that's the whole point of this question).
If you set the margin-top of the yellow panel to 20em then it will be visible because the margin is calculated from the top of the outer blue box.
Use 'padding-top' in your main data div instead. Or, alternatively, wrap the main data div in one with 'padding-top'.
Try setting a bottom margin on one of the floated elements. Alternatively, you can wrap the floats in a parent element, and use a css hack to clear it without additional markup.
Sometimes a combination of position relative and margin can solve these type of problems.
I use this technique for my alignright and alignleft classes in WordPress.
For instance if I want a "bottom margin" that is respected by clearing elements you can use.
.alignright{
float: right;
margin-left: 20px;
margin-top: 20px;
position: relative;
top: -20px;
}
For your example you could do something like
<div style="float: left;">Left</div>
<div style="float: right;">Right</div>
<div style="clear: both; margin-bottom: 200px; position: relative; top: 200px;">Main Data</div>
Related
I have two divs. The first one is width: 50% and the second on is width: 80%. When I set float: left to the first one, the text of the second one is placed on the right of the first one. That's ok, it is what I expect. See the code here:
<div style="float: left; width: 50%; background: orange">floated div</div>
<div style="width: 80%; background: red">second div</div>
The doubt: if I set width: 30% to the second div. The div is placed below the first one, why? Check the snippet:
<div style="float: left; width: 50%; background: orange">floated div</div>
<div style="width: 30%; background: red">second div</div>
float doesn't cause block elements to display side by side or wrap necessarily. Using float will cause text and inline elements that come after the floated element to wrap around it. So if the second div is wider than the first, the text in the second will wrap around the first. If the second div is more narrow (or the same size) as the first, it won't wrap since the second div is not just text or an inline element.
https://developer.mozilla.org/en-US/docs/Web/CSS/float
The float CSS property specifies that an element should be taken from the normal flow and placed along the left or right side of its container, where text and inline elements will wrap around it.
In your first example, the first div is floated and therefore removed from the flow of the document. The second div then occupies the space behind the first div and since there just happens to be enough room for the text you've given in the second div, it all stays neatly on the same line. If you add a lot of text to your second div, you'll see that it will overflow and begin to wrap under the first div.
In your second example, again the first div is floated and removed from the flow of the document. Now however, since you only have the second div a width of 30%, there's not enough room for the text that it contains to exist on the same line since it's very narrow, so the text is forced below the text of the first div. If you remove the text from the second div, it will essentially disappear beneath the floated first div.
Not sure what you are trying to do with the snippet, but I would just add a clear between the 2 div's.
<div style="float: left; width: 50%; background: orange">floated div</div>
<div style="clear: both;"></div>
<div style="width: 80%; background: red">second div</div>
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
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.
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;
}