Clean CSS fix of IE7's 'float: right' drop bug - css

I continuously find myself having problems with elements floated right in IE7.
I have read many Stack Overflow questions which are similar to this one but there doesn't seem to be any consistently clean CSS answers.
What I mean by this is is I want to see answers which DO NOT change the HTML. E.g:
Put the floated element first
Add a 'clear: both' div after the floated element.
I understand that sometimes the floated element doesn't account for its parents height and therefore sometimes fails to contain it properly. Occasionally I find myself 'adding layout' to an element with zoom: 1 which sometimes fixes it. Other times I find myself messing about in a conditional IE7 style-sheet which isn't the best fix in my opinion.
Note: What I mean by 'having layout' - http://www.satzansatz.de/cssd/onhavinglayout.html
I have also read other answers to do with using relative and absolute positioning (parent div and child div respectively). This pulls it up but often affects surrounding divs.
I would be happy to add a bounty to this question if someone can give an in depth explain as to the reasons this happens and a detailed discussion of the various fixes, IDEALLY CSS ONLY!
Many thanks!
EDIT
The most common problem I encounter is when I have something like this:
Left Sidebar - Main - Right Sidebar
Right will often drop when floated. Ideally this should be in the format Left - Right - Main, but I continuously find myself styling developers work (Drupal mainly) where this is the case and it is too much hassle to get them to change their work. Make sense? Because I'm styling developers work they never put the clear block in too (which personally I think is horrible and dirty anyways!)

Introduction
Your title indicates a desire to see a fix for the float: right drop bug, but your text implies some broader scope desire to see solutions to “problems with elements floated right in IE7.” There are many general problems with floated elements (right or left) in that browser. Even though one may question whether support of the IE7 browser is worthy of much attention any more, it undoubtedly will remain so for some people for some time. Therefore, I’m going to take the opportunity here to address numerous issues at once regarding floats in that browser. Note that many experiments and references below come from an excellent resource: http://www.brunildo.org/test/index.html.
CSS for the Containing Element
For a containing parent to the floated element the following css should be set:
.container {
overflow: auto; /* forces clearing of the child float */
zoom: 1; /* give it layout (this can be some other css that does likewise) */
}
Making sure it hasLayout is important to prevent types of margin and padding errors, a type of peek-a-boo bug, and allowing the overflow to clear. For a sequence of floats, some html may need changing if padding on the container is desired to work properly.
With regards to one “drop” issue with a float: right, you may want to avoid setting an explicit height or max-height on the container. A min-height is okay. Setting a height and then having the float be taller than the container makes IE7 not behave with following elements. There is no pure css solution that I have found noted.
If the container is itself position: absolute there can be issues with positioning a float that may require that float itself to be set to position: absolute instead of being floated.
References:
For overflow to clear -- http://www.quirksmode.org/css/clearing.html
Margins -- http://www.brunildo.org/test/IEFloatAndMargins.html
Peek-a-boo -- http://www.brunildo.org/test/iew_boo.html and http://www.brunildo.org/test/iew_boo3.html
Float sequence padding -- http://www.brunildo.org/test/IEmfloa.html
Avoiding height -- http://austinmatzko.com/2007/07/25/internet-explorer-7-float-bug/, http://www.brunildo.org/test/fenc7.html (and his similar problem link on that page).
Container is absolute -- Floating Too Far Right!
CSS for the Floated Child
For a the floated child element, the css (besides float: right) to set depends on two things:
Absolute Container
Again, as noted above, a containing parent that is absolute may require a change in how the child is handled.
Float is Also a Clearing Element
If the float is also going to have a clear set on it, then there are numerous issues that can arise depending totally upon the html and css of the elements around it. There is no single canonical fix, so look at the references below.
References:
Container is absolute -- Floating Too Far Right!
Also having clear -- http://www.brunildo.org/test/IEWfc.html, http://www.brunildo.org/test/IEWfc2.html, http://www.brunildo.org/test/IEWfc3.html
CSS for Child Elements of Container Before the Float
If the float: right follows an element in the html structure that should be to its left (and not above it), then that preceding element(s) must be float: left.
CSS for Child Elements of Container After the Float
A Clear Element
For an element after the float that has clear set, then if it has padding and background-color, make sure it also hasLayout to avoid a doubling of the padding; also this prevents extra space above the clear due to container padding, and avoids other margin issues.
References:
For padding -- http://www.brunildo.org/test/IEClearPadding.html and http://www.brunildo.org/test/IEFloatClearPadding.html
For margins -- http://www.brunildo.org/test/Op7_margins_float.html (look down the page for IE7)
A Paragraph Before a Clear Element
Having a paragraph with a margin-bottom and shorter in height than the float, located between the floated element and a clearing element, can create an extra gap between the clear and the float equal to that margin. There is no known pure css fix other than giving the paragraph a zero bottom margin (which may not be acceptable if the paragraph may go taller than the float).
Reference:
Paragraph following -- http://www.brunildo.org/test/IEFloatClearMargin.html
Conclusion
I cannot guarantee I have addressed every issue that may occur with a right floated object, but certainly many major ones are covered. As to “why” these things happen, it is all “bugginess` in IE7.

Have you tried to use the clearfix solution to collapsing divs? There are variations on this and there is a newer version but I don't have the url to hand, but this is standard clearfix css which you add to the parent element that is collapsing and causing issues with floated elements http://www.webtoolkit.info/css-clearfix.html. Chris Coyer has a better version here http://css-tricks.com/snippets/css/clear-fix/.
You say "I understand that sometimes the floated element doesn't account for its parents height and therefore sometimes fails to contain it properly" this is kind of true, the parent will collapse if all child elements are floated. This is due to the elements being removed from the normal flow, when this occurs the parent div is unable to calculate its height and collapses as if there isn't anything inside of the div.
But without seeing the page and the issue you are having I can only estimate that the issue is due to IE6-IE7's haslayout property which is really annoying, they sorted it out from version 8 upwards but it does add extra development time to your build.
But in most situations the clearfix solution is best as it doesn't add extra markup to the page such as
<div style="clear: both"></div>
this is old and out of date and should be avoided.
I hope this helps you, if you need any more information or I have not answered the question just ask.

We have been using the clearfix solution for years now.
.cf:after { content: "."; display: block; clear: both; visibility: hidden; line-height: 0; height: 0; }
.cf { display: inline-block; }
html[xmlns] .cf { display: block; }
* html .cf { height: 1%; }
This is a simple CSS class which, ideally, has to be applied to a container that has any child float elements. Since you're restrictive about not changing the HTML at all, you can either:
replace all occurrences of .cf with your own div's selector [or]
use JS to apply the class (which is bad because users will see a broken layout a few seconds until the page loads completely) [or]
use PHP ob_start() + regex to apply the class [or]
just go vintage and rewrite everything using tables (as we used to do in the `90s)

It's simple:
Where you have float:right, add *clear:left.
Or where you have float:left, add *clear:right.
* for IE7-
Or for validation
*+html .class{clear:left/right}

I know it's been a year since this was posted, but I found a solution that I like for this. The gist is using 'expression' tag in your CSS for IE7 only to move the floated element to be the first element of the parent in the DOM. It will be semantically correct for all other browsers, but for IE7 we modify the DOM to move the floated element.
In my case, I have:
<div>
<h1></h1>...<p>any other content...</p>
<small class="pull-right"></small>
</div>
In my CSS for pull-right, I use:
.pull-right {
float:right;
*zoom: ~"expression( this.runtimeStyle.zoom='1',parentNode.insertBefore( this,parentNode.firstChild ))";
}
The result is that IE7 moves my <small> to be the first element of <div> but all other browsers leave the markup alone.
This might not work for everyone. Technically, it is modifying the markup but only in the DOM for IE7 and it's also a javascript solution.
Also, I understand there may be some performance issues with expression (it's slow), so perhaps it's not ideal there are a lot of floats like this. In my case, it worked well and allowed me to keep semantically correct HTML.

Related

Advantages of using display:inline-block vs float:left in CSS

Normally, when we want to have multiple DIVs in a row we would use float: left, but now I discovered the trick of display:inline-block
Example link here.
It seems to me that display:inline-block is a better way to align DIVs in a row, but are there any drawbacks? Why is this approach less popular then the float trick?
In 3 words: inline-block is better.
Inline Block
The only drawback to the display: inline-block approach is that in IE7 and below an element can only be displayed inline-block if it was already inline by default. What this means is that instead of using a <div> element you have to use a <span> element. It's not really a huge drawback at all because semantically a <div> is for dividing the page while a <span> is just for covering a span of a page, so there's not a huge semantic difference. A huge benefit of display:inline-block is that when other developers are maintaining your code at a later point, it is much more obvious what display:inline-block and text-align:right is trying to accomplish than a float:left or float:right statement. My favorite benefit of the inline-block approach is that it's easy to use vertical-align: middle, line-height and text-align: center to perfectly center the elements, in a way that is intuitive. I found a great blog post on how to implement cross-browser inline-block, on the Mozilla blog. Here is the browser compatibility.
Float
The reason that using the float method is not suited for layout of your page is because the float CSS property was originally intended only to have text wrap around an image (magazine style) and is, by design, not best suited for general page layout purposes. When changing floated elements later, sometimes you will have positioning issues because they are not in the page flow. Another disadvantage is that it generally requires a clearfix otherwise it may break aspects of the page. The clearfix requires adding an element after the floated elements to stop their parent from collapsing around them which crosses the semantic line between separating style from content and is thus an anti-pattern in web development.
Any white space problems mentioned in the link above could easily be fixed with the white-space CSS property.
Edit:
SitePoint is a very credible source for web design advice and they seem to have the same opinion that I do:
If you’re new to CSS layouts, you’d be forgiven for thinking that
using CSS floats in imaginative ways is the height of skill. If you
have consumed as many CSS layout tutorials as you can find, you might
suppose that mastering floats is a rite of passage. You’ll be dazzled
by the ingenuity, astounded by the complexity, and you’ll gain a sense
of achievement when you finally understand how floats work.
Don’t be fooled. You’re being brainwashed.
http://www.sitepoint.com/give-floats-the-flick-in-css-layouts/
2015 Update - Flexbox is a good alternative for modern browsers:
.container {
display: flex; /* or inline-flex */
}
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
More info
Dec 21, 2016 Update
Bootstrap 4 is removing support for IE9, and thus is getting rid of floats from rows and going full Flexbox.
Pull request #21389
While I agree that in general inline-block is better, there's one extra thing to take into account if you're using percentage widths to create a responsive grid (or if you want pixel-perfect widths):
If you're using inline-block for grids that total 100% or near to 100% width, you need to make sure your HTML markup contains no white space between columns.
With floats, this is not something you need to worry about - the columns float over any whitespace or other content between columns. This question's answers have some good tips on ways to remove HTML whitespace without making your code ugly.
If for any reason you can't control the HTML markup (e.g. a restrictive CMS), you can try the tricks described here, or you might need to compromise and use floats instead of inline-block. There are also ugly CSS tricks that should only be used in extreme circumstances, like font-size:0; on the column container then reapply font size within each column.
For example:
Here's a 3-column grid of 33.3% width with float: left. It "just works" (but for the wrapper needing to be cleared).
Here's the exact same grid, with inline-block. The whitespace between blocks creates a fixed-width space which pushes the total width beyond 100%, breaking the layout and causing the last column to drop down a line.
Here' s the same grid, with inline-block and no whitespace between columns in the HTML. It "just works" again - but the HTML is uglier and your CMS might force some kind of prettification or indenting to its HTML output making this difficult to achieve in reality.
If you want to align the div with pixel accurate, then use float. inline-block seems to always requires you to chop off a few pixels (at least in IE)
You can find answer in depth here.
But in general with float you need to be aware and take care of the surrounding elements and inline-block simple way to line elements.
Thanks
There is one characteristic about inline-block which may not be straight-forward though. That is that the default value for vertical-align in CSS is baseline. This may cause some unexpected alignment behavior. Look at this article.
http://www.brunildo.org/test/inline-block.html
Instead, when you do a float:left, the divs are independent of each other and you can align them using margin easily.

CSS Floating inline elements (960 GS)

I was just checking out 906.gs css code and noticed that they made all the floated divs inline.
http://960.gs/demo.html
Just wondering what the purpose of that is...I am always interested in learning CSS theories.
An element with float: left is forced to have a computed display value of block.
For more information on that, see: jQuery in Chrome returns "block" instead of "inline"
The purpose of also adding display: inline is to fix an IE6 bug, the "double margin bug":
http://www.positioniseverything.net/explorer/doubled-margin.html
A coder innocently places a left float
into a container box, and uses a left
margin on the float to push it away
from the left side of the container.
Seems pretty simple, right? Well it is
until it's viewed in IE6. In that
browser the left float margin has
mysteriously been doubled in length!
It's a free fix with no downsides (even in IE6):
That means that {display: inline;} on
a float should be no different than
using {display: block;} (or no display
value at all), and indeed all browsers
follow this specification, including
IE. But, this does somehow trigger IE
to stop doubling the float's margin.
Thus, this fix can be applied
straight, without any fussy hiding
methods.
In fact, you could just apply the
Inline Fix to all floats if you like,
since there are no known side-effects.
That way the bug can never gain
traction regardless of any margins you
might or might not use.

A depth (z-index) nightmare

The best way to illustrate this question is with...a Fiddle! Before you visit the fiddle, notice there is text behind the grayest element, which is on top of a light gray element that has a border.
There is a main wrapping div (root), and two wrapping divs inside (wrap1 and wrap2). The problem here is that I need the content of wrap2 (highlight) to be behind the content of wrap1 (text), but in front of the background of the root.
This, however, must not change:
The HTML, the elements and wraps should be left untouched. Excluding the order of wrap1 and wrap2 inside root.
The highlight div must keep the absolute positioning.
Styling highlight with background-color is not an option, the existence of highlight is a must.
PS: the italics reference the id's of <div>s in the fiddle example, for whomever was too lazy to visit it.
I was able to display the text in front of the highlight by adding a z-index to text. (Adding the z-index to wrap1 also works.) The trick is to remember that z-index doesn't apply to statically-positioned elements, so you need to give the same div position: relative.
#text {
position: relative;
z-index: 1000;
}
(Large z-index because I've been bitten by IE not respecting low values in the past. May or may not still be an issue. ;-)
z-index can be difficult to grasp. I think somebody already answered your question, but if you want to learn more how they work, this is a pretty comprehensive guide:
http://www.onextrapixel.com/2009/05/29/an-indepth-coverage-on-css-layers-z-index-relative-and-absolute-positioning/
And also, here is a link where you can try out different z-index and how they are affected by different position properties (the main reason for difficulty)
http://tjkdesign.com/articles/z-index/teach_yourself_how_elements_stack.asp
#wrap1{position:absolute;z-index:2;}

Help clearing floats, what do you think of this global method?

I'm just learning the ropes on clearing floats for all browsers and had and idea.
Do you see any harm in defining this globally for all div elements?
div {
_zoom: 1; /* Clear floats for ie6. Does NOT validate. */
overflow: hidden; /* Clear floats for all other browsers. */
}
There would probably only be a few special cases where the above two rules would need to be overwritten. Off the top of my head, I can't think of any problems that might come up as a result of the above rule, but maybe someone knows better?
What do you think?
EDIT 1:
Changed height: 100%; to _height: 1%;.
EDIT 2:
Changed _height: 1%; to _zoom: 1;.
This is the version I'm running with. Here is an excellent link to an article describing all clearing methods for newbies.
One potential problem you could run into is what happens when you float elements that arent divs. Your style covers <div /> tags, but nothing else so you'd have to keep that in mind in case you do use float on other tags.
It may be better to apply those styles to containers that need to clear floats rather than applying a catch-all that may not catch everything.
Also keep in mind that having hidden overflow may make it hard to apply some styles which rely on content extending beyond a div tag. A few situations I can think of are
styles for sides or corners of elements for adding shadows or rounded corners, which typically overflow their container.
Light boxes which may extend beyond the bounds of your container, if they're placed within a <div />
Custom javascript tooltips that are placed within <div />s. Tooltips typically "pop out" of their container, which could cause problems depending on how they're designed.
These issues are easier to work around if you only do it on elements you need to and not all elements.
It would cause problems. Take a look at these images, 1 is regular, 2 is with div {height: 100%;}
(source: zastica.com)
(source: zastica.com)
There were also a few other inconsistencies with just that one setting. So, you can get some strange unexpected behavior.

IE 6 & IE 7 Z-Index Problem

http://madisonlane.businesscatalyst.com
I'm trying to get the div#sign-post to sit above the div#bottom. This works fine in all browsers except IE6 & IE7. Can anyone see what the problem is here?
Also IE6 is displaying an additional 198px to the top of div#bottom.
Most of the answers here are wrong; some work, but not for the reason they state. Here is some explanation.
This is how z-index should work according to the spec:
you can give a z-index value to any element; if you don't, it defaults to auto
positioned elements (that is, elements with a position attribute different from the default static) with a z-index different from auto create a new stacking context. Stacking contexts are the "units" of overlapping; one stacking context is either completely above the another (that is, every element of the first is above any element of the second) or completely below it.
inside the same stacking context, the stack level of the elements is compared. Elements with an explicit z-index value have that value as a stack level, other elements inherit from their parents. The element with the higher stack level is displayed on top. When two elements have the same stack level, generally the one which is later in the DOM tree is painted on top. (More complicated rules apply if they have a different position attribute.)
In other words, when two elements have z-index set, in order to decide which will show on top, you need to check if they have any positioned parents which also have z-index set. If they don't, or the parents are common, the one with the higher z-index wins. If they do, you need to compare the parents, and the z-index of the children is irrelevant.
So the z-index decides how the element is placed compared to other children of its "stacking parent" (the closest ancestor with a z-index set and a position of relative, absolute or fixed), but it doesn't matter when comparing to other elements; it is the stacking parent's z-index (or possibly the z-index of the stacking parent's stacking parent, et cetera) which counts. In a typical document where you use z-index only on a few elements like dropdown menus and popups, none of which contains the other, the stacking parent of all the elements which have a z-index is the whole document, and you can usually get away with thinking of the z-index as a global, document-level ordering.
The fundamental difference with IE6/7 is that positioned elements start new stacking contexts, whether they have z-index set or not. Since the elements which you would instinctively assign z-index values to are typically absolutely positioned and have a relatively positioned parent or close ancestor, this will mean that your z-index-ed elements won't be compared at all, instead their positioned ancestors will - and since those have no z-index set, document order will prevail.
As a workaround, you need to find out which ancestors are actually compared, and assign some z-index to them to restore the order you want (which will usually be reverse document order). Usually this is done by javascript - for a dropdown menu, you can walk through the menu containers or parent menu items, and assign them a z-index of 1000, 999, 998 and so on. Another method: when a popup or dropdown menu becomes visible, find all its relatively positioned ancestors, and give them an on-top class which has a very high z-index; when it becomes invisible again, remove the classes.
Agree with validator comment - validating usually helps. But, if it doesn't heres a few pointers for z-index in IE:
1) elements who's z-index you're manipulating should be on the same level ie. you should be setting the z-index of #bottom and #body
if this is not feasible then
2) IE sometimes wont apply the z-index correctly unless the elements ou are applying it to have a position:relative. Try applying that property to #bottom and #body (or #signpost)
let me know how that works out
Darko
I just had this problem and the fix I found (thanks to Quirksmode) was to give the direct parent of the node you are trying to set a z-index of it's own z-index that is at less than the z-index of the node you are trying to set. Here is a quick example that should work in IE6
<html>
<head>
<style type="text/css">
#AlwaysOnTop {
background-color: red;
color: white;
width: 300px;
position: fixed;
top: 0;
z-index: 2;
}
#Header {
color: white;
width: 100%;
text-align: center;
z-index: 1;
}
</style>
</head>
<body>
<div id="Header">
<div id="AlwaysOnTop">This will always be on top</div>
</div>
<div id="Content">Some long amount of text to produce a scroll bar</div>
</body>
</html>
Welcome, I solved the problem with:
.header {
position: relative;
z-index: 1001;
}
.content {
position: relative;
z-index: 1000;
}
Looks to me like you have some malformed HTML in there. I tried counting, and perhaps I lost count of the opening and closing tags, but it looks like div#container isn't closed. Try running your page through a validator (such as W3C's HTML Validator, or something) and fixing some of the errors. That's helped me with these sorts of problems in the past. Good luck!
I've recently had an ongoing problem displaying one layer above another. In my case I was programmatically creating two layers in Javascript, one for diaplaying a custom control and one for creating a full screen layer behind it. FF was fine, bu IE displayed the full screen layer always on top of everything else.
After numerous trawls over the interweb, trying everyone's suggestions, the only way I eventually get it working was to remove position: attributes from both layers, and tweak the margin-top: attribute until I got a satisfactory result.
A bit of a hash, but it works and it'll be fine until IE 8 sorts out all of the current bugs......
the only reliable solution is, to put the top elements below in the code and then push them over the other stuff with absolute positioning.
e.g. Wordpress:
put the navigation in the footer file, but still inside the page wrapper.
might also bring some advantages for search engines, because they can directly start with the content, without crawling through the menu first...
UPDATE:
I need to correct myself. While putting the element below and then pushing it over is still the easiest way, there are certain cases when this is not possible in reasonable time. Then you have to make sure that each and every parent element has some kind of positioning and some senseful z-index. Then the z-index should work again even in IE7.

Resources