Why an inline-block container doesn't collapse when contains only floated items?
Because inline-block
generate a block formatting context
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. ref
and you can read in the MDN:
Formatting contexts affect layout, but typically, we create a new block formatting context for the positioning and clearing floats rather than changing the layout, because an element that establishes a new block formatting context will:
- contain internal floats.
- exclude external floats.
- suppress margin collapsing.
Why do inline elements behave like block level elements when floated?
This behavior is defined in the point 3 of this CSS2.1 section:
9.7 Relationships between
display
,position
, andfloat
The three properties that affect box generation and layout —
display
,position
, andfloat
— interact as follows:
- If
display
has the valuenone
, thenposition
andfloat
do not apply. In this case, the element generates no box.- Otherwise, if
position
has the valueabsolute
orfixed
, the box is absolutely positioned, the computed value offloat
isnone
, and display is set according to the table below. The position of the box will be determined by thetop
,right
,bottom
andleft
properties and the box's containing block.- Otherwise, if
float
has a value other thannone
, the box is floated anddisplay
is set according to the table below.- Otherwise, if the element is the root element,
display
is set according to the table below, except that it is undefined in CSS 2.1 whether a specified value oflist-item
becomes a computed value ofblock
orlist-item
.- Otherwise, the remaining
display
property values apply as specified.┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓
┃ #Specified value# ┃ #Computed value# ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩
│ inline-table │ table │
├──────────────────────────────────────────────────────────┼──────────────────┤
│ inline, table-row-group, table-column, table-column-group│ block │
│ table-header-group, table-footer-group, table-row │ │
│ table-cell, table-caption, inline-block │ │
├──────────────────────────────────────────────────────────┼──────────────────┤
│ others │ same as specified│
└──────────────────────────────────────────────────────────┴──────────────────┘
In Display Level 3, this process is called blockification:
2.7. Automatic Box Type Transformations
Some layout effects require blockification or inlinification of the box type, which sets the box’s outer display type, if it is not
none
orcontents
, toblock
orinline
(respectively).Some examples of this include:
- Absolute positioning or floating an element blockifies the box’s display type. [CSS2]
Why doesn't the height of a container element increase if it contains floated elements?
The floated elements do not add to the height of the container element, and hence if you don't clear them, container height won't increase...
I'll show you visually:
More Explanation:
<div>
<div style="float: left;"></div>
<div style="width: 15px;"></div> <!-- This will shift
besides the top div. Why? Because of the top div
is floated left, making the
rest of the space blank -->
<div style="clear: both;"></div>
<!-- Now in order to prevent the next div from floating beside the top ones,
we use `clear: both;`. This is like a wall, so now none of the div's
will be floated after this point. The container height will now also include the
height of these floated divs -->
<div></div>
</div>
You can also add overflow: hidden;
on container elements, but I would suggest you use clear: both;
instead.
Also if you might like to self-clear an element you can use
.self_clear:after {
content: "";
clear: both;
display: table;
}
How Does CSS Float Work?
What is float exactly and what does it do?
The
float
property is misunderstood by most beginners. Well, what exactly doesfloat
do? Initially, thefloat
property was introduced to flow text around images, which are floatedleft
orright
. Here's another explanation by @Madara Uchicha.So, is it wrong to use the
float
property for placing boxes side by side? The answer is no; there is no problem if you use thefloat
property in order to set boxes side by side.Floating an
Demoinline
orblock
level element will make the element behave like aninline-block
element.If you float an element
left
orright
, thewidth
of the element will be limited to the content it holds, unlesswidth
is defined explicitly ...You cannot
float
an elementcenter
. This is the biggest issue I've always seen with beginners, using, which is not a valid value for thefloat: center;
float
property.float
is generally used tofloat
/move content to the very left or to the very right. There are only four valid values forfloat
property i.eleft
,right
,none
(default) andinherit
.Parent element collapses, when it contains floated child elements, in order to prevent this, we use
clear: both;
property, to clear the floated elements on both the sides, which will prevent the collapsing of the parent element. For more information, you can refer my another answer here.(Important) Think of it where we have a stack of various elements. When we use
float: left;
orfloat: right;
the element moves above the stack by one. Hence the elements in the normal document flow will hide behind the floated elements because it is on stack level above the normal floated elements. (Please don't relate this toz-index
as that is completely different.)
Taking a case as an example to explain how CSS floats work, assuming we need a simple 2 column layout with a header, footer, and 2 columns, so here is what the blueprint looks like...
In the above example, we will be floating only the red boxes, either you can float
both to the left
, or you can float
on to left
, and another to right
as well, depends on the layout, if it's 3 columns, you may float
2 columns to left
where another one to the right
so depends, though in this example, we have a simplified 2 column layout so will float
one to left
and the other to the right
.
Markup and styles for creating the layout explained further down...
<div class="main_wrap">
<header>Header</header>
<div class="wrapper clear">
<div class="floated_left">
This<br />
is<br />
just<br />
a<br />
left<br />
floated<br />
column<br />
</div>
<div class="floated_right">
This<br />
is<br />
just<br />
a<br />
right<br />
floated<br />
column<br />
</div>
</div>
<footer>Footer</footer>
</div>
* {
-moz-box-sizing: border-box; /* Just for demo purpose */
-webkkit-box-sizing: border-box; /* Just for demo purpose */
box-sizing: border-box; /* Just for demo purpose */
margin: 0;
padding: 0;
}
.main_wrap {
margin: 20px;
border: 3px solid black;
width: 520px;
}
header, footer {
height: 50px;
border: 3px solid silver;
text-align: center;
line-height: 50px;
}
.wrapper {
border: 3px solid green;
}
.floated_left {
float: left;
width: 200px;
border: 3px solid red;
}
.floated_right {
float: right;
width: 300px;
border: 3px solid red;
}
.clear:after {
clear: both;
content: "";
display: table;
}
Let's go step by step with the layout and see how float works..
First of all, we use the main wrapper element, you can just assume that it's your viewport, then we use header
and assign a height
of 50px
so nothing fancy there. It's just a normal non floated block level element which will take up 100%
horizontal space unless it's floated or we assign inline-block
to it.
The first valid value for float
is left
so in our example, we use float: left;
for .floated_left
, so we intend to float a block to the left
of our container element.
Column floated to the left
And yes, if you see, the parent element, which is .wrapper
is collapsed, the one you see with a green border didn't expand, but it should right? Will come back to that in a while, for now, we have got a column floated to left
.
Coming to the second column, lets it float
this one to the right
Another column floated to the right
Here, we have a 300px
wide column which we float
to the right
, which will sit beside the first column as it's floated to the left
, and since it's floated to the left
, it created empty gutter to the right
, and since there was ample of space on the right
, our right
floated element sat perfectly beside the left
one.
Still, the parent element is collapsed, well, let's fix that now. There are many ways to prevent the parent element from getting collapsed.
- Add an empty block level element and use
clear: both;
before the parent element ends, which holds floated elements, now this one is a cheap solution toclear
your floating elements which will do the job for you but, I would recommend not to use this.
Add, <div style="clear: both;"></div>
before the .wrapper
div
ends, like
<div class="wrapper clear">
<!-- Floated columns -->
<div style="clear: both;"></div>
</div>
Demo
Well, that fixes very well, no collapsed parent anymore, but it adds unnecessary markup to the DOM, so some suggest, to use overflow: hidden;
on the parent element holding floated child elements which work as intended.
Use overflow: hidden;
on .wrapper
.wrapper {
border: 3px solid green;
overflow: hidden;
}
Demo
That saves us an element every time we need to clear
float
but as I tested various cases with this, it failed in one particular one, which uses box-shadow
on the child elements.
Demo (Can't see the shadow on all 4 sides, overflow: hidden;
causes this issue)
So what now? Save an element, no overflow: hidden;
so go for a clear fix hack, use the below snippet in your CSS, and just as you use overflow: hidden;
for the parent element, call the class
below on the parent element to self-clear.
.clear:after {
clear: both;
content: "";
display: table;
}
<div class="wrapper clear">
<!-- Floated Elements -->
</div>
Demo
Here, shadow works as intended, also, it self-clears the parent element which prevents to collapse.
And lastly, we use footer after we clear
the floated elements.
Demo
When is float: none;
used anyways, as it is the default, so any use to declare float: none;
?
Well, it depends, if you are going for a responsive design, you will use this value a lot of times, when you want your floated elements to render one below another at a certain resolution. For that float: none;
property plays an important role there.
Few real-world examples of how float
is useful.
- The first example we already saw is to create one or more than one column layouts.
- Using
img
floated insidep
which will enable our content to flow around.
Demo (Without floating img
)
Demo 2 (img
floated to the left
)
- Using
float
for creating horizontal menu - Demo
Float second element as well, or use `margin`
Last but not the least, I want to explain this particular case where you float
only single element to the left
but you do not float
the other, so what happens?
Suppose if we remove float: right;
from our .floated_right
class
, the div
will be rendered from extreme left
as it isn't floated.
Demo
So in this case, either you can float
the to the left
as well
OR
You can use margin-left
which will be equal to the size of the left floated column i.e 200px
wide.
Margin collapse on inline-block elements?
This is documented in the spec that margins of inline-block elements do not collapse:
8.3.1 Collapsing margins
- Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
- 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.- Margins of absolutely positioned boxes do not collapse (not even with their in-flow children).
- Margins of inline-block boxes do not collapse (not even with their in-flow children).
- ...
Therefore the answer is No. You probably need to alter the margins of the element.
Why do non-floating parents of floating elements collapse?
Take a look at this section in the w3c CSS 2.1 spec: 9.5 Floats
Note this image at the bottom, just before section 3.5.1:
... this seems to provide the use-case I'm after:
Case description: You have an image floated inside a paragraph with a great enough height that it extends well below its sibling text. In general, you'd want the text in the subsequent paragraph to wrap around this image as well. The way to achieve this is to allow the image to protrude outside the containing paragraph. Otherwise -- if the first, containing paragraph's height extends all the way down to wrap the image -- the subsequent paragraph gets pushed down completely below the image, leaving a large white-space between the texts of the two paragraphs.
However: more often than not we don't want this effect when using floats. So often we need floats to layout main areas of a web page (lest we resort to tables), and in these cases we typically need a container to expand to include whatever is inside in its height calculation.
My wish: It seems, then, that there should be a CSS property along the lines of:
box-model-height: [ include-floats | exclude-floats ];
Browsers could have the default on paragraphs as "exclude-floats", and all other blocks as "include-floats".
Or if that would break too many designs, "exclude-floats" could be the default everywhere, and we could still fix the situation, wherever we need to, entirely in the style-sheet, instead of requiring a class-name (e.g. clearfix) in the markup.
Floating elements within a div, floats outside of div. Why?
The easiest is to put overflow:hidden
on the parent div and don't specify a height:
#parent { overflow: hidden }
Another way is to also float the parent div:
#parent { float: left; width: 100% }
Another way uses a clear element:
<div class="parent">
<img class="floated_child" src="..." />
<span class="clear"></span>
</div>
CSS
span.clear { clear: left; display: block; }
Strange margin issue with a display: inline-block child
What you're seeing is one of the stranger cases of margin collapsing.
If the parent and children are block elements and there's nothing (padding, a border, etc.) separating their vertical margins, then those margins will collapse. Collapsed margins are when two neighboring margins aren't added (as you might expect), but instead the larger of the two is displayed. In the parent-child case, the collapsed margin ends up outside the parent. You can read more details under the section Parent and first/last child in the above link.
Setting the parent to inline-block
, or float:left;
ing it or a number of other things (refer to the link for a more complete list) will stop the margins from collapsing. This leads to the behavior we're used to: the child's margin will appear inside the parent, adding to its total height, and the parent's margin will also be displayed.
Why does CSS float not change the width of the following div?
This is an expected behavior of float positioning.
When an element is floated to the left (in your case the .inline
div), the following content flows down the right side of that element, line boxes get shortened BUT the width of the containing block which is established by the following element (in your case the .yellow
div) is reserved.
This is documented in the spec:
9.5 Floats
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.
However, the current and subsequent line boxes created next to
the float are shortened as necessary to make room for the margin box
of the float.
Which means block level elements (such as <div>
, <p>
, ...)—That are not positioned—ignore the float, whereas line boxes flow along its side.
An example given by W3C:
[D]
The IMG box is floated to the left. The content that follows is
formatted to the right of the float, starting on the same line as the
float. The line boxes to the right of the float are shortened due to
the float's presence, but resume their "normal" width (that of the
containing block established by the P element) after the float.
Hence if you give the .yellow
element a background, you'll see that it spans the container and continues through the floated element.
The solution
From CSS level 2.1 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.
Hence if you add an overflow
property with value other than visible
to the .yellow
div, it prevents the div from overlapping the floated element:
EXAMPLE HERE
.yellow {
overflow: hidden;
}
Overlapping makes sense specially in situations where the length of the following content is large enough to continue normally after the floated element.
If it was restricted by default, the content wouldn't be continued under the floated element.
Related Topics
How to Remove a CSS Class from a Jqgrid Cell
How to Override Max-Width for Specific Div
How to Select a Text (Without Tag) in a Div Using CSS Selector
Chrome and It's Handling of %S
Default CSS Overriding Media Query
Hover Style Can Not Apply When Press Mouse Button in Chrome
Img with {Display: Table-Cell} -- Is It a Bug
How to Create Multiple Rows Using Semantic Markup in Bootstrap 3
Article Push/Pull Alignment Using Bootstrap 3
How to Layer Box-Shadows Using Z-Index
How to Use Commas in a CSS Variable Fallback
Position Floated Elements Directly Under Each Other
Stop Animation from Replaying When Parent Switches from Display:None to Block
Reset Angle of Text in Skewed Div Using CSS
Change Ie Background Color on Unopened, Focused Select Box
How to Center Text Inside a Li Element Inside an Unordered List