css floats and its stack order - css

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>

Related

Element with clear:both has floating sibling elements on both sides of it

My understanding was that a div with clear:both; would not have any floating sibling divs positioned on either side of it. In this example I have 3 sibling, left floating divs inside of a container div with overflow:auto. There's enough room for all of them to be side by side.
Link to jsfiddle below.
When I apply clear:both to the middle div it moves it to the next line (as expected) however the div to the right of it also moves down and remains on it's right side despite that area being cleared. I'd expect each div to be on a new line.
Further more if I just add clear:right; to the middle div it remains where it is (in line with the div to its left - as expected) and the div to its right also stays beside it. I would have though the right div would have moved to a new line.
This behaviour seems to contradict what clear is supposed to achieve by preventing floating sibling elements from being beside each other. Can anyone explain this?
jsfiddle here: https://jsfiddle.net/2tfgwmek/1/
HTML
<div class="container">
<div class="left">Left Div<br>float: left; </div>
<div class="middle">Middle Div<br>float: left; clear:both; </div>
<div class="right">Right Div<br> float:left </div>
</div>
CSS
.container {
width:300px;
overflow:auto;
border:solid 2px black;
}
.container > div {
width:90px; height:90px;
border:solid 1px red;
background:grey;
float:left;
color:white;
}
.middle {
clear:both;
}
clear only applies to elements that precede the element you've applied clear to.
https://developer.mozilla.org/en-US/docs/Web/CSS/clear
The clear CSS property specifies whether an element can be next to floating elements that precede it or must be moved down (cleared) below them. The clear property applies to both floating and non-floating elements.
And the left or right (or both) values refer to the direction of the float on the previous element. So here, the only float you can clear on the middle div is the one that preceded it, and that element was floated left, so clear: left is all you can use that will affect the layout. clear: right won't do anything in your example.
If there were 2 divs before the middle one, and one was floated left, and the other right, then you could use clear: left or clear: right (or clear: both) to affect the layout.

Very strange overflow+float behavior

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.

Expand parent div height to childs

I have a problem with footer positioning. It doesn't go to the bottom/last.
So, I have a container div which has 3 divs - float:right , float:left and the center one (which has position:absolute) that comes between the two floated divs.
The center one must have fixed width and height because it's an image.
In that center div I have another div with a lot of content.
The problem is, because the center div has fixed width and height, it doesn't take the childs div height.
So my problem is how to put the footer that it comes last (after the container)?
Note - with JQuery I put the width of the floated divs because they take 100%-980px width.
This is how it looks like.
I tried putting to the center div overflow:auto,overflow:overlay,margin-left:auto;margin-right:auto;.
After reading your question again an again i come to conclusion and create the below fiddle using your code and embed a sample image for you desired size.
Please let me know if i am wrong while understanding your question. So i can work around according your needs.
fiddle: http://jsfiddle.net/ah3nr/6
Demo: http://jsfiddle.net/ah3nr/6/embedded/result/
My approach:
I have remove the position:absolute from center div and added new div for image and relate them both using css layer techniques.
Updated css:
.sectionDownContainer {
width: 980px;
/*height:270px;*/
border:1px solid red;
/*position: absolute;*/
position:relative;
top: -32px;
z-index: 1;
}
/*.sectionDownMenu {
margin-left: 50px;
margin-top: 1px;
display: block;
}
*/
#image_container {
position:relative;
width:980px;
height: 270px;
margin-top:-2px;
z-index:2;
}
.sectionDownContent {
width: 640px;
margin-top: -190px;
margin-left: 50px;
position: relative;
z-index:5;
color:#000;
font-weight:bold;
}
Screenshot:
Try this for the parent.
overflow:auto;
Also refer to this stack overflow post: Expanding a parent <div> to the height of its children
You need to set this property of the center-div: height:auto (you could also add a minimum height: min-height:400)
About your second question with the footer, this is much more complicated. You must do this:
<div id="content">
<div id="content_left">
</div>
<div id="content_center">
</div>
<div id="content_right">
</div>
<div id="footer">
</div>
</div>
I'll give you now the full CSS (because it's not so easy):
.content {position:relative; overflow:hidden;} //hidden overflow just a hack for common issues...
.content_left {height:auto; float:left} //set height to auto (very important)
.content_center {height:300; float:left} //a fixed height also works!
.content_right {height:auto; float:right}
.content_footer {width:100%; height:auto; float:right} //for tests you can also set a fixed height
This solution is also according to other threads on Stackoverflow: Align DIV's to bottom or baseline, How to align content of a div to the bottom?
But, if you experience problems with that, you may do this (my preferred solution):
<div id="content">
<div id="content_left">
</div>
<div id="content_center">
</div>
<div id="content_right">
</div>
</div>
<div id="footer">
</div>
And its CSS:
.content {position:relative; overflow:hidden;} //hidden overflow is just a hack
.content_left {height:auto; float:left} //set height to auto (very important)
.content_center {height:300; float:left} //a fixed height also works!
.content_right {height:auto; float:right}
.content_footer {width:100%; height:xxx; float:left} //you can use any height...
Note that all above solutions works only if you set all the "contents" to float, it doesn't work with absolute values! I found this here: http://wiki.answers.com/Q/How_can_a_parent_DIV_wrap_around_child_DIVs_which_are_floating_left_or_right
This is due to an issue with divs: It's not possible to "tell" a parent div the size! So childs like "content_center" or "content_right" won't tell the "content" how long they are and how long "content" must be. So it's impossible to tell the footer where to align, if you use absolute values for the childs.
So your second question, although it looks trivial, is a very important question, and not easy to solve.
IMPORTANT UPDATE:
I tried to find a solution with absolute now. The problem is, that absolute and fixed are taken out of the regular (text)flow, so their size can't influence the size/positioning of any other element anymore. But we also have to understand that an absolute element still controls all its childs, so we should rather set the childs as relative than the parent (here: "content")! So I finally found the solution, and it's quite weird, because it's almost the opposite thing I suggested above, but that solution was influenced by the posting of others, while following solution is "my own" one (I added a header for demonstration purpose):
<div id="header">
</div>
<div id="content">
<div id="content_left">
</div>
<div id="content_center">
</div>
<div id="content_right">
</div>
<div id="footer">
</div>
</div>
The CSS (the "header" clearly shows, that "content" inherites all positioning to its childs like "content_left", "content_right", aso.):
.header {position:absolute; left:0; top:0; height:100; width:100%}
.content {position:absolute; left:0; top:100; height:auto; min-width:700} //min-width is only voluntary, but quite useful
.content_left {position:relative; left:0; top:0; width:200; height:auto;} //height:auto is important to adapt the height from containing text!
.content_center {position:relative; left:200; top:0; right:200; width:auto; height:auto;} //in the middle element, also auto-width is important!
.content_right {position:fixed; right:0; top:0; width:200; height:1000;} //we set a fixed position, but that won't influence the footer anymore!
.content_footer {margin:0 0 60 0; position:relative; left:0; bottom:-60; width:100%; height:150;} //a fixed height is also okey...but relative position is needed!
//you still need to add margin:0; border:0; padding:0 or similar values for some elements to get a good layout
The important point here is, that you can decide which child element will be the longest one, and set this element's position:relative, while the other may have absolute or fixed. But if you don't know which element will be the longest, all child's positions need to be set as relative. Anyway, I suggest to set all childs to relative (beside fixed if needed), because their parent "content" will set their absolute height-position already correctly, so there's no need for any absolute at all.
I'm repeating myself: Above I wrote it's not possible to tell a parent div the size...actually it's possible, but not if the values absolute and fixed are used. Only if you use the browser standart value (static) or relative, the parent div will be informed about the size of its childs, an therefore the footer is set correctly at the bottom of the page.
Well, my solution works everywhere...even in IE (tested 6.0 and 8.0!) due to the hack margin:0 0 60 0 where the value 60 should be the positive value of bottom:-60. Now we finally got the non-floating crossbrower-solution. ;)
The problem you're experiencing is that certain CSS properties cause elements to be "removed from the flow" of the document (see the W3C Visual formatting model). Parent elements naturally grow to fit the height of children elements, however, floated and absolutely positioned elements are removed from the document flow. As mentioned in a few comments, setting overflow: auto; or overflow: hidden; on the parent element re-establishes a bounding box around floated elements. This means you can float elements within the parent container, then set overflow: hidden; on the parent element, and the parent element will contain the floats. However, this doesn't work for absolutely positioned elements: the absolutely positioned box is "removed from the normal flow entirely (it has no impact on later siblings)". The only exception is that the entire document will try and grow to display any positioned elements (give an element position: absolute; top: 3000em; and the page scrollbar will grow to allow you to scroll to that element). I don't know of any way to trigger this for elements other than the document.
Back to your intended effect… If you don't need IE7 support, you can use display: table; table-layout: fixed; to achieve a centered column with a fixed width and two columns of variable width on either side.
jsFiddle Demo
In the near future, this will also be possible using the CSS "flexbox" properties. Flexbox will allow for some nifty new features, including horizontal and vertical centering, changing the order of rendered elements, and setting "flex" values for how much of the remaining variable width an element should take. However, the standard is currently going through a period of flux, and the old standard (enjoying moderate support) is being replaced by a new standard (with little to no support). See "Old" Flexbox and "New" Flexbox and the accompanying demo. Considering the glacially slow progress of web standards implementation, I don't expect to see this in use for a few years unless a truly masterful polyfill is produced.

Basic CSS: Float left and inline divs

I've captured an illustration of a CSS two-column layout I've set up, while using the following rule for the orange containers:
.embedded_post{
float: left;
width: 46%;
margin-right: 20px;
padding: 10px;
display: inline-block;
}
As can be seen, the second orange container on the right column is preventing the second orange container on the left column from floating up to the top left box.
This happens apparently since float:left automatically grants the element with a block level flow.
How can I get the second box on the left column to be positioned under the first one?
can you wrap your columns in another pair of divs, so that floating in the right column won't affect floating in the left?
<div id='left_column'>
<div class='embedded_post'></div>
<div class='embedded_post'></div>
</div>
<div id='right_column'>
<div class='embedded_post'></div>
<div class='embedded_post'></div>
<div class='embedded_post'></div>
</div>
css:
#left_column, #right_column {
float:left;
}
you've answered it yourself, there are a couple of options:
trick yourself by granting the div elements with an inline level flow, i.e. specifying display: inline (not recommended).
update the markup to be more semantic and alter the layout to conform to the desired result, e.g. replacing the divs with spans (preferred).
The second div on the left has less width than the rest of the divs, this might have something to do with it. Also, the combination with your (desired) structure and the margin-right isn't how I would do it. In fact, the margin-right may, depending on the with of the parent div of the embedded_post divs, screw up your structure and cause postioning problems.
It works fine when I try it.
p.s. keep in mind that in Firefox, the padding adds to the width/height of the div while this doesn't happen in other browsers.

A div with relative position over a div float

I don't understand why a div with float right or left is not above a div with relative position or defined with a background color when the last one is declared after.
Here is the html:
<html>
<body>
<div class="container">
Main container <br/><br/>
<div class="header">This is the header</div>
<div class="text-right">Right text</div>
<div class="footer">This is the footer</div>
</div>
</body>
And here is the css:
.header {
background-color:blue;
border: solid;
color: white;
border-color:black;
height: 100px;
}
.text-right{
float: right;
border: solid;
background-color: green;
}
.container{
padding: 10px;
border: solid;
}
.footer{
padding-top: 50px;
border: solid;
background-color: yellow;
position: relative;
}
I know that I can use a .clear: both rule to correct this problem but my main point is: why when I set the background-color or the position or both in the .footer rule, the float div is under the footer?
Thank you very much!
While reading this very good post, at the end of the post, the author talks about the z-order internal working but also say that if you want to learn more, this next one will be a much more detailed article
The key point is that the order in the z-axis where are put the elements.
Here is what the author says:
If we do not specify any z-index values, the default stacking order
from closest to the user to furthest back is as follows:
1. Positioned elements, in order of appearance in source code
2. Inline elements
3. Non-positioned floating elements, in order of appearance in source code
4. All non-positioned, non-floating, block elements in order of source code
5. Root element backgrounds and borders
As we can see, the positioned elements(1) are always on top of non-positioned elements(3-4). If I put a div with just a float property, this element will not be "positioned" onto the surface.
In this case, the second element, my footer div, that is positioned with a relative property value will be at the top of the previous one not just I don't add a clear: both property after the float div property or because the last one is added after the floating element but because it is positioned!
Like powerbuoy said, you must set add a position relative to the float element to be able to go top of the stack the floating element. But it's not enough. Because these two elements are now at the same level and because they are both crossing each other, you must tell the engine which one will be the first and this is why you must set the z-order to 1 to the floating element again like said powerbuoy.
I'm not a very good writer and for this reason, I strongly suggest you to read the referenced articles that I mentioned previously. I think you will have a very deep explanation of the case.
Since the footer comes after the text-right it will be rendered on top of text-right. To avoid this you can give text-right a z-index (and a position other than static):
http://jsfiddle.net/wxMhx/
Edit: hmmm... no that's not entirely correct. If you remove position: relative; from the footer text-right will be rendered on top of it. TBH I'm not sure why that happens. But the solution in either case is to either remove position: relative; from the footer, or add it (as well as a z-index) to text-right.
Because position: relative. If you delete this line you will see div with text-right class. You can set z-index: -1; to footer class and this should work as well.

Resources