According to [W3][1],
an element in the normal flow that establishes a new block formatting
context (such as an element with 'overflow' other than 'visible') must
not overlap the margin box of any floats in the same block formatting
context as the element itself.
You edited out the critical bit from the quote. The quote should be
The border box of a table, a block-level replaced element, or an
element in the normal flow that establishes a new block formatting
context (such as an element with 'overflow' other than 'visible') must
not overlap the margin box of any floats in the same block formatting
context as the element itself.
It's the border box of the BFC that must not overlap. The margin box of the BFC is not restricted.
Try this:
.float{
width:200px;
height:300px;
float:left;
background:yellowgreen;
margin-right:10px;
}
.bfc{
overflow:hidden; /*establish a new bfc*/
width:366px;
height:400px;
float: right;
background:blue;
margin-left:50px;/*overlap with div.float*/
}
<div class="float"></div>
<div class="bfc"></div>
I've decreased size of width of .bfc and added float:rigth; to the same selector.
Related
From the CSS Display Module Level 3 specs there is a note about block container that says:
Note: A block container box can both establish a block formatting
context and an inline formatting context simultaneously.
How is this possible conceptually?
And how are children boxes laid out then? For example, if we have both inline-level and block-level boxes inside block container, which formatting context is used in that case? Are both formatting contexts used at the same time or one of them "wins" and the other one is put aside?
It's entirely possible, and even necessary for certain CSS rules. The easiest way to understand this is with an example of such a box.
<div style="overflow:auto">hello world</div>
Here we have an element with display:block (by default for div elements) and overflow:auto. This is one way that an element's rendered box will establish a block formatting context. This affects, for example, how the box's location and dimensions are affected by the presence of floats.
Compare these two examples:
.formatting.contexts {
overflow:visible;
}
.container {
width:70px;
}
img {
float:left;
margin-right:3px;
}
<div class="container">
<img src="http://placehold.it/16" alt="placeholder grey square less than one line in height">
<div class="formatting contexts">hello world</div>
</div>
.formatting.contexts {
overflow:auto;
}
.container {
width:70px;
}
img {
float:left;
margin-right:3px;
}
<div class="container">
<img src="http://placehold.it/16" alt="placeholder grey square less than one line in height">
<div class="formatting contexts">hello world</div>
</div>
In the first example, the text wraps underneath the image. That's because the div with class "formatting contexts" has overflow:visible, so it doesn't form a block formatting context.
However, it contains only inline boxes - formed by the text content. So by the CSS rules, it establishes an inline formatting context. The text content can therefore be laid out horizontally in line boxes within this context. It is the first line box which is shrunk to avoid overlapping with the float.
In the second example, the text does not wrap underneath the image. That's because the div with class "formatting contexts" now has overflow:auto which means that it establishes a block formatting context, and it is the block box that is shrunk to avoid it overlapping the float. But its contents are just the same, just inline boxes, so it also establishes an inline formatting context.
<body>
<div class="content">
<div class="content-sidebar">
content-sidebar
</div>
<div class="content-main">
content-main
</div>
</div>
</body>
above is html code, and below is css code.
body {
margin: 0;
padding: 0;
}
.content {
background-color: yellow;
}
.content-sidebar {
background-color: red;
float: right;
margin-left: 30px;
}
.content-main {
background-color: green;
height: 300px;
overflow: hidden;
}
overflow hidden property creates new block formatting context in the .content-main, so .content-sidebar and .content-main are totally in different context.
so I thought that margin-right:30px on .content-main would work.
but it is working only in .content-sidebar (margin-left).
edited))
plus, I checked it with chrome dev tools, and margin-right on main div interacts with the browser. (not with the sidebar). but floated sidebar interacts with main div. why is that..?
The first thing to point out is that you say:
overflow hidden property creates new block formatting context in the .content-main, so .content-sidebar and .content-main are totally in different context.
That is incorrect. The overflow hidden property establishes a new block formatting context for its contents. It doesn't affect the context that it is in. So .content-sidebar and .content-main are in the same context. This is relevant for the quote below.
CSS 2.2 section 9.5 Floats says:
The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space. They may even make the border box of said element narrower than defined by section 10.3.3.
Here we have "must not overlap the margin box of any floats" That's why margin-left on the sidebar spaces the main section away from it. But we also have "make the border box of said element narrower" - Note the border box, not the margin box, so there's no requirement to position the margin of main so that it doesn't overlap with the floated sidebar.
I am reviewing the floats property which i learned before,I found a simple issue about floated elements with its own stacking order, the code as:
Example 1:
.box-1{
background: teal;
width:100px; height:100px;
float: left;
}
<div class="box box-1"></div>
<p> this is the text for the testing purpose<p>
I totally understand the text will wrap around the the box which is right next to the box-1, but when there is no text elements only two div boxes:
Example 2:
.box {
width:100px;
height:100px;
}
.box-1{
background:teal;
float:left;
}
.box-2{
background:blue;
}
<div class="box box-1"></div>
<div class="box box-2"></div>
This time the .box-1 will overlap the .box-2 since it was floated and taken from the normal document flow.
So my questions are:
Since the p tag is a block element and it could be considered as a box. but why in the example 2 the p tag is moving to the right after the box-1? but in the example 1 there is totally different behavior?
It is because of the floated elements has same stack order like p tags and both of them have higher stacking order than the non-floated box as .box-2 here?
I am going to add more explanation as I think the accepted answer omitted some important parts and didn't provide a real explanation. Let's start with the definition of float from the MDN documentation:
The float CSS property specifies that an element should be placed
along the left or right side of its container, allowing text and
inline elements to wrap around it. The element is removed from the
normal flow of the web page, though still remaining a part of the flow
(in contrast to absolute positioning).
So yes float behave like absolute positioning but not exactly because element is still a part of the flow.
Now both of your examples behave exactly the same, the only difference is that in the first one you have text. So the float element doesn't push the p like you think but overlap it and push only the text. If you inspect the element you will see this:
So p is a block element and behave exactly like the box-2 in your second example and the floated element box-1 is above it. This confirms that in both examples we have the same thing but in the first one we have text inside the block element p and unlike absolute positioned element, floated element pushs text as described above.
Now why the floated element is above the p tag and above the box-2?
You can find this answer within the specificaton of the painting order. Both elements are not positioned and one is floated:
For all its in-flow, non-positioned, block-level descendants in tree
order: If the element is a block, list-item, or other block
equivalent:
All non-positioned floating descendants, in tree order.
As we can see, we first draw the in-flow element in the step (4) (in your case the p tag and the box-2) then we print the floating ones in the step (5) (the box-1).
To avoid such things you have two solutions (like provided in other answers):
You clear float which is a common solution used in order to avoid element being affected by the floating behavior.
You make the box-2 an inline-block element because inline-block behave like inline-elements and they are also pushed by floated element
I believe I understand the issue now (somewhat). Because they have the same dimensions, and because float: left kind of acts like display: absolute while maintaining text space, it's pushed box-2's text to the bottom.
You can get around this setting display: inline-block for box-2 and interestingly enough, putting an overflow: hidden or overflow: auto also fixes it.
.box {
width:100px;
height:100px;
}
.box-1{
float:left;
}
.box-2{
background:blue;
overflow: auto
}
<div class="box box-1">box-1</div>
<div class="box box-2">box-2</div>
Try this. Just add the overflow:hidden in your css for .box class.
.box {
width:100px;
height:100px;
overflow:hidden;
}
.box-1{
background:teal;
float:left;
}
.box-2{
background:blue;
}
<div class="box box-1">box-1</div>
<div class="box box-2">box-2</div>
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/
HTML:
<div id="float_left">
DIV1
</div>
<div id="without_overflow">
DIV2
</div>
css:
#float_left{
float: left;
width:200px;
background-color: red;
}
#without_overflow{
width:400px;
height:40px;
background-color:green;
}
http://jsfiddle.net/kgypo14y/1
The result of the above code is what I expected. However, if I added overflow:auto or overflow:hidden to the second div the result is totally unexpected to me.
http://jsfiddle.net/60nzadLz/2/
Do you have a good explanation for that?
Thank you
Those values of overflow cause the element to establish a new block formatting context. A float may never intrude another block formatting context, so the entire element is shifted away from the float. From the spec:
The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space.