I found a "clean" way to workaround this behaviour using the CSS Adapters, and because I hope it could help many people: there is the step by step procedure:
The main idea: the IFRAME tag is some kind of hybrid component, half windowed and half windowless.
Because he is windowless (since IE5.5) h can be drawn under a DIV. And because he is also a little bit windowed: he will overlap the SELECT tags.
My MenuAdapter.cs: (I just added lines 143 to 146)
using System;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace CSSFriendly
{
public class MenuAdapter : System.Web.UI.WebControls.Adapters.MenuAdapter
{
public MenuAdapter()
{
//
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
RegisterScripts();
}
private void RegisterScripts()
{
Utility.RegisterScripts(Page);
Page.ClientScript.RegisterClientScriptInclude(GetType(), GetType().ToString(), Page.ResolveUrl("~/js/MenuAdapter.js"));
}
protected override void RenderBeginTag(HtmlTextWriter writer)
{
if ((Control != null) && (Control.Attributes["CssSelectorClass"] != null) && (Control.Attributes["CssSelectorClass"].Length > 0))
{
writer.WriteLine();
writer.WriteBeginTag("div");
writer.WriteAttribute("class", Control.Attributes["CssSelectorClass"]);
writer.Write(HtmlTextWriter.TagRightChar);
writer.Indent++;
}
writer.WriteLine();
writer.WriteBeginTag("div");
writer.WriteAttribute("class", "AspNet-Menu-" + Control.Orientation.ToString());
writer.Write(HtmlTextWriter.TagRightChar);
}
protected override void RenderEndTag(HtmlTextWriter writer)
{
writer.WriteEndTag("div");
if ((Control != null) && (Control.Attributes["CssSelectorClass"] != null) && (Control.Attributes["CssSelectorClass"].Length > 0))
{
writer.Indent--;
writer.WriteLine();
writer.WriteEndTag("div");
}
writer.WriteLine();
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Indent++;
BuildItems(Control.Items, true, writer);
writer.Indent--;
writer.WriteLine();
}
private void BuildItems(MenuItemCollection items, bool isRoot, HtmlTextWriter writer)
{
if (items.Count > 0)
{
writer.WriteLine();
writer.WriteBeginTag("ul");
if (isRoot)
{
writer.WriteAttribute("class", "AspNet-Menu");
}
writer.Write(HtmlTextWriter.TagRightChar);
writer.Indent++;
foreach (MenuItem item in items)
{
BuildItem(item, writer);
}
writer.Indent--;
writer.WriteLine();
writer.WriteEndTag("ul");
}
}
private void BuildItem(MenuItem item, HtmlTextWriter writer)
{
Menu menu = Control as Menu;
if ((menu != null) && (item != null) && (item.Enabled) && (writer != null))
{
writer.WriteLine();
writer.WriteBeginTag("li");
writer.WriteAttribute("class", item.ChildItems.Count > 0 ? "AspNet-Menu-WithChildren" : "AspNet-Menu-Leaf");
writer.Write(HtmlTextWriter.TagRightChar);
writer.Indent++;
writer.WriteLine();
if (item.NavigateUrl.Length > 0)
{
writer.WriteBeginTag("a");
writer.WriteAttribute("href", Page.ResolveUrl(item.NavigateUrl));
writer.WriteAttribute("class", "AspNet-Menu-Link");
if (item.Target.Length > 0)
{
writer.WriteAttribute("target", item.Target);
}
if (item.ToolTip.Length > 0)
{
writer.WriteAttribute("title", item.ToolTip);
}
else if (menu.ToolTip.Length > 0)
{
writer.WriteAttribute("title", menu.ToolTip);
}
writer.Write(HtmlTextWriter.TagRightChar);
writer.Indent++;
writer.WriteLine();
}
else
{
writer.WriteBeginTag("span");
writer.WriteAttribute("class", "AspNet-Menu-NonLink");
writer.Write(HtmlTextWriter.TagRightChar);
writer.Indent++;
writer.WriteLine();
}
if (item.ImageUrl.Length > 0)
{
writer.WriteBeginTag("img");
writer.WriteAttribute("src", Page.ResolveUrl(item.ImageUrl));
writer.WriteAttribute("alt", item.ToolTip.Length > 0 ? item.ToolTip : (menu.ToolTip.Length > 0 ? menu.ToolTip : item.Text));
writer.Write(HtmlTextWriter.SelfClosingTagEnd);
}
//This line is to solve the problem with the
//divs unable to overlap select boxes in versions of IE previous to IE7
writer.Write("<!--[if lt IE 7]><iframe></iframe><![endif]-->");
writer.WriteLine();
writer.Write(item.Text);
if (item.NavigateUrl.Length > 0)
{
writer.Indent--;
writer.WriteLine();
writer.WriteEndTag("a");
}
else
{
writer.Indent--;
writer.WriteLine();
writer.WriteEndTag("span");
}
if ((item.ChildItems != null) && (item.ChildItems.Count > 0))
{
BuildItems(item.ChildItems, false, writer);
}
writer.Indent--;
writer.WriteLine();
writer.WriteEndTag("li");
}
}
}
}
And then in my stylesheet menuStyle.css I added the following rules:
/* This format the iframes to allow the menu items to overlap select boxes in IE versions previous to IE7 */
a.AspNet-Menu-Link iframe, span.AspNet-Menu-NonLink iframe
{
position: absolute;
/* top, right, left and bottom parameters are fixed depending on the
padding value of the ".AspNet-Menu-Link a, .AspNet-Menu-NonLink span" rule*/
top: -4px;
right: -2px;
bottom: -4px;
left: -8px;
z-index: -1;
filter: mask();
width: 100%;
height: 25px; /*size of the background image (22px) + 3px to hide the select object even through the tiny spaces between menu items*/
}
Because the <iframe></iframe> is surrounded withe IE specific conditional comments they will be ignored by other browsers.
Another solution could have be to make a specific MenuAdapter for IE6 and determining wich one to use on the .browser file.
landhar
Member
16 Points
9 Posts
Using the CSS Adapters to make a dropdown menu that overlaps select tags
Oct 26, 2007 10:42 AM|LINK
In IE 6, there are some elements like SELECT that always appear in front of all other elements no matter what z-index you apply to them.
Here is a screenshot of happens in IE6 and IE5.5 when a CSS dropdown menu crosses the way of a <select> tag:
More information about this behaviour here.I found a "clean" way to workaround this behaviour using the CSS Adapters, and because I hope it could help many people: there is the step by step procedure:
The main idea: the IFRAME tag is some kind of hybrid component, half windowed and half windowless.
Because he is windowless (since IE5.5) h can be drawn under a DIV. And because he is also a little bit windowed: he will overlap the SELECT tags.
My MenuAdapter.cs: (I just added lines 143 to 146)
using System; using System.IO; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; namespace CSSFriendly { public class MenuAdapter : System.Web.UI.WebControls.Adapters.MenuAdapter { public MenuAdapter() { // } protected override void OnInit(EventArgs e) { base.OnInit(e); RegisterScripts(); } private void RegisterScripts() { Utility.RegisterScripts(Page); Page.ClientScript.RegisterClientScriptInclude(GetType(), GetType().ToString(), Page.ResolveUrl("~/js/MenuAdapter.js")); } protected override void RenderBeginTag(HtmlTextWriter writer) { if ((Control != null) && (Control.Attributes["CssSelectorClass"] != null) && (Control.Attributes["CssSelectorClass"].Length > 0)) { writer.WriteLine(); writer.WriteBeginTag("div"); writer.WriteAttribute("class", Control.Attributes["CssSelectorClass"]); writer.Write(HtmlTextWriter.TagRightChar); writer.Indent++; } writer.WriteLine(); writer.WriteBeginTag("div"); writer.WriteAttribute("class", "AspNet-Menu-" + Control.Orientation.ToString()); writer.Write(HtmlTextWriter.TagRightChar); } protected override void RenderEndTag(HtmlTextWriter writer) { writer.WriteEndTag("div"); if ((Control != null) && (Control.Attributes["CssSelectorClass"] != null) && (Control.Attributes["CssSelectorClass"].Length > 0)) { writer.Indent--; writer.WriteLine(); writer.WriteEndTag("div"); } writer.WriteLine(); } protected override void RenderContents(HtmlTextWriter writer) { writer.Indent++; BuildItems(Control.Items, true, writer); writer.Indent--; writer.WriteLine(); } private void BuildItems(MenuItemCollection items, bool isRoot, HtmlTextWriter writer) { if (items.Count > 0) { writer.WriteLine(); writer.WriteBeginTag("ul"); if (isRoot) { writer.WriteAttribute("class", "AspNet-Menu"); } writer.Write(HtmlTextWriter.TagRightChar); writer.Indent++; foreach (MenuItem item in items) { BuildItem(item, writer); } writer.Indent--; writer.WriteLine(); writer.WriteEndTag("ul"); } } private void BuildItem(MenuItem item, HtmlTextWriter writer) { Menu menu = Control as Menu; if ((menu != null) && (item != null) && (item.Enabled) && (writer != null)) { writer.WriteLine(); writer.WriteBeginTag("li"); writer.WriteAttribute("class", item.ChildItems.Count > 0 ? "AspNet-Menu-WithChildren" : "AspNet-Menu-Leaf"); writer.Write(HtmlTextWriter.TagRightChar); writer.Indent++; writer.WriteLine(); if (item.NavigateUrl.Length > 0) { writer.WriteBeginTag("a"); writer.WriteAttribute("href", Page.ResolveUrl(item.NavigateUrl)); writer.WriteAttribute("class", "AspNet-Menu-Link"); if (item.Target.Length > 0) { writer.WriteAttribute("target", item.Target); } if (item.ToolTip.Length > 0) { writer.WriteAttribute("title", item.ToolTip); } else if (menu.ToolTip.Length > 0) { writer.WriteAttribute("title", menu.ToolTip); } writer.Write(HtmlTextWriter.TagRightChar); writer.Indent++; writer.WriteLine(); } else { writer.WriteBeginTag("span"); writer.WriteAttribute("class", "AspNet-Menu-NonLink"); writer.Write(HtmlTextWriter.TagRightChar); writer.Indent++; writer.WriteLine(); } if (item.ImageUrl.Length > 0) { writer.WriteBeginTag("img"); writer.WriteAttribute("src", Page.ResolveUrl(item.ImageUrl)); writer.WriteAttribute("alt", item.ToolTip.Length > 0 ? item.ToolTip : (menu.ToolTip.Length > 0 ? menu.ToolTip : item.Text)); writer.Write(HtmlTextWriter.SelfClosingTagEnd); } //This line is to solve the problem with the //divs unable to overlap select boxes in versions of IE previous to IE7 writer.Write("<!--[if lt IE 7]><iframe></iframe><![endif]-->"); writer.WriteLine(); writer.Write(item.Text); if (item.NavigateUrl.Length > 0) { writer.Indent--; writer.WriteLine(); writer.WriteEndTag("a"); } else { writer.Indent--; writer.WriteLine(); writer.WriteEndTag("span"); } if ((item.ChildItems != null) && (item.ChildItems.Count > 0)) { BuildItems(item.ChildItems, false, writer); } writer.Indent--; writer.WriteLine(); writer.WriteEndTag("li"); } } } }And then in my stylesheet menuStyle.css I added the following rules:
/* This format the iframes to allow the menu items to overlap select boxes in IE versions previous to IE7 */
a.AspNet-Menu-Link iframe, span.AspNet-Menu-NonLink iframe
{
position: absolute;
/* top, right, left and bottom parameters are fixed depending on the
padding value of the ".AspNet-Menu-Link a, .AspNet-Menu-NonLink span" rule*/
top: -4px;
right: -2px;
bottom: -4px;
left: -8px;
z-index: -1;
filter: mask();
width: 100%;
height: 25px; /*size of the background image (22px) + 3px to hide the select object even through the tiny spaces between menu items*/
}
The html generated will look like this:
<div class="PrettyMenu">
<div class="AspNet-Menu-Horizontal">
<ul class="AspNet-Menu">
<li class="AspNet-Menu-WithChildren">
<span class="AspNet-Menu-NonLink">
<!--[if lte IE 6.5]><iframe></iframe><![endif]-->
Navigation
</span>
<ul>
<li class="AspNet-Menu-WithChildren">
<a href="/AAP_Website/Tasklist.aspx" class="AspNet-Menu-Link">
<!--[if lte IE 6.5]><iframe></iframe><![endif]-->
Go to Task List
</a>
<ul>
<li class="AspNet-Menu-Leaf">
<a href="/AAP_Website/S_Masterfile/#" class="AspNet-Menu-Link">
<!--[if lte IE 6.5]><iframe></iframe><![endif]-->
test
</a>
</li>
</ul>
</li>
[...]
</div>
Because the <iframe></iframe> is surrounded withe IE specific conditional comments they will be ignored by other browsers.
Another solution could have be to make a specific MenuAdapter for IE6 and determining wich one to use on the .browser file.
As you can see, the issue is solved now:
I found the idea of using iframes here: http://shepherdweb.com/2007/02/14/z-index-ignored-for-select-element-in-ie-6-workaround/
Hope it helps !
css adapters ie6 dropdown menu select tag dropdownlist z-index