CSSFriendly adapters, IE6 and dropdown lists that want to display on top

October 2, 2008

I have added CSSFriendly adapters to my ASP.NET web solution. CSSFriendly adapters allow you to apply style sheet classes to almost every display element on the page. Once understood, it’s far easier to use than tables for screen layout, and it unclutters the page, removing a lot of unnecessary tags. If you decide to move elements around on the page, it also becomes easier, as you can generally figure out where the data that you want to move starts and finishes, and you don’t don’t spend as much time trying to tweak nasty html tables.

Of course, Microsoft were quite late to the game with stylesheets. Most of their controls still use tables internally, and these don’t have stylesheet classes hanging off them, so there’s very little that you can do to style with the standard web controls. That was until the CSSFriendly adapters.

CSSFriendly adapters override the base controls and replace the contents of the controls with CSS friendly tags. These tags have style sheet classes attached to them. The controls are then able to be positioned using the float, clear and display styles, and the heights and widths can be set by style instead of within the elements themselves. The CSSFriendly adapters can also add javascript code to controls that need it. The drop down list is one of those controls.

In IE6, the drop down list (which is really a SELECT tag) sits in front of almost every other control, regardless of z-order. So if you have a menu that drops down over the top of a drop down list control, the menu will appear behind the control. This is a known issue, and it has a work around. Basically, when using IE6, you position an IFRAME over the top of the drop down, which hides the drop down list, and then the menu will appear in front of the drop down list. Works beautifully….when it works.

I have a two level menu. Click on the top level, and it expands the second level vertically down on the page. On my web site, this clashes with the drop down list. That is, the drop down list appeared in front of the menu item. Highly undesireable.

I downloaded the latest CSSFriendly adapter project from the codeplex site, http://www.codeplex.com/cssfriendly, and I added the source code to my project. It turns out that it does implement the IFRAME hack to get around the drop down list problem. So why is this not working with my site?

Next I ran up the project, got to the offending page, ran the IE Developer Toolbar, and selected the menu item that was clashing. I expanded the elements and found the IFRAME. Clicked on the IFRAME. When the menu is expanded, the IFRAME appears in the middle of nowhere. So I inspected the attributes. It turns out that the IFRAME is absolutely positioned, which means that is doesn’t follow the conventional flow of the page. But for some reason, it sits not underneath, but next to the menu item. Well that’s odd.

So I edited the attributes for the IFRAME in IE Dev Toolbar. Set it’s left attribute to -1px, then hit enter. It worked. The menu item was now sitting on top of the drop down list. Yay!

So I went into the CSSFriendly adapter source code, Javascript folder. Edited the MenuAdapter.js file, and where the iframe is being created in code in the SetHover__AspNetMenu() method, I added the following line of code:

iFrameFormElementMask.style.left = "-1px";

Recompiled, ran the project, and the problem has now gone away.

So that code section looks like this:

if (isPreIE7 && ((typeof(items[k].iFrameFormElementMask) == "undefined")
|| (items[k].iFrameFormElementMask == null)))
var iFrameFormElementMask = document.createElement("IFRAME");
iFrameFormElementMask.scrolling= "no";
iFrameFormElementMask.src = "javascript:false;";
iFrameFormElementMask.frameBorder = 0;
iFrameFormElementMask.style.display = "none";
iFrameFormElementMask.style.left = "-1px";
iFrameFormElementMask.style.position = "absolute";
iFrameFormElementMask.style.filter =

iFrameFormElementMask.style.zIndex = -1;
items[k].insertBefore(iFrameFormElementMask, items[k].firstChild);
items[k].iFrameFormElementMask = iFrameFormElementMask;