I noticed that inline-blocks and blocks behave differently when they are situated near a floated element : background of blocks extends under the floated element while inline-blocks wrap it entirely.
div is a block :
div {
height: 5em;
width: 5em
}
div:first-child {
background: #27A5CC;
float: left
}
div:nth-child(2) {
width: 6em;
background: #EEEEEE
}
div is an inline-block :
div {
height: 5em;
width: 5em
}
div:first-child {
background: #27A5CC;
float: left
}
div:nth-child(2) {
width: 6em;
background: #EEEEEE;
display: inline-block
}
Is there an explanation for it?
I will assume that you understand the difference between block and inline-block displays. Let us now look at how floats work:
A float is a box that is shifted to the left or right on the current
line. [...] Content flows down the right side of a left-floated box
and down the left side of a right-floated box.
A floated box is shifted to the left or right until its outer edge
touches the containing block edge or the outer edge of another float.
If there is a line box, the outer top of the floated box is aligned
with the top of the current line box. [...]
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.
Your examples explained below:
Example 1
The first div is floated. It is taken out of the flow and aligned with left side of the parent. The second div also starts from left side ignoring the first div as if it did not exist.
Result: both divs end up with their top-left corners aligned with each other.
Example 2
The first div is floated. It is taken out of the flow and aligned with left side of the parent. The second div is an inline block element, therefore it follows the rules that apply to content flow and line boxes. It starts rendering towards the right side of first div just as normal text would.
Result: the second div aligns with the right side of first div.
Related
My question relates to when you have one div floated (float:left) and a div right afterwards that is not floated. In that situation, why does the unfloated div cover and overlap the first div? It's like the first, floated div is taken out of the flow (like absolute positioning) in how the 2nd unfloated div goes over the 1st div.
I am aware that text in the 2nd unfloated div does not do this. It seems aware of the first div and floats next to it.
I am also aware that the fix is to have the 2nd div also floated to the left.
My question is a focus on the why. Why does the 2nd unfloated div (except for any text that might be in it) cover and overlap the 1st floated div?
In another similar question here on Stack Overflow, someone said "float removes an element from the normal flow, meaning that neighboring elements are positioned as if the float didn't exist...This isn't the case if an element has an inline display." So my question is why is a floated element removed from the normal flow (except for inline elements)? I understand why that is the case with inline elements (you want the text flushed to the floated div for word wrap around an image, for example). But why is it removed from the normal flow at all???
Here is some code to illustrate what I mean.
.box1 {
border: solid 3px;
width: 350px;
float: left;
height: 100px;
}
.box2 {
background-color: lightblue;
width: 400px;
height: 150px;
border: blue solid 3px;
}
<div>
<div class="box1"></div>
<div class="box2"></div>
</div>
It's like the first, floated div is taken out of the flow
Exactly, that's the reason. Floated elements are out-of-flow:
An element is called out of flow if it is floated, absolutely
positioned, or is the root element.
And that's necessary given the behavior of floats:
A float is a box that is shifted to the left or right on the current line.
If they were not removed from the normal flow, they would continue occupying some space in their initial position before being shifted.
Note inline floats are not an exception, because there is no such thing. Floats are blockified as explained in Relationships between 'display', 'position', and 'float'
Therefore, blocks following a float overlap it:
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.
You can prevent this behavior by establishing a new block formatting context:
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.
.box1 {
border: solid 3px;
width: 350px;
float: left;
height: 100px;
}
.box2 {
background-color: lightblue;
width: 400px;
height: 150px;
border: blue solid 3px;
overflow: hidden; /* Establish BFC */
}
<div>
<div class="box1"></div>
<div class="box2"></div>
</div>
As I understand float:left, it will push the subsequent element to its left rather than on a new line.
In the following example I would expect that the second div begins to the right of the first div, but as you can see in the jsfiddle below, it still spans the whole width.
The content on the other hand magically begins where it's supposed to. Does the float rule only float the content but not the margins?
Example here
.inline {
float:left;
}
.yellow {
background-color:yellow;
}
<div class="inline">
first line<br>
second line<br>
third line<br>
</div>
<div class="yellow" >floated div</div>
EDIT: I would expect that the code above looks something like this but without the explicit need to use margins.
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.
You need to float the yellow div as well, then it will work;
.inline {
float:left;
}
.yellow {
background-color:yellow;
float: left;
}
However, just floating elements doesn't put it on the left of the next element automatically, so you need display: inline-block; to show the next div on the same line and display: block; to show underneath.
You should also give a width (in percent if you want) for both divs that add up to 100% or less including any left and right margins and padding if displaying inline.
The other thing you could do is set a width for .inline and float it, then give .yellow the same value as its left margin and don't float it.
.inline {
float:left;
width:50px;
}
.yellow {
background-color:yellow;
margin-left:50px;
}
This will allow the .yellow div to fill the remaining width.
Hope this helps.
CSS:
.inline {
float:left;
position:relative;
width:auto
}
.yellow {
background-color:yellow;
position:relative;
float:left;
}
see fiddle
I'm creating a horizontal menu bar.
There is an outer div that contains inner divs (each of these divs is the individual menu item).
I use float: left for styling on these inner divs to display them horizontally instead of vertically.
The problem is that the menu bar has uneven space on the left and right, hence the overall menu bar doesn't appear to be centralized... i.e the first menu item on left has lesser space from left border and the space between last menu item on right and the right border is more.
I want equal margin/padding on the left and right to make the menu bar display in center.
I tried setting margin-left: auto; margin-right: auto on the outer div and then on the inner div as well. Both don't seem to help.
Already had a look here: How to horizontally center a <div> in another <div>?
However this particular answer is to center just one div, what I have is a collection of horizontal divs (menu items) that need to be centralized.
Any help is appreciated.
If your menu items aren't complex (like no fixed sizes or sub-elements), try adding the following styles:
#outer {
text-align: center;
}
.menu-item {
display: inline; /* replace 'float:left' with this */
}
DEMO
Otherwise you'll need a wrapper for the inner elements that has a fixed width:
#wrapper {
margin: 0 auto; /* center in outer DIV */
width: /* sum of widths of inner elements */;
}
DEMO
NOTE: Semantically its better to style menu items using a list, as in the DEMOs.
Firstly if all your menu items have specified widths and display:inline which is default, you wouldn't need a float to line them up.
But supposing you do, when you set a float, your elements are removed from the natural flow of the document, and hence margin:auto will not work to center it. What you could do in this case is create another container div of specified width for the menu items, within which you could use float to line them up.
Now what's left is to center this one container div within your outer div, which you have already seen how to solve. For example, you could use the margin:auto technique on the container div to center it. Make sure you have text-align:center for the outer div.
So I have a div, 720px wide, and i'm filling it with divs that are 140px wide, floated left. I would love to be able to line these divs up flush with the left and right edges of the containing div.
Of course, the issue is that when I put a margin-right on the floated divs, the right edge won't line up due to that margin. A left margin yields the same results, but on the left edge.
Is there any way to combat this issue?
Try this: Link
You can put the elements into rows and detect first, middle, and last elements with these css2 selectors. You can specify different margins for the different positions inside.
element:first-child {
}
element:last-child {
}
element .className {
margin-left: 6px;
}
If you are using a server-side language to generate these divs you can calculate which item is last in the row by doing something like this:
<div class="column <%if iteration % 6 == 0 %>last-in-row<%end%>"></div>
and then just set the style
.column {
margin-right: 10px;
}
.last-in-row {
margin-right: 0;
}
I would like to position three items in CSS using float.
In the top left--logo
To the right of the logo, the navigation, which is an unordered list, ie floating left.
In the top right, a 2 line sign up for newsletter field--copy top row and form field with submit bottom in the second
I've given each it's own Div tag but can't see to get it to work with float. Only absolute positioning which doesn't look good when the site is resized. I put a table inside the div right now but would love a pure CSS solution.
I can get the logo to float left and the sign up field to float right but can't seem to get the navigation properly positioned. Either it goes all the way left or I put a clear in and it goes below the logo and field.
Any suggestions would be appreciated.
What about the following?
.floatleft_logo
{
float: left;
width: 200px;
}
.floatleft_nav
{
float: left;
width: 600px;
}
.floatright_email
{
float: right;
width: 300px;
margin-left:-250px;
}
Put all three in a 850px-wide container div and this works for me in a test page.
If I've understood it correctly, maybe you could set the first and second element to float: left, and then set the margin of the third element equal to the width of the first and second?
You could also set the first element to float left, the third to float right, and the second with a margin equal to the width of the first element. Like a three-column layout.