Busted Mug

A blog that documents solutions to the most frustrating problems that occur during development in technologies such as Java, XML, AJAX, SQL, CSS and others that make me want to throw my coffee mug against the cube wall.

Monday, December 11, 2006

IE Select z-index bug (w/select-free layer and autosuggest)

Recently I ran into one of the biggest nasties I've ever seen. It is in IE (fixed in 7 thankfully). When you've got any element over a select box, the select box breaks through and shows on the top. It is a real bugger to fix. This page INCORRECTLY throws in the towel and says you can't fix it so just alter your design. To it's credit, it does sum up the problem pretty well and has a nice pic: I ran into this while implementing Autosuggest which I think is a great UI add-on. However, you'll run into issues when you autosuggest overtop of a select. No good. The solution to the select popping over is called Select-free layer. It is very interesting. Don't be confusing by the dragginess of their example. All it does is filter a hidden iframe though to cover any selects, since an iframe doesn't suffer the bug (unless you have selects on that, then heaven help you). In a nutshell they use this css:
<style> .select-free { position:absolute; z-index:10;/*any value*/ overflow:hidden;/*must have*/ width:33em;/*must have for any value*/; } .select-free iframe { display:none;/*sorry for IE5*/ display/**/:block;/*sorry for IE5*/ position:absolute;/*must have*/ top:0;/*must have*/ left:0;/*must have*/ z-index:-1;/*must have*/ filter:mask();/*must have*/ width:3000px;/*must have for any big value*/ height:3000px/*must have for any big value*/; } .select-free .bd{border:solid 1px #aaaaaa;padding:12px;} </style> <div class="select-free" id="dd3"><div class="bd"> your content here </div><!--[if lte IE 6.5]><iframe></iframe><![endif]--></div>
I had the agonizing task of integrating this with autosuggest. It isn't fun. Some css had to be changed:
<style type="text/css"> /* =========================== styling for autosuggest =========================== */ .autosuggest{ position:absolute; z-index:10;/*any value*/ overflow:hidden;/*must have*/ width:100px;/*must have for any value*/; } .autosuggest .bd{border:solid 0px #aaaaaa;padding:0px;} .autosuggest #mask{ border: 0px; margin: 0px; display:none;/*sorry for IE5*/ display/**/:block;/*sorry for IE5*/ position:absolute;/*must have*/ top:0;/*must have*/ left:0;/*must have*/ z-index:-1;/*must have*/ filter:mask();/*must have*/ width:3000px;/*must have for any big value*/ height:3000px/*must have for any big value*/; } ul.autosuggest { //position: absolute; list-style: none; margin: 0; padding: 0; //overflow-y: auto; } ul.autosuggest li { text-align: left; border-bottom: 1px solid blue; border-left: 1px solid blue; border-right: 1px solid blue; } ul.autosuggest li a:link, ul.autosuggest li a:visited { display: block; padding: 0px; text-decoration: none; text-color: black; background-color: #EEEEEE; } ul.autosuggest li a:hover, ul.autosuggest li a:active { color: #fff; background-color: green; } ul.autosuggest li.highlight a:link, ul.autosuggest li.highlight a:visited { color: #fff; background-color: green; } </style>
(mask is the id of my iframe btw) and then I had to change some of BSN's javascript to support select-free layer:
_bsn.AutoSuggest.prototype.createList = function(arr) { // clear previous list // this.clearSuggestions(); // create and populate ul // var ulWrap = _bsn.DOM.createElement("div", { id:this.idAs, className:this.oP.className }); var ulCont = _bsn.DOM.createElement("div", { id:"inner", className:"bd" }); var ul = _bsn.DOM.createElement("ul", {id:this.idAs+"ul", className:this.oP.className}); var pointer = this; for (var i=0;i<arr.length;i++) { var a = _bsn.DOM.createElement("a", { href:"#" }, arr[i]); a.onclick = function () { pointer.setValue( this.childNodes[0].nodeValue ); return false; } var li = _bsn.DOM.createElement( "li", {}, a ); ul.appendChild( li ); } var pos = _bsn.DOM.getPos(this.fld); ulWrap.style.overflow = "hidden"; ulWrap.style.left = pos.x + "px"; ulWrap.style.top = ( pos.y + this.fld.offsetHeight ) + "px"; ulWrap.onmouseover = function(){ pointer.killTimeout() } ulWrap.onmouseout = function(){ pointer.resetTimeout() } ul.style.width = this.fld.offsetWidth + "px"; ulCont.style.width = this.fld.offsetWidth + "px"; ulWrap.style.width = this.fld.offsetWidth + "px"; ulCont.style.height = ((ul.childNodes.length-1) * (this.fld.offsetHeight+2)+6); ulWrap.style.height = ((ul.childNodes.length-1) * (this.fld.offsetHeight+2)+6); ulCont.appendChild(ul); ulWrap.appendChild(ulCont); ulWrap.innerHTML += "<!--[if lte IE 6.5]><iframe id=\"mask\"></iframe><![endif]-->"; //document.getElementsByTagName("body")[0].appendChild(ul); document.getElementsByTagName("body")[0].appendChild(ulWrap);
In the end it was a real bugger to get going but sure enough my auto suggest is no longer broken by IE's stupid bug. I hope this helps any other poor souls that face this task. If you suffer from IE's select bug at all I highly recommend select-free layer. If I wasn't doing autosuggest too it would have been an easy patch to apply. I hate IE btw ;) They made me play DHTM-Hell for a few days this time.

0 Comments:

Post a Comment

<< Home