TRIM Support Enabled in Windows 7

In a command line window:

fsutil behavior query disabledeletenotify

DisableDeleteNotify = 1 (Windows TRIM commands are disabled)
DisableDeleteNotify = 0 (Windows TRIM commands are enabled)

Advertisements

IE7 z-index Bug and Workaround

For the tl;dr Crowd

find all the parent elements in your page that are

  • position : relative
  • position : absolute
  • position : fixed

Set descending z-index values for each. I.e., the first element that matches the above should start with say z-index 1000, the second should get 999, and so on until all positioned elements are given descending order z-index values.

This fix will only work top-left to bottom-right.  Meaning, if you have normal fly-out menus, the above should get your visually at par with Chrome or Firefox.  This may not work for you if your the absolutely positioned visual element is lower down in the DOM hierarchy.

The (really) Long Version

IE7 is an order of magnitude easier to build web applications and web pages versus the Sisyphean effort required to get IE6 compliant.  But it is not without it’s own set of unique and equally difficult bugs.

One bug that has several posts scattered around the ‘net is the infamous IE7 z-index stacking order bug.  A one-sentence precis of this bug is z-indexed elements do not respect their assigned stacking order when used in conjunction with absolute and relative positioning.

Some required reading:

  • Quirksmode – from 2006, and maybe a bit dated
  • Brenelz – decent fix, but incorrect assessments in main post
  • StackOverflow – accepted solution has the correct analysis, and a fix for the asker
  • Webdemar – offers a simple solution – it may be all you need to fix your issue

A brief sample

To illustrate, examine this example: Simple Example

View the source of the sample page to get an idea of the markup that will cause this bug.  The example shows exactly what is needed to fix this particular instance, but to fix the doubtlessly more complicated examples found in most web applications/pages requires a bit more digging, and a lot more understanding.

If the above links didn’t solve your issue, you are in the boat I was (still am?) in; sometimes floundering to apply what should be turn-key solutions/workarounds into magical fixes.

The problem

The gist of the IE7 z-index bug is that a positioned element (i.e., one that is positioned absolutely, relatively, or fixedly) will reset the z-index stacking order to 0.  In a vacuum, this would go unnoticed, but when applied in conjunction with other elements that are absolutely positioned, the bug symtoms show themselves.

The solution at a glance

The workaround is to cascade a reverse z-index through your DOM; in effect, you assign the highest z-index to the positioned elements as you work your way down through the node tree.  Assume the following example has position:relative for all the elements:


body
    div - 10000
        div - 9900
            div - 9890
            div - 9880
                div - absolutely positioned menu (or something)
                    - this will display above 9800 (and its widget), 9700, etc.
        div - 9800
            div - widget, child nodes are absolutely positioned
                (before the z-index fix, this would obstruct the menu)
        div - 9700
    div - 9000
    div - 8000

A simple bit of Javascript could massage the DOM for you automatically.  Say the problematic widget is an absolutely positioned flyout menu that is built and applied as the child of DIV 9890.  Upon instantiation, have a utility method crawl up the DOM tree and sniff for postioning, and if found, apply a descending z-index value.  Something like the following pseudo-code should get you well on your way:

var IE7Kludge = {
    zIndex : 10000,
    applyIe7Workaround : function(el) {
        var p = el.parentNode;
        while(p != document.body) {
            if(p.style.position == 'absolute' || p.style.position == 'fixed' || p.style.position == 'relative') {
                p.style.zIndex = this.zIndex--;
            }
        }
    }
}
IE7Kludge.applyIeWorkaround(document.getElementById("myWidgetRootId");

 

Another problem

The crux of the issue is finding all those elements in your DOM hierarchy that do have positioning.  In the apps I work on, there are literally dozens of widgets running side-by-side that instantiate, append, and apply behavior after the DOM has loaded fully.  The above solution caught roughly 75% of the issues, but there were lots of stragglers that I had to manually find and apply my fixes.  For this, I used a slightly modified version of the above, and ran it before my widget-triggered version (pardon the jQuery, but one could easily modify this to fit POJS or any number of other libraries that offer CSS selectors):

var IE7Kludge = {
    zIndex : 10000,
    fixStragglers : function(j) {
        var idx = this.zIndex;
        j.each(function(i, el) {
            idx = idx-10;
            $(el).css("zIndex", idx);
        });
        this.zIndex = idx;
    }
}
IE7Kludge.fixStragglers($('.myCrazy, .selector, .that-finds-all-relative-positioned-elements'));

Yet another problem

With the above two utility methods, I was able to get to about 90% compliance.

The last 10% is due to the fact that this workaround works only top-left to bottom-right. If I only supported widgets that flew out to the left, or top to bottom, there would be no more work to be done, but if you have widgets that fly out bottom-up (say, a viewport aware info bubble that pops above an anchor element if near the bottom of the viewport), its hierarchical z-index stacking is below elements above it in the DOM.  So yet another set of headaches to deal with.

The fix for this last issue is similar to the first kludge, walking the DOM.  There are some caveats, and this may or may not apply to your situation:

  1. While running the 1st fix, I made sure to keep references to the modified elements in order of manipulation, working my way up the DOM tree.  It was easy enough to do this by .push()’ing the element references into a handy array that I could access in a callback when the fly-out closed itself.
  2. While iterating through that array, we must treat it FILO (first in, last out) stack, as IE7 apparently calculates the z-index stacking order from the root node onwards, not as a gestalt sum after all behaviors are applied.  The handy array.pop() method makes this a simple exercise.

The pseudo code for this (again in jQuery-speak):


var IE7Kludge = {
    zIndex3 : 10000,
    seed : new Date().getTime(),

    generateGUID : function() {
        return "custom_id_" + this.seed++;
    }

    handleInstanceManipulation : function(el) {
        var pos, j, z, p = el.parentNode;
        var backup = [];
        var z3 = this.zIndex3;

        while(p != document.body) {
            j = $(p);
            pos = j.css("position");
            z = j.css("zIndex");

            if(pos == 'relative' || pos == 'absolute' || pos == 'fixed') {
                if(p.id == "") {
                    p.id = this.generateGUID();
                }

                backup.push({
                    selector : p.id,
                    zIndex : z
                });
                j.css("zIndex", z3--);
            }

            j = null;
            p = p.parentNode;
        }

        return backup;
    },

    resetInstanceManipulation : function(backup) {
        var i;
    	while(backup.length > 0) {
    	    i = backup.pop();
    	    $(i.selector).css("zIndex", i.zIndex);
    	}
    }
}

Home stretch

With the combination of the above 3 workarounds, I was able to get my web app fully compliant in IE7. For convenience’s sake, here’s a skeleton of my static methods. If you’re in a jQuery shop, it’s basically a drop-in, otherwise you’ll have to account for how the DOM reports CSS values (instance, javascript assignment, and external css files). Hope this helps someone.

var IE7Kludge = {
    zIndex3 : 10000,
    zIndex : 10000,
    seed : new Date().getTime(),

    generateGUID : function() {
        return "custom_id_" + this.seed++;
    },

    applyIe7Workaround : function(el) {
        var p = el.parentNode;
        while(p != document.body) {
            if(p.style.position == 'absolute' || p.style.position == 'fixed' || p.style.position == 'relative') {
                p.style.zIndex = this.zIndex--;
            }
        }
    },

    fixStragglers : function(j) {
        var idx = this.zIndex; // this value must stay at the preset value every time, so we copy it
        j.each(function(i, el) {
            idx = idx-10;
            $(el).css("zIndex", idx);
        });
        this.zIndex = idx;
    },

    handleInstanceManipulation : function(el) {
        var pos, j, z, p = el.parentNode;
        var backup = [];
        var z3 = this.zIndex3; // this value must stay at the preset value every time, so we copy it

        while(p != document.body) {
            j = $(p);
            pos = j.css("position");
            z = j.css("zIndex");

            if(pos == 'relative' || pos == 'absolute' || pos == 'fixed') {
                if(p.id == "") {
                    p.id = this.generateGUID();
                }

                backup.push({
                    selector : p.id,
                    zIndex : z
                });
                j.css("zIndex", z3--);
            }

            j = null;
            p = p.parentNode;
        }

        return backup;
    },

    resetInstanceManipulation : function(backup) {
        var i;
    	while(backup.length > 0) {
    	    i = backup.pop();
    	    $(i.selector).css("zIndex", i.zIndex);
    	}
    }
}