 |
Windowed Controls and the absurd SELECT box "feature"
[reply]
|
06/22/05 12:56 PM EST posted by JER email web |
|
If you've ever written a DHTML menu, you've no doubt seen the IE 5.5+ bug that positions SELECT boxes on top of DHTML controls. No matter what you use as a z-index value, your menu simply will not appear in front of the select box. The "how and why" of this behavior is explained by Microsoft here: INFO: How the Z-index Attribute Works for HTML Elements
One workaround I've used in the past (I think I stole this from Blearns) is to hide all select elements when the DHTML menu pops up, then make them re-appear when the menu is minimized. This is Microsoft's 1st suggested solution & works like so:
for (j=0; j<document.forms.length; j++) { var thisForm = document.forms[j] if(thisForm.elements != null){ for(i=0; i < thisForm.elements.length; i++){ if(thisForm.elements[i].tagName == "SELECT" { // you can also use .type = "select-one", I believe thisForm.elements[i].style.visibility = "visible"; } } } }
That gets the job done and is barely noticeable, but I've received feedback that it was "a hack" or "disorienting." Another solution that I implemented this morning was inspired by Microsoft's bizarre explanation of how an iFrame is a "windowed control" but also somehow isn't a windowed control, because it can interact with both windowed & non-windowed controls. It's just as much of a hack as the first approach but is unnoticeable by the end user. Based on Microsoft's gobbledy-gook explanation, my theory was that one can sandwich an iFrame between a DHTML menu and a SELECT box, which will hide the SELECT box. After some tinkering, I came up with an iFrame solution works like so.
1. Create your DHTML menu however you normally do it but place an iFrame immediately after your control. Notice that the iFrame is not displayed by default:
<span id=myDhtmlMenu onClick="drawMenu()" style="position:absolute; z-index:99; width:200px; height:100px">Click Here!</span><iframe id="myIFrame" style="position:absolute; display:none" frameborder=0 scrolling=no marginwidth=0 src="" marginheight=0> </iframe>
<p><select id=someAHoleSelectControl><option value=1>Some Select Value</option></select>
2. In the drawMenu() function, you can then resize, reposition and lower the z-index of the iFrame to achieve the "hidden SELECT'" result:
function drawMenu(){ if(document.getElementById && document.getElementById('myIFrame')){ //Make the iFrame visible document.getElementById('myIFrame').style.display = '';
document.getElementById('myIFrame').width = document.getElementById('myDhtmlMenu').style.width; document.getElementById('myIFrame').height = document.getElementById('myDhtmlMenu').style.height; document.getElementById('myIFrame').style.left = document.getElementById('myDhtmlMenu').style.left; document.getElementById('myIFrame').style.top = document.getElementById('myDhtmlMenu').style.top;
//Set the iFrame's index to a value greater than everything EXCEPT our popup. document.getElementById('myIFrame').style.zIndex = document.getElementById('myDhtmlMenu').style.zIndex-1; }
// ... original menu drawing code resumes here }
3. That's it...
My example has not been thoroughly tested in terms of "which style elements are required?", "how would this behave in FireFox?", etc. However, for my situation, this did exactly what I needed. I'm not even sure if the select box behavior IS an issue in FireFox, so this solution could potentially be workable for that browser, since you can just have it ignore the iFrame altogether. |
|
[reply]
|
06/23/05 07:16 AM EST posted by nate web |
|
I can confirm that this solution fizzles out in Firefox. I believe that all you need to do to modify it so that it does work in FF is to set the background-color property on either the DHTML pane or the iFrame. Once you do that you don't see through the iFrame's transparency. There might be a way to turn off the iFrame transparency though...
I cranked out a complete html markup in order to see what was really going on and I discovered a few things. First, here's the entire markup I used:
<html> <head> <title>DHTML Test</title> <script> function toggleWinder(oTarget) { oDHTML = document.getElementById("DHTMLDiv"); oMatte = document.getElementById("MatteFrame"); oMatte.style.zIndex = oDHTML.style.zIndex - 1; if( oDHTML.style.display == "none" ) { oDHTML.style.top = oTarget.offsetTop + 10; oDHTML.style.left = oTarget.offsetLeft + 10; oDHTML.style.display = "block"; cloneStyles(oMatte,oDHTML); } else { oDHTML.style.display = "none"; oMatte.style.display = "none"; } } function cloneStyles(oClone, oOrig) { oClone.style.top = oOrig.style.top; oClone.style.left = oOrig.style.left; oClone.style.height = oOrig.style.height; oClone.style.width = oOrig.style.width; oClone.style.display = "block"; } </script> </head> <body> <form name="TestForm" action="#" method="post"> <a href="#" onclick="toggleWinder(this);">Toggle DHTML Menu</a><br> <select name="SelectBox"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> </select> </form>
<iframe id="MatteFrame" style="display: none; position: absolute; border: 0px;"></iframe> <div id="DHTMLDiv" style="display: none; position:absolute; height: 200px; width: 150px; border: 1px #000 solid; background-color: #fff; z-index: 99;"> Here is a bunch of content that you can't see until you click on the toggle link. </div>
</body> </html>
Now, a few things became apparent to me.
- The order of the iFrame before the DHTML div already establishes the z-index for both elements so you don't have to set them. I just happen to like putting my dynamically positioned elements at the bottom of the page because that's how I have always seen it done. This is probably why.
- In trying to tidy this up I created a style tag in the head and then use id's to set the styles for the div and iframe. When I did this a few things quirked out. In IE the iFrame "matte" would not sit behind the div and instead "popped" to the right of it. In FF the DHTML div didn't work on the first click. It took two clicks before the display property was set to block.
- You can see how I prefer to use one div to handle all the dynamic content whereas I think you were planning on putting multiple dynamic elements and iFrame mattes on a single page. I think I could see the need for either depending on the situation and, since I'm not that experienced in .NET, maybe there's something about .NET that makes it more difficult to reuse HTML elements.
All in all I think I like this new method Jerry. Thanks for the heads-up. I'll file this away in my snip-its catalog in case I ever get the chance to code again. Please feel free to tear up that sample code and suggest improvements or point out redundancies. |
|
[reply]
|
06/23/05 07:21 AM EST posted by nate web |
|
| Oh right. I meant to mention that even though the iFrame and the div are at the bottom of the page (and are then assigned incremental z-indexes), I specified the z-index for the div and dynamically set the z-index for the iFrame in case someone decides to place more than one set of dynamic div/iFrame pairs. |
|
Note: Only registered ShinyDonkey.com users
can post images. Only administrators can delete images.