Effect of overflow and clear styles with floats - css

I'm pretty CSS-savvy, but I'm seeing some odd float/clear behavior. I have it working, but I'm not entirely sure why and am looking for an explanation.
JSFiddle: http://jsfiddle.net/ismyrnow/JV5n6/
I have a 2 column layout - sidebar and content - where the sidebar is floated but the content is not; the content div has a left margin applied to it.
If I use clear:both on any elements in the content div, the element unexpectedly drops below the height of the sidebar div (unexpectedly because the floated sidebar isn't directly affecting the positioning of items inside the content area).
What is even more unexpected, is that when I add overflow:auto to the content div, the problem goes away. (I found the solution here)
Can someone explain:
Why clear:both would cause an element to clear a floated element that isn't directly affecting its position.
Why overflow:auto on the parent element fixes the issue.

Why clear:both would cause an element to clear a floated element that isn't directly affecting its position.
It may not be directly affecting its position, but it would still have affected it anyway, because in the absence of any clearance, floats aren't normally restricted in how they affect the rest of the normal flow layout even once they are taken out of it, not even by different parent elements such as your .b content element with the left margin in this case. The only real restriction is that floating elements may only affect elements that come after them in document tree order, i.e. elements that are following (not preceding) siblings, as well as their descendants.
The content that's just above the element within your content column isn't tall enough to push it beneath the floated element. If you remove that declaration, you would see that both .c elements become positioned next to their respective floats as well.
When you add clear, what happens is that it forces the clearing element to be positioned beneath the float regardless of where it ends up horizontally.
Why overflow:auto on the parent element fixes the issue.
This is because any block boxes with overflow other than visible generate block formatting contexts. A property of a block formatting context is that floating boxes outside it can never interact with any boxes inside it, and vice versa.
Once you cause the content element to establish its own block formatting context, your floating element is no longer able to affect any elements inside the content element (see the section on the float property), and the clearing element inside it is no longer able to clear any floats that are outside the content element (see the clear property).

For clear:both
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.
When applied to non-floating blocks, it moves the border edge of the element down until it is below the margin edge of all relevant floats. This movement (when it happens) causes margin collapsing not to occur.
When applied to floating elements, it moves the margin edge of the element below the margin edge of all relevant floats. This affects the position of later floats, since later floats cannot be positioned higher than earlier ones.
The floats that are relevant to be cleared are the earlier floats within the same block formatting context.
I hope this will clear your doubt.
This is the link from where i found the above info.....
https://developer.mozilla.org/en-US/docs/Web/CSS/clear

Related

CSS float: taken out of normal flow or not?

Regarding float, MDN says:
The element is removed from the normal flow of the page, though still remaining a part of the flow (in contrast to absolute positioning).
But it does not expand on that at all.
So I did a simple experiment. It seems when the floated element has an inline sibling, it is still part of the normal flow, allowing text and inline elements to wrap around it. But for block siblings, the floated element collapsed to have a zero height.
This behavior is further confirmed in the spec. For content (inline elements I guess?) -
The most interesting characteristic of a float (or "floated" or "floating" box) is that content may flow along its side (or be prohibited from doing so by the 'clear' property). Content flows down the right side of a left-floated box and down the left side of a right-floated box.
And for block boxes -
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.
This does not feel intuitive nor consistent. Why was this design choice?

Why is this non-float margin collapsing with a float?

While investigating this question about clearing floats, I came across a peculiar situation with margins and clearance with a non-floating box.
According to section 8.3.1 of the spec, margin collapse should not occur when either
at least one of the elements generating the margins is a float, or
clearance is in the way.
But, consider a series of floating boxes, the last of which clears the rest:
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
div.container > div {
float: left;
width: 50px;
height: 50px;
margin: 10px;
}
div.container > div:last-child {
clear: left;
}
As you would expect, both the horizontal and vertical gaps between each box are 20 pixels wide. The vertical margins do not collapse.
However, when the clearing element is not floated, it jumps up by 10 pixels as though its top margin were collapsing with that of the float directly above it.
This behavior completely defies both conditions listed above:
There is clearance.
For clearance to occur, there must be some other float to clear in the first place. The fact that the clearing element itself is not floated shouldn't be relevant.
This behavior also seems to be consistent across all browsers, including less-than-recent versions of IE.
That said, I don't claim to know the CSS float model like the back of my hand, so... Can somebody else explain why this happens?
Never mind, I think I found it myself. Looks like the following assumption in my question was wrong (told you I don't fully grok the CSS float model):
The fact that the clearing element itself is not floated shouldn't be relevant.
In section 9.5.2, which describes the clear property, it says:
Computing the clearance of an element on which 'clear' is set is done by first determining the hypothetical position of the element's top border edge. This position is where the actual top border edge would have been if the element's 'clear' property had been 'none'.
If this hypothetical position of the element's top border edge is not past the relevant floats, then clearance is introduced, and margins collapse according to the rules in 8.3.1.
Then the amount of clearance is set to the greater of:
The amount necessary to place the border edge of the block even with the bottom outer edge of the lowest float that is to be cleared.
The amount necessary to place the top border edge of the block at its hypothetical position.
And further down that section, it says:
When the property is set on floating elements, it results in a modification of the rules for positioning the float. An extra constraint (#10) is added:
The top outer edge of the float must be below the bottom outer edge of all earlier left-floating boxes (in the case of 'clear: left'), or all earlier right-floating boxes (in the case of 'clear: right'), or both ('clear: both').
(Emphasis mine. Note that "outer edge" is synonymous with "margin edge", as described in section 8.1.)
Essentially, this means if the clearing element is not floated and its top margin alone does not push it far enough away from the floats, then the element is pushed just enough for its top border to sit right underneath the bottom margin of the float being cleared. While it would appear as if its top margin was collapsing with the bottom margin of the float, in reality the top margin doesn't have any meaningful effect because it doesn't reach the border edge of the clearing element.
Otherwise if the clearing element is floated, then its top margin is taken into account, so to speak (as consistent with the rules stated in 8.3.1).
And as I write this, I recall that in-flow non-floating elements are positioned as if the floats were never there to begin with, because floats are taken out of the normal flow. In other words, any top margin that is set on a non-floating clearing element does not take into account any floats, regardless of whether it is enough for clearance. For example, when both clear and float are set to none on the last element, it sits flush with the edges of its container in the exact same position as the first floating element, albeit behind it (note that the borders on the container block margin collapse between it and the container).
Lastly, the fact that clearance is introduced is actually not relevant in this specific situation, because clearance blocks margin collapse only when the element's margins would normally have collapsed had its clear property been set to none. Since we're talking about floats here, margin collapse should indeed never happen normally, and so whether or not the last element has clearance isn't relevant (not directly, anyway).

Why overflow:hidden expands parent element (containing floated child elements)?

In short:
Basically, I just want to know why overfow:hidden explands the container containing a floated item. Shouldnt it hide the overflowing element like in this image http://css-tricks.com/wp-content/csstricks-uploads/css-overflow-hidden.png
why does it do this instead http://css-tricks.com/wp-content/csstricks-uploads/overflow-float.png
Long version:
Non-positioned, non-floated, block-level elements act as if the floated element is not there, since the floated element is out of flow in relation to other block elements. And inline elements wrap around the floated elements to acknowledge their presence.
I know how the overflow property works and where to apply it, and that clearing floats is best done with a clearfix and not the overflow property (although some cases may call for the usage of overflow clearing instead). However, I still don't understand why it expands the parent element, especially when we use overflow:hidden. Why don't the parent element just "hide" the overflowing floated child element? After all, aren't we hiding overflow?
It is a very good question. I gave it a thought.
overflow:hidden set on the parent element clips the overflow of the child elements when the parent element has a height or width defined (I tested it). overflow:hidden expands parent element (containing floated child elements) in the case either height or width of the parent element is not determined.
So, what seems to happen is that overflow:hidden set on the parent element enters in action and looks for an area to be applied. As the parent element does not have height and width set, that same area will be yielded by the size of the child elements. Simultaneously, after the area is set there is nothing to be cut since the child floating elements are providing the area to make a clipping from.
However, when you apply a box-shadow, for instance, to the child floated element, the box-shadow may be clipped, depending of the size of it, and that's one of the reasons why perhaps the best solution to expand a parent element (containing floated child elements) is the solution 1 provided by A.M.k for this question How do you keep parents of floated elements from collapsing?
This is a really good question despite others' comments.
The actual answer is "because someone decided it should work that way."
Fortunately, we can discuss the topic online, maybe influence those people, and sometimes even change things.
In the meantime you can always read "Why Containers Don’t Clear Themselves": http://css-tricks.com/containers-dont-clear-floats/

When do nested child elements expand their parent elment?

In many places I have put elmeents nested in other elements. I can't deduce when a child element causes the parent element to expand. I don't have any code to post as this is a general conceptual question so that I can design as needed.
The first thing that you should understand is the CSS Box Model. That will help you understand how properties of an element cause it to have the size and dimensions that it has. Another good resource is here.
To answer your main question in the most simple manner (and being very general):
Block level elements take up as much width as possible (obeying their CSS width rule). Their height is dependent on their content and the CSS height property.
Elements like div, p, and ul are all block.
These will generally cause your parent element to expand.
Inline level elements will continue to flow together in a line, filling up only as much width and height as necessary.
Elements like span, em, strong are all inline.
These will cause your parent element to expand only when there are enough of them on the same line to warrant another line.
There are many ways to tweak the display of elements with CSS.
Get firebug for firefox. You can browse the DOM (the HTML structure of the page) and it will highlight elements according to how the "browser's eye" sees them (versus how they look aesthetically).
A few general rules of thumb:
Children will expand their parent's height as long as they're not floated or absolutely positioned, but...
You can "clear" a series of floated images http://www.quirksmode.org/css/clearing.html to make the parent element expand
If you use top positioning for a relatively positioned child element, the browser will still see that element in the exact same place. In other words the height of the parent element will stay the same regardless of where the child is relatively positioned to.
Using positive or negative margins on a child that is display: block will add or subtract height from its parent

Why does setting overflow alter layout of child elements?

In this question someone was having a layout problem because they had two floated divs inside a non-floated div. I suggested adding float: left to their outer div, which does fix the problem. Someone else suggested adding overflow: hidden, which to my surprise, also worked.
This doesn't seem at all like the purpose of of overflow: hidden. Clearly overflow: hidden causes elements to view their children differently somehow. What I'm really trying to understand is what that difference is. Intuitively it should only make the element smaller than it would otherwise be, never bigger and I don't see why it would affect the layout hierarchy.
Can anyone explain why this would be correct/necessary behavior or if this is just a browser quirk? Is their another facet to the overflow property I'm missing? Is either solution any better than the other?
Edit: I've discovered setting overflow: auto works too, so it doesn't seem to be the value of overflow that's important, just that it's set. I still don't understand why.
Overflow of anything but visible creates a new block formatting context which causes floats to be contained. It's standard behaviour.
Floats, absolutely positioned
elements, inline-blocks, table-cells,
table-captions, and elements with
'overflow' other than 'visible'
(except when that value has been
propagated to the viewport) establish
new block formatting contexts.
In a block formatting context, boxes
are laid out one after the other,
vertically, beginning at the top of a
containing block. The vertical
distance between two sibling boxes is
determined by the 'margin' properties.
Vertical margins between adjacent
block boxes in a block formatting
context collapse.
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). This is true even in the
presence of floats (although a box's
line boxes may shrink due to the
floats), unless the box establishes a
new block formatting context (in which
case the box itself may become
narrower due to the floats).
Floating items removes them from the normal layout in many cases. It's not exactly like or unlike position: absolute; in that. Block items tend to ignore floated items (including block items that contain the item), but unlike position: absolute; items, floated ones are recognized and wrapped around by inline items, like text.
Having the wrapping item (div or otherwise) also be floated causes it to behave differently related to floated items it contains. Having the wrapping item set to overflow: hidden; forces it to consider the items it contains differently, as well. My guess is it's just a happy coincidence that the end result here appears to be the same. Not a quirk or bug... just how it works out.

Resources