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

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).

Related

Effect of overflow and clear styles with floats

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

Text squashed when using position: absolute;

I have a text box that will expand across the screen when I do not use position: absolute;, however upon using it, the text is all in one column per word, and the box is very tiny.
What is causing this? Or what can cause this? I've been trying overflow settings, different sort of positions and z-indexes, etc.
This is a good question because it highlights an important aspect of absolutely positioned elements.
If you don't specify the width of an absolutely positioned element, or if you don't specify the left and right offsets, then the width is computed to be a shrink-to-fit width similar to what is done for table cells.
The details are given in the CSS specification, Chapter 10: http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width
There are also some subtle consequences when you place an absolutely positioned element such that it triggers an overflow condition or when one of the edges if out of the view port. In these cases, a absolutely positioned block may have a computed width smaller than you specified.
The key is to consider what type and how much content the block will hold and provide a clear constraint for setting the width, either with a fixed value of a relative value.
Example
If you absolutely position the following:
<div class="abs ex3"><b>Small amount of text:</b> shrink-to-fit</div>
as shown in http://jsfiddle.net/audetwebdesign/SHxPR/, then the computed width of the block will be smaller than the width of the page. The block will expand in width and then height as needed to accommodate more text.
The element where you have position:absolute; is doing as it is expected to do. You should use position:relative; to the parent container for this absolutely positioned element.

Why is the left margin jumping up?

I'm following In Search of the Holy Grail, but am having trouble understanding what's actually going on in step 3.
To break the problem down, I disabled the margins/offsets of the "left" and "right" divs. This gives you the content at the top, and then the two other elements sitting side by side under it as I would expect [see P1].
I then gradually decreased the margin-left of the "left" div from 0px to -199px which again does what I expect [see P2].
But at -200px (the width of the left element itself), it shoots up to the top [see P3], with the left edge against the right edge of the content. I would have expected it to just keep going off the edge.
Why does it jump up? And if there's no conceptual explanation as to why, where does it describe that functionality in the spec?
Images:
P1
P2
P3
Remember that both #content and #left (as well as #right) are floated.
Due to the nature of floats, they (or their contents) may overlap. This is well described in this section of the spec, and is fairly easy to understand. If you apply negative margins to a floated element that's adjacent to another float, it will simply move to its left (similar to having a left relative offset), over its sibling.
In the section on the float property, you'll find a list of "the precise rules that govern the behavior of floats." Now, I'm not 100% familiar with the float model, but these points are what I believe to be relevant:
2. If the current box is left-floating, and there are any left-floating boxes generated by elements earlier in the source document, then for each such earlier box, either the left outer edge of the current box must be to the right of the right outer edge of the earlier box, or its top must be lower than the bottom of the earlier box. Analogous rules hold for right-floating boxes.1
7. A left-floating box that has another left-floating box to its left may not have its right outer edge to the right of its containing block's right edge. (Loosely: a left float may not stick out at the right edge, unless it is already as far to the left as possible.) An analogous rule holds for right-floating elements.
8. A floating box must be placed as high as possible.
9. A left-floating box must be put as far to the left as possible, a right-floating box as far to the right as possible. A higher position is preferred over one that is further to the left/right.
So my guess is: a margin of -200px, which is as you say the negative equivalent of the width of the #left element itself, causes it to float all the way up and to the right (rather than to the left) and to hug the edge of the #center element which itself is also floated. The right edge of both elements touch each other because of this full, equal negative margin. Consequently, as you continue to increase (or decrease?) the negative margin, you'll see that the #left element continues to move to its left.
Note that the padding applied to the #container element doesn't interact with the margins; even if you remove the padding on either side or both sides, the margins will interact in the same way.
1 Note also that there's a statement in the section on collapsing margins in the linked section of the spec, that describes the behavior of negative margins, but that is irrelevant as the margins we are concerned with here are horizontal and belong to floated elements, and so are never affected by collapsing.
you are using <h2> tag for left and right heading but in center you are using <h1> that's why you have this problem if you want to solve this problem do one thing 1 use all <h2> tag for heading and if you want to use then apply below class on
h1
{
margin-top:10px;
}

div not floating along the preceding div with float property set to left

Which CSS rules explain the following sceanrio:
Assuming I have the following HTML CSS snippets
HTML:
<div id="main">
<div id="first">
first div float left
</div>
<div id="second">
second div does not have a float property set
and appears in a new line instead of next to
the first div
</div>
</div>
CSS:
#first
float: left
What I am wondering about is, why the second div floats next to the first div, only when its width is set. If I replace the second div with a paragraph, it also floats next the first div. So why does the second div only position next to the first one when its width is set or its own float property is set to float left?
By the way. I am not trying to achieve any sort of layout here. I am just trying to understand these particular behaviours of the div element and other block elements.
EDIT:
OK. First of all thanks for the answers. The problem I had was based on the fact that I did set the width of the first and the second div to the same value, so that the content of the second could not float around the first one. To sum things up, I guess it is important to know that elements with the float property set are taken put of the page flow and dont take up any space. Secondly one should remember only the content can flow around, not the actual div.
A <div> is a block level element which is 100% wide and has a line break before & after when it's within the normal content flow.
Technically, when you float a <div>, you're taking the element out of the normal flow so it no longer has a line-break before & after and also the other page content flows around it.
So why does the second div only position next to the first one when
its width is set or its own float property is set to float left?
Floated <div>'s will always appear side-by-side only if there's enough room to contain them side-by-side. Otherwise, the next floated <div> will wrap to a new line. This is because floated <div>'s are outside the content flow and defined to behave this way in the spec.
However, you've made some incorrect assumptions in your question about what happens when you set the width of the second (non-floated) <div>.
The second <div>, itself, is always underneath (meaning behind) the floated <div>. Whereas, the "content" of the second <div> always flows around the floated <div>. (see three examples below)
So whether or not you set the width of the second div, its content will still flow around the left floated div as you can see illustrated here in three examples. (For illustration purposes, the first <div> is red with 50% opacity and the second is blue with a thick green border.)
Fiddle with second div wider than first
Fiddle with no set width (100%) on second div
Fiddle with second div narrower than first
As you can see from all three examples above, despite the existence of the floated first <div>...
the second <div> always starts on the left edge of the screen despite the width of the second <div>.
the second <div> always starts on the top edge of the screen because there's no other page flow content above the second <div>.
the actual content of the second <div> flows around (to the right of) the floated first <div> only where there is enough room inside its container to allow it to flow around the floated <div>. Otherwise, it appears as if it's starting a new line where really only its content is continuing to flow around the bottom of the floated <div>.
W3C Spec: 9 Visual formatting model, 9.5 Floats
A float is a box that is shifted to the left or right on the current
line. 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. The following is an introduction to float
positioning and content flow; the exact rules governing float behavior
are given in the description of the 'float' property.
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.
If there is not enough horizontal room for the float, it is shifted
downward until either it fits or there are no more floats present.
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.
And here are a whole bunch of examples...
W3C Spec: 9 Visual formatting model, 9.8 Comparison of normal flow, floats, and absolute positioning
What makes you believe the div's are floated next to each other? In reality they are not. It's only that their content shows up next to each other but that's not because DIV #second is to the left of the floated DIV. It doesn't matter if you set the width or not.
What in fact is happening is that the floated DIV #first is floated to the left. Because it's floated, it's taken out of the normal flow. This means that DIV #second is actually on the same place as where DIV #first is appearing. The content of DIV #second though is inline content and inline content always flows around floated elements. Even floated elements that are outside of the container. So DIV #second is underneath DIV #first but the content of DIV #second is floating around DIV #first.
To illustrate that, I've create this CSS:
#first { float: left; background-color: rgba(255,0,0,0.3); }
#second { background-color: rgba(0,255,0,1); }
Play with the alpha value of the RGBA() value (i.e. the last parameter, it can range from 0 to 1) of the background-color of DIV #first and you will see that DIV #second is in fact below DIV #first all the time
Unless you clear your floats, the next block level element will float next to the last float by default.
I'm not sure what you're trying to achieve here, but if you want #first to float, and #second to NOT float, the rule you'd want to add to #first is : clear:both
But, that's pretty silly, you might as well just remove the float properties completely if you want to stack them.
Block elements take 100% of the width of their parent element, so even if your first div is floated, the second div will take the width of his parent, thus falling on a second line. This is why if you specify a smaller width, it stands next to the first floated div.
The reason why it also works if you float the two divs is that floated element behave a bit more like inline-block elements, wich means they will only take the space needed for the content inside of them.
Bottom line is, if you want these two divs to stand next to each other, you should probably just float the two of them.

Floats and horizontal margins

I have the following CSS:
label{
float:left;
margin-left:24px;
}
button{
margin-left:24px;
}
for this HTML:
<label>
<input>
</label>
<button>
and I was hoping that the button was found at a distance of 24 pixels of the label, however this did not happen until I floated the button to the left too. What part of the CSS specification I can refer to understand why this happening?
(Please, sorry my English.)
Just read the W3C documentation for float:
Here are the precise rules that govern
the behavior of floats:
The left outer edge of a left-floating box may not be to the
left of the left edge of its
containing block. An analogous rule
holds for right-floating elements.
If the current box is left-floating, and there are any
left-floating boxes generated by
elements earlier in the source
document, then for each such earlier
box, either the left outer edge of the
current box must be to the right of
the right outer edge of the earlier
box, or its top must be lower than the
bottom of the earlier box. Analogous
rules hold for right-floating boxes.
The right outer edge of a left-floating box may not be to the
right of the left outer edge of any
right-floating box that is next to it.
Analogous rules hold for
right-floating elements.
A floating box's outer top may not be higher than the top of its
containing block. When the float
occurs between two collapsing margins,
the float is positioned as if it had
an otherwise empty anonymous block
parent taking part in the flow. The
position of such a parent is defined
by the rules in the section on margin
collapsing.
The outer top of a floating box may not be higher than the outer top
of any block or floated box generated
by an element earlier in the source
document.
The outer top of an element's floating box may not be higher than
the top of any line-box containing a
box generated by an element earlier in
the source document.
A left-floating box that has another left-floating box to its left
may not have its right outer edge to
the right of its containing block's
right edge. (Loosely: a left float may
not stick out at the right edge,
unless it is already as far to the
left as possible.) An analogous rule
holds for right-floating elements.
A floating box must be placed as high as possible.
A left-floating box must be put as far to the left as possible, a
right-floating box as far to the right
as possible. A higher position is
preferred over one that is further to
the left/right.
It's because inline elements can't have a margin property. <label> is an inline element, and by floating it, you make it act as if it were an inline-block, allowing you to add a margin to it.
It's strange.
Try using display: inline-block; instead of float: left; and see what happens.
Sorry for my previous answer which I hope was deleted.
Margins are tricky. In this case, margins don't count against floats: they are computed from the place where the element would start if the float wasn't there. Possibly you can apply a margin-right to the float, or if you know the float's width add that plus its margin to the value you want to separate them.
A training made by the W3C consortium may help you.
And the specification with all the theory involved with this field: Visual formatting model

Resources