Why does CSS float not change the width of the following div? - css

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

Related

Why does an unfloated div cover/overlap a floated div? (with "why" being the focus)

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>

Why do inline-blocks and blocks behave differently near a floated element?

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.

Unwanted Space in div tags

I have two div id's. One has has an image in it and the other has a background image. There is an unwanted space in between these two divs. In the dreamweaver design view it appears as if there is no space, but if I make it live or preview in browser the space appears again.
This is the css for the divs
#header {
text-align: center;
padding: 0px;
margin: 0px;
}
#content {
background-image:url(img/ContentBox.png);
background-repeat: no-repeat;
background-position:center;
padding: 0;
margin: 0;
}
This is my body html (ignore the multiple line breaks, this is just so I can see the bg img in the div)
<body>
<div id="header"><img src="img/Header.jpg" /></div>
<div id="content"><br><br><br><br><br><br><br></div>
</body>
Images have a default display setting of inline. This causes them to flow inline with text, vertically-aligned with the baseline. All text is vertically-aligned with the baseline by default as well, unless you change it by setting vertical-align to something else on its containing element.
What is baseline?
The baseline floats above the bottom of the actual line. Look at the lower-case letter g. The bottom of the top circle is the baseline. That's where the images are getting aligned.
You can solve this multiple ways, but here are a couple:
Vertical Alignment
Again, image elements are set to display: inline by default. Assuming you don't want to change this, you need to adjust how the image element aligns vertically on the current line of text.
The vertical-align CSS property sets the vertical alignment of an inline element on the current line of text. It doesn't set it relative to the container.
Therefore, you can set the vertical-align property to middle, top, or bottom, and as long as the image element is larger than the line-height of the current line of text, it will not have the extra space below it.
However, you need to remember what I just said about line-height. In the event that your line-height is larger than your image element, vertical-align will do more than remove that extra spacing: it will actually align the image element on the line accordingly. See this jsFiddle to see an example of how a line-height greater than the height of the image will affect the result.
So, keeping with the HTML that you provided, to set the vertical alignment, you'd do the following CSS rule:
#header img {
vertical-align: bottom; /* or top or middle */
}
Displaying as Block Level
Another option would be to change the image element to display as a block level element. I don't recommend this approach unless you know you want a block level image.
Block level elements automatically fill to their container, and don't flow inline with text or other inline elements. Also, if you set a float on the image, this would force it to be block level.
So, you have two options to display as block level:
#header img {
display: block;
}
or
#header img {
float: left; /* You could float right too */
}

What is the purpose of float:left on an unordered list when creating a horizontal navigation bar?

The code sample below works almost the same, if I include or remove the 'float: left' line. The only difference is the float left version moves the blocks below it up a bit more, but not more than a line break. I don't understand why you would add floating to an element set to 100% width. To my understanding,this prevents everything below it from flowing around it. Isn't that the purpose of floating?
ul
{
list-style-type: none;
float: left;
width:100%;
padding:0;
margin:0;
}
li
{
display: inline;
}
The reason why this works is because your <li> display is set to inline. This means that all elements with of this HTML tag will show up on the same line as all other ones. In other words, there will be no line-break. I would suggest the following instead:
ul {
list-style-type: none;
width: 100%;
padding: 0px;
margin: 0px;
overflow: hidden; /* This will ensure there's a line break after using float for the list items */
}
li {
float: left;
}
This way you can ensure that each list item can also use margin and padding properly as opposed to inline elements which act as characters in a string of text normally would.
The float property is meant to allow an object to be displayed inline with the text directing it to one side. Float left is thus a lot like inline but with the exception that the element being floated is aligned towards the left or the right. It is not necessary to use the float:left; flag for what you are trying to do, It can often be better to place the ul where you want it using position, margin, padding, left , top , right , bottom instead. This usualy gives a more controllable result.
Here is an example fiddle of what happens when switching between no float and float left.
http://jsfiddle.net/um9LV/
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.
when an element is floated it is taken out of the normal flow of the document. It is shifted to the left or right until it touches the edge of it's containing box or another floated element.
float:left - use float to get block elements to slide next to each other
display:block - Displaying the links as block elements makes the whole link area clickable (not just the text), and it allows us to specify the width

Main column appears where sidebar column ends

I'm braindead on this and I know it's simple.
There's a header div, appears fine. There's a left-sidebar div, appears fine with top snuggled up to header div.
Then there's a main content div. There is an image and h1 which appear like you would expect up against the header div, but then a large gap appears until the navigation (in a nested div). Navigation is correctly in the main content div, but top of this div always aligns with bottom of sidebar content.
I've tried mixtures of clear:left and both and floating and whatnot. If inside the html I move the sidebar div below the main content div then the main content has no gap but the sidebar has a big top gap and appears flush to the bottom of where the main content nav ends.
What am I missing here, thanks in advance!
Are you setting any widths (or padding, margin, border) which might make your problematic div too wide to fit?
Remember that if you are doing something like :
width: 100%;
border: 1px solid;
Then your element will take up 100% width + 2 pixels.
It sounds like you have your sidebar occuring first in the source order.
If you have the two divs (sidebar, main) floated in different directions, then look at the width avaiable they are sharing. Reduce the width of one div (you should have width set on your floats) until their combine width, including padding, margin, borders fits in available space. (I will only use width in my example for brevity).
When this effect happens, in my experience, the one occurring later in the source order is the one that gets prevent from sliding up into it's spot by too much width.
<div id="container">
<div id="header">head</div>
<div id="sidebar">side</div>
<div id="mainContent">main</div>
</div>
Width of #sidebar & #mainContent too wide (#mainContent gets bumped down):
#container{
**width:950px;**
margin:0 auto;
background:blue;
}
#mainContent{
float:right;
**width:651px;**
background:red;
}
#sidebar{
float:left;
**width:301px;**
background:green;
}
Width of #sidebar & #mainContent fit inside container:
#container{
**width:950px;**
margin:0 auto;
background:blue;
}
#mainContent{
float:right;
**width:650px;**
background:red;
}
#sidebar{
float:left;
**width:300px;**
background:green;
}
btw...if you floated the two elements in the same direction, but their combined width is too wide, the last one in the source order would fit underneath the above floated element.
Does your h1 or img have a top margin? It will stick out of the top of the mainContent div and push it down.

Resources