Introduction
The problem I want to discuss in this article appears only in Internet Explorer. When an absolutely positioned layer (div
) is overlaid with a dropdown or some ActiveX component, the z-index style sheet property does not work and the layer shows under such an object.
Web developers very often use absolutely positioned layers to make navigation elements like drop-down menus, show messages, and even for making-up of whole pages. So, are there any workarounds?
Method 1: Hide all dropdowns on the page
The idea of the first method is simple – hide all the dropdowns on the page. If there won’t be any dropdowns, there is no problem. Yes, it is right, but it does not apply to ActiveX components.
To hide all dropdowns, we can use client script code. For instance, using JavaScript, we can find all the dropdowns on the form by looping through a list of all elements:
for (f = 0; f < document.forms.length; f++)
{
var elements = document.forms[f].elements;
for (e = 0; e < elements.length; e++)
{
if (elements[e].type == "select-one")
{
elements[e].style.display = 'none';
}
}
}
The first loop is for the forms array, and the second, for each element on a certain form. Also, for each element, we check the type and if the type equals “select-one”, we change the display
property to “none
” so the element will be hidden. Finally, add a block to show the layer and we get the function ShowLayer()
which we can use to display a layer on the page:
function ShowLayer() {
for (f = 0; f < document.forms.length; f++)
{
var elements = document.forms[f].elements;
for (e = 0; e < elements.length; e++)
{
if (elements[e].type == "select-one")
{
elements[e].style.display = 'none';
}
}
}
var layer = document.getElementById('layer');
layer.style.display = 'block';
}
To hide a layer and show dropdowns again, we need to do similar work, but in a reverse fashion. This logic will be encapsulated in the function HideLayer()
:
function HideLayer() {
for (f = 0; f < document.forms.length; f++)
{
var elements = document.forms[f].elements;
for (e = 0; e < elements.length; e++)
{
if (elements[e].type == "select-one")
{
elements[e].style.display = 'block';
}
}
}
var layer = document.getElementById('layer');
layer.style.display = 'none';
}
In my opinion, the main disadvantage of such a solution is changing the user interface when the script hides all the dropdowns, so the user could become confused. In addition, using such an approach, we can hide the dropdowns which do not overlay the layer but have an important functionality which the user can use while the layer is shown. Let’s see what we have in method #2.
Method 2: Using IFRAME
The idea of this method is using an IFRAME
. This element overlays all other elements of the form and also ActiveX components. But the beauty of this method is that we can set the z-index for it! Thus, we can make a dividing layer between dropdowns and absolutely position the layer. Let’s take a look at this simple example (instead of three dots, I placed a form with a dropdown which I used in method one):
<html>
<head>
<title>Method Two</title>
<style>
#layer {
position: absolute;
top: 10px;
left: 100px;
width: 220px;
height: 100px;
border: 1px solid black;
background-color: #e4e4e4;
padding: 10px;
z-index: 11;
}
#iframe {
position: absolute;
top: 10px;
left: 100px;
width: 222px;
height: 102px;
z-index: 10;
}
</style>
</head>
<body>
<form>
<iframe id="iframe" frameborder="0"></iframe>
<div id="layer">
This is absolutely positioned layer.
</div>
...
</form>
</body>
</html>
If you open this HTML page in IE, you will see that the dropdown will be under the layer. This is because I placed the third layer between the form elements like the dropdown and the layer. I set its z-index to 10, whereas for the layer, I set it 11. I also set the width and height to be exactly like the absolutely positioned layer so it’s hidden for the user and just does the work to hide everything under it.
Let’s change the functions from the example in method 1 to work with the IFRAME
:
function ShowLayer() {
var layer = document.getElementById('layer');
layer.style.display = 'block';
var iframe = document.getElementById('iframe');
iframe.style.display = 'block';
iframe.style.width = layer.offsetWidth;
iframe.style.height = layer.offsetHeight;
iframe.style.left = layer.offsetLeft;
iframe.style.top = layer.offsetTop;
}
function HideLayer() {
var iframe = document.getElementById('iframe');
iframe.style.display = 'none';
var layer = document.getElementById('layer');
layer.style.display = 'none';
}
The ShowLayer
function sets the width, height, left, and top values for the IFRAME
depending on the layer properties. We do not need to set those values in the style sheet for a dropdown layer.
Method 3: Replacing SELECTs with SPAN
Volkan.ozcelik posted an interesting method in his article Modal Dialog – enhanced. He proposed to use a replacement to avoid "bleeding". Before a new layer is opened, a JavaScript function searches the whole HTML file and replaces all dropdowns with a SPAN
tag. Using CSS, we can make the SPAN
look almost like a SELECT
so the form view will be changed a little and it won’t annoy users like method 1 when we hide all dropdowns.
Conclusion
I do not see any advantages in the first method. It does not help with ActiveX components and annoys users when the JavaScript hides all the dropdowns in the page. The second method helps with dropdowns and ActiveX components and doesn’t change the SELECT
s. The third method helps only with dropdowns and changes the view of the form a little. Also, users cannot use the form while the layer is shown because all SELECT
s will be replaced with SPAN
s.
The first two method examples can be found in the source files. Regarding method 3 example, refer to the Modal Dialog – enhanced article please.