I'm confused by the interaction I'm seeing between the overflow property on an element and float on a sibling element. Consider the following:
.div1 {
float: left;
width: 100px;
height: 50px;
margin: 10px;
border: 3px solid #73AD21;
}
.div2 {
border: 1px solid red;
width: 50px;
height: 150px;
}
<h2>Without clear</h2>
<div class="container">
<div class="div1">div1</div>
<div class="div2">div2 - Notice that div2 is after div1 in the HTML code. However, since div1 floats to the left, the text in div2 flows around div1.</div>
</div>
(This example was adapted from this example on w3schools: https://www.w3schools.com/css/tryit.asp?filename=trycss_layout_clear
In this case, dev1 floats to the left of div2, and is within the box for div2 — e.g., the border for div2 extends above and to the left of div1, but the text content of div2 wraps around div1. But also note: because of the width/height set on div2, the text in div2 overflows below.
Now, add overflow:hidden; to div2:
.div1 {
float: left;
width: 100px;
height: 50px;
margin: 10px;
border: 3px solid #73AD21;
}
.div2 {
border: 1px solid red;
width: 50px;
height: 150px;
overflow: hidden;
}
<h2>Without clear</h2>
<div class="container">
<div class="div1">div1</div>
<div class="div2">div2 - Notice that div2 is after div1 in the HTML code. However, since div1 floats to the left, the text in div2 flows around div1.</div>
</div>
Now div2 is entirely to the right of div1 — it's border no longer extends around div1.
Why does adding the overflow:hidden property to div2 change its layout interaction wtih div1 in this way? (Same effect also happens for overflow:auto or overflow:scroll.)
You need to consider the concept of Block formatting contexts where you can read the following:
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
So when adding overflow:hidden, the div2 will establish a new BFC then we can read:
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 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 ref
To make it easy, when an element create a BFC its content will no more interact with the outside world. From the MDN you can read:
Setting overflow: auto created a new BFC containing the float. Our <div> now becomes a mini-layout inside our layout. Any child element will be contained inside it.
Related
Here are my test code:
.div1 {
width: 100px;
background: red;
padding-top: 0.1px;
border: solid;
}
.div2 {
width: 100px;
margin: 100px;
background: pink;
}
.div3 {
overflow: visible;
}
.div4 {
overflow: hidden;
}
<p>sample 1</p>
<div class="div1">
<div class="div2"><div class="div3"></div></div>
</div>
<hr />
<p>sample 2</p>
<div class="div1">
<div class="div2"><div class="div4"></div></div>
</div>
According to the spec:
top and bottom margins of a box that does not establish a new block formatting context and that has zero computed 'min-height', zero or 'auto' computed 'height', and no in-flow children
margins of both div2 may not collapse. However, in sample 2, margins didn't collapse as I thought, but they collapse in sample 1. So why?
According to BoltClock's explanation, margins in sample 1 collapse because the in-flow child(i.e. div3) don't establish a new BFC. I tried another test:
.div1 {
width: 100px;
background: red;
padding-top: 0.1px;
border: solid;
}
.div2 {
width: 100px;
margin: 100px;
background: pink;
}
.div5 {
overflow: visible;
float: left;
/* position: absolute;*/
}
<div class="div1">
<div class="div2"><div class="div5"></div></div>
</div>
With float value other than none, div5 establish a new BFC, so margins of div5 may not collapse accordingly. But they collapse unfortunately.
From the spec:
Note the above rules imply that:
A box's own margins collapse if the 'min-height' property is zero, and it has neither top or bottom borders nor top or bottom padding, and it has a 'height' of either 0 or 'auto', and it does not contain a line box, and all of its in-flow children's margins (if any) collapse.
Emphasis mine.
In sample 2, div4 establishes a new block formatting context. As a result, its own margins are not adjoining (i.e. it does not meet the condition that you have quoted), and so they cannot collapse. Because div4's margins do not collapse, the margins of its own div2 parent cannot collapse through it. As a result, none of the positive margins in sample 2 collapse.
Floating an element takes it out of the flow, so the margins of div2 in your new test are able to collapse because it has no in-flow children.
This is very interesting question. I never faced with this before, but now, according to some articles I found that some situation prevents margin collapsing:
http://www.sitepoint.com/web-foundations/collapsing-margins/
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
Apparently overflow prevent margin collapsing not only if it is applied on parent element ;)
From other article I saw, that this effect is used in several micro clearfix.
<div style="width:<?php echo $w; ?>">
<div style="float:left;margin-right:10px;width:200px">whatever</div>
<h2 style="border-bottom:solid 1px black">title</h2>
</div>
By default, the width of h2 would be $w, and the bottom border will strike the inner div, I want the h2 to automatically occupy the rest width, no matter what $w's value is, the h2's width should be $w - 200 - 10. How to achieve this in pure CSS?
PS: if I set css h2{float:left}, h2's width would depend on its inner text's length. To have the h2 element occupy the rest of the width (so that I can have a beautiful bottom border) I have to manually set a width value for h2, which is what I'm trying to avoid.
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.
Therefore, you can just add
h2 {
overflow: hidden;
}
div {
width: 500px; /* $w */
}
div > div {
float: left;
margin-right: 10px;
width: 200px;
}
h2 {
border-bottom: solid 1px black;
overflow: hidden;
}
<div>
<div>whatever</div>
<h2>title</h2>
</div>
You may also want to style the outer div with overflow: hidden just in case the floated element is taller than the h2.
I have a content div where all the content is located. this div has a border. I would like to place things inside this div so that this div expands if the content inside is too big. Should the items inside the content div be a "div" or a "p" and what css position should they have?
CSS:
#content{
position: relative;
margin-left: auto;
margin-right: auto;
border: 1px solid #E0E0E0;
min-height: 200px;
width: 1000px;
padding: 0px 0px 80px 0px;
background-color: #fff;
}
When you set width: 1000px; it will prevent the content div from being any wider. I suspect you want min-width: 1000px; instead.
For internal content use p tags if you are creating paragraphs that only use inline html elements. If you are using block level elements then use div tags.
I can't say how you should style your internal elements because I know nothing about your design specs.
Contents of the #content div can be either p or div elements its up to you. The #content div will expand to the height of its content either way unless you have elements inside #content with a float property.
If that is that case you can do something like below to make the #content div expand its height.
<div id="content">
<div style="float:right; border:1px solid red; height:500px;"></div>
<div style="clear:both;"></div>
</div>
The important part here is the latest div with clear:both property which fixes the height of the parent element.
You should still be able to use a DIV. If you use height:auto; that should make it expand based on your content. Also I think you can use min-height:200px; and height:auto; together; With that said. I also agree with mrtsherman, if you set a width or height to a specific pixel it is going to limit you to those constraints.
How does the CSS Block Formatting Context work?
CSS2.1 specifications says that in a block formatting context, boxes are laid out vertically, starting at the top. This happens even if there are floated elements in the way, except if the block box established a new block formatting context. As we know, when browsers render block boxes in a block formatting context, the floated element is omitted, why does establishing a new block formatting context work?
How are boxes (block boxes and inline boxes) laid out in the normal flow?
I read somewhere that block elements generate block boxes, but floating elements are ignored when a user agent draws box and take them into account when they fill out content. Whilst floating elements will overlap other elements's boundary of the boxes, the solution is establishing a new block formatting context for the overlapped elements using overflow:hidden.
"New block formatting context is still block formatting", so when drawing a box, it will also treat the floating element as if it doesn't exit. Is that right or have I misunderstood "new block formatting context?"
Update:more questions
By saying "It's this behaviour that's useful for columnar style layouts. The main use of it however is to stop floats, say in a "main content" div, actually clearing floated side columns, i.e. floats that appear earlier in the source code."
I don't understand the meaning, I will provide an example, maybe you will understand me.
.content {
background: #eee;
color #000;
border: 3px solid #444;
width: 500px;
height: 200px;
}
.float {
background: rgba(0, 0, 255, 0.5);
border: 1px solid #00f;
width: 150px;
height: 150px;
float: right;
}
p {
background: #444;
color: #fff;
}
<div class="content">
<h3>This is a content box</h3>
<p>It contains a left floated box, you can see the actual content div does go under the float, but that it is the <h3> and <p> <b>line boxes</b> that are shortened to make room for the float. This is normal behaviour.</p>
<div class="float">floated box</div>
</div>
I thought the floating box should float to the top of the containg block-the div with class content. Besides, if the floating box appears earlier in the markup, then it will display what I think it should be.
.content {
background: #eee;
color #000;
border: 3px solid #444;
width: 500px;
height: 200px;
}
.float {
background: rgba(0, 0, 255, 0.5);
border: 1px solid #00f;
width: 150px;
height: 150px;
float: right;
}
p {
background: #444;
color: #fff;
}
<div class="content">
<div class="float">floated box</div>
<h3>This is a content box</h3>
<p>it contains a left floated box, you can see the actual content div does go under the float, but that it is the <h3> and <p> <b>line boxes</b> that are shortened to make room for the float, this is normal behaviour</p>
</div>
How can we explain this? Can we use "block formatting context and inline formatting context" to explain it?
Block Formatting Contexts
Floats, absolutely positioned
elements, block containers (such as
inline-blocks, table-cells, and
table-captions) that are not block
boxes, and block boxes with 'overflow'
other than 'visible' (except when that
value has been propagated to the
viewport) establish new block formatting contexts for their contents.
With my bold, it's the establish bit that is important
What this means is that the element you use overflow (anything other than visible) or float or inline-block..etc on becomes responsible for the layout of its child elements. It's the child elements which are then "contained", whether that's floats or collapsing margins they should be wholly contained by their bounding parent.
In a block formatting context, each
box's left outer edge touches the left
edge of the containing block (for
right-to-left formatting, right edges
touch)
What the above line means:
Because a box can only be rectangular and not irregular shaped this means a new block formatting context between two floats (or even beside one) will not wrap around neighbouring side floats. The inner, child boxes can only extend as far as to touch their parents left (or right in RTL) edge. It's this behaviour that's useful for columnar style layouts. The main use of it however is to stop floats, say in a "main content" div, actually clearing floated side columns, i.e. floats that appear earlier in the source code.
Float Clearance
In normal circumstances floats are supposed to clear all previous floated elements, that's previously floated in the whole source code, not just your displayed "column"
The telling quote from the "float clearance specs" is:
This property indicates which sides of
an element's box(es) may not be
adjacent to an earlier floating box.
The 'clear' property does not consider
floats inside the element itself or in other block formatting contexts
So say you have a three column layout where the left and right columns are floated left and right respectively, the side columns are now in new Block Formatting Contexts, because they are floated (remember float is also one of the properties that establish a new BFC), so you can happily float list elements inside them and they only clear floats which are already inside the side columns they no longer care about floats previously in the source code
##To make the main content a new Block Formatting Context or not?
Now that middle column, you can simply margin it from both sides so that it appears to sit neatly between the two side floated columns and take the remaining width, a common way to get desired width if the centre column is "fluid" - which will be fine until you need to use floats/clearance inside your content div (a common occurrence for those using "clearfix" hacks or templates including them)
Take this very simple code:
#left-col {
border: 1px solid #000;
width: 180px;
float: left;
}
#right-col {
border: 1px solid #000;
width: 180px;
float: right;
height: 200px;
}
#content {
background: #eee;
margin: 0 200px;
}
.floated {
float: right;
width: 180px;
height: 100px;
background: #dad;
}
<div id="left-col">left column</div>
<div id="right-col">right column</div>
<div id="content">
<h3>Main Content</h3>
<p>Lorem ipsum etc..</p>
<div class="floated">this a floated box</div>
<div class="floated">this a floated box</div>
</div>
It produces the following:
In general this is fine, especially if you have no background colours or internal (in the main content) floats - notice the floats are fine (not cleared yet) they're doing probably what you except them to but they, the H3's top margin and the p's bottom margin are not actually really contained by the content div (lightgrey background).
So to the same simple margined scenario of above code add:
.clear-r {clear: right;}
to the CSS, and change the second HTML floated box to:
<div class="floated clear-r"> this a floated cleared box</div>
#left-col {
border: 1px solid #000;
width: 180px;
float: left;
}
#right-col {
border: 1px solid #000;
width: 180px;
float: right;
height: 200px;
}
#content {
background: #eee;
margin: 0 200px;
}
.floated {
float: right;
width: 180px;
height: 100px;
background: #dad;
}
.clear-r {
clear: right;
}
<div id="left-col">left column</div>
<div id="right-col">right column</div>
<div id="content">
<h3>Main Content</h3>
<p>Lorem ipsum etc..</p>
<div class="floated">this a floated box</div>
<div class="floated clear-r">this a floated cleared box</div>
</div>
This time you get this:
The second float is clearing the right side but it's clearing the whole height of the right column. The right column is floated earlier in the source code so it's clearing it as told! Probably not the desired effect though, also note the h3 and p margins are still collapsed (not contained).
###Make it establish a Block Formatting Context, for the sake of the children!
and finally make the main content column take responsibility - become a Block Formatting Context - for its contents : remove margin: 0 200px; from the main content CSS and ADD overflow: hidden; and you get this:
#left-col {
border: 1px solid #000;
width: 180px;
float: left;
}
#right-col {
border: 1px solid #000;
width: 180px;
float: right;
height: 200px;
}
#content {
background: #eee;
overflow: hidden;
}
.floated {
float: right;
width: 180px;
height: 100px;
background: #dad;
}
.clear-r {
clear: right;
}
<div id="left-col">left column</div>
<div id="right-col">right column</div>
<div id="content">
<h3>Main Content</h3>
<p>Lorem ipsum etc..</p>
<div class="floated">this a floated box</div>
<div class="floated clear-r">this a floated cleared box</div>
</div>
This is probably much more like what you would expect to happen, note now the floats are contained, they clear properly ignoring the right side column, and also the h3 and p margins are contained instead of collapsed.
With the extensive use of resets these days the margins are less noticeable (and IE still doesn't get them quite right) however what just happened to the centre "main content" is that it became a Block Formatting Context and is now responsible for its own child (descendant) elements. It's actually very similar to Microsoft's early days notion of hasLayout, it uses the same properties display: inline-block, float, and overflow anything other than visible, and of course table cells always have layout.. it is however without the bugs ;)
##Update: re more information in question:
When you say "but floating elements are ignored when user agent draws box and take them into account when they fill out content."
Yes floats normally overlay their container boxes, is that what you mean about parent boundaries? When a block element is drawn and it contains a float the block parent itself is drawn as a rectangle under the float and it is the "inline anonymous boxes" or simply "line boxes" of the other child elements that are shortened to make room for the float
Take this code:
#content {
background: #eee;
color #000;
border: 3px solid #444;
}
.float {
background: rgba(0, 0, 255, 0.5);
border: 1px solid #00f;
width: 150px;
height: 150px;
float: left;
margin: 10px;
}
p {
background: #444;
color: #fff;
}
<div id="content">
<div class="float">floated box</div>
<h3>This is a content box</h3>
<p>it contains a left floated box, you can see the actual content div does go under the float, but that it is the <h3> and <p> <b>line boxes</b> that are shortened to make room for the float, this is normal behaviour</p>
</div>
Which produces this:
You see that the parent element doesn't actually contain the float, as in it doesn't wrap it entirely.. the float is simply floating on top of the content - if you were to keep adding content to the div it would eventually wrap underneath the float because there would be no need for the (anonymous) "line boxes" of the p element to shorten themselves any more.
I've coloured the paragraph element so you can see that it too actually goes under the float, the darkgray background is where the paragraph starts, the white text is where the "anonymous line box" starts - it's only actually them that "make room" for the float, unless you tell it otherwise (i.e. you change the context)
Again referring to the above picture, if you were to margin the left side of thep element, yes it will stop the text wrapping under the bottom of the float because the "line boxes" (the white text) will only touch the left edge of their container, and you will bring the coloured background of the p to the right, clear of the float, but you won't have changed the behaviour of the p's formatting context. Like the centre column in the first picture way above ;)
<style>
div#float {
text-align: center;
float: left;
width: 150px;
height: 150px;
border: 1px solid blue;
background: gold;
}
div.content {
background: yellow;
border: 1px solid purple;
height: 150px;
}
</style>
<div id='float'>
Float text.
</div>
<div class='content'>
Content text.
</div>
<div class='content'>
Content text.
</div>
can anyone explain how the 2nd div content is on the newline ? while the 1st div is inline with div#float?
By default, divs will take up the entire width of the block. Your first one is just beginning after the floated div because that's where it can begin. Since both your content divs are block-level elements, they will take up the entire width available to them.
There are lots of ways to control this, but I'm not sure what you're after.
The second div is displayed as a block-element. Block elements have a width of 100%, so there is no room left for the first div to appear on the left size of your second div.
try switching the "display" css property to "inline-style"
The first <div class='content'> is 150px tall, the same as the #float one, so it's pushed down exactly one line. If you wanted the #float to "span" both lines, give it more height, e.g.:
div#float {
text-align: center;
float: left;
width: 150px;
height: 300px;
border: 1px solid blue;
background: gold;
}
You can try it out here.
As becomes clear with above answers, this is not an issue specific about divs. It's about something called "The flow" within html-pages.
DIV's render default as an block element, which gives it a maximum width. When you float such an element, it loses this effect. Block elements however do not automatically clear floats. Thus, the first contentdiv takes all space available next to the float. The other contentdiv starts at the newline.
It's behaving exactly as it should. The first div in the markup is floated and thus taken out of the flow. It'll take up the 150x150 slot up in the top left corner and anything that comes after it in the markup will try to squeeze in the left over space to the right of the floated div which is what the first content div does. div's are block level elements so they will take up the entire width of the available space. Unlike an inline element, they will not shrink to fit the rendered text.
The first content div will stretch out till the rightmost edge of the window. If you're wondering why the first div (float div) did not behave like a block level element, it's because it was floated, which will cause it to shrink to fit it's contents (in your case you gave it an explicit width of 150px).
Once the browser has rendered the float div and the content div, it has exhausted the left over space so it goes to the next line and starts from the very beginning of that line for the second content div.
Looks like you are trying to set up a navigation bar followed by content. If you wrap your content in a div and float that div to the left, you will stay to the right of the gold div but a column drop will occur when the browser is resized too small to accommodate them. So you need a parent div with a width for both the float and content divs. I added an 800 pixels outerwrapper div to your markup.
.....
div#contentwrapper {
float: left;
width: 550px;
}
#outerwrapper {
width: 800px;
}
</style>
</head>
<body>
<div id="outerwrapper">
<div id='float'>
Float text.
</div>
<div id="contentwrapper">
<div class='content'>
Content text.
</div>
<div class='content'>
Content text.
</div>
</div>
</div>
.....
You might also want to use a different name than the css reserved word "float" for your divs. For more CSS float tutorials.