CSSing gone wild - styled select boxes
Tuesday, 22. April 2008, 13:22:00
The following CSS/JavaScript isn't meant for my.opera.com this time, but for for experimental and discussion purposes.As some of you CSS magicians may know, the IE isn't able to style select boxes, but instead using the sources of Windows itself. Now your customer might insist that that box has to look stylish, so you'll have to find a way to create a select box that looks all the same on all current browsers.
It takes a bit of CSS and JavaScript to get this job done, but as you can see in the screenshot to the right, it is possible (with some flaws and downsides, that I'll explain later).
I'll cut the code a liitle bit to the relevant pieces, but most of you will still get the idea. If you don't, just ask.
HTML
Let's start with the HTML-part. I create a form, include a 2 input fields (1 showing the text for the visitor, 1 holding the value we need to submit), an image for the dropdown button and the list of elements I want to select from:
<div id="superlayer"></div>
<form action="dropform.htm">
<table border="0" cellpadding="0" cellspacing="4">
<tr>
<td align="right">dropform:</td>
<td style="position:absolute; top: 10px; left: 75px; z-index: 9999">
<div class="dropborder" onclick="OpenDropBox('droplist1')">
<input name="display1" onfocus="blur();" id="dropform1" class="input drop" type="text" size="30" maxlength="30" value="select" />
<input name="value1" type="hidden" id="dropvalue1" value="" />
<img src="dropform.gif" style="position:relative; top:0px; right:0px;" />
</div>
<div id="droplist1" class="droplist">
<div class="dropelement" onclick="ChangeDropFormAndClose('dropform1','dropvalue1','droplist1','select', '')">select</div>
<div class="dropelement" onclick="ChangeDropFormAndClose('dropform1','dropvalue1','droplist1','element1', '1')">element1</div>
<div class="dropelement" onclick="ChangeDropFormAndClose('dropform1','dropvalue1','droplist1','element2', '2')">element2</div>
<div class="dropelement" onclick="ChangeDropFormAndClose('dropform1','dropvalue1','droplist1','element3', '3')">element3</div>
</div>
</td>
</tr>
..
explanations:
Using a table layout as base wasn't on purpose, it was just the fastest layout with forms I had at hand. As you can see I set the TD for the dropform to z-index:9999. That's for IE, to make sure that the DIV "superlayer" will not be above the dropdown box, neither under the form itself. We later use that layer to close open elements (like a onClickOutside). The onFocus-JavaScript on the visible text field shall prevent editing by the user. The value contains the preselected text, the hidden field the preselected value of that text.
CSS
The CSS is pretty easy and fast forward. The only things to mention are the superlayer (z-index:9999) and the dropelement-class (z-index:10000). Furthermore the superlayer contains a transparent GIF as background, fixing a strange behaviour of IE (if a DIV is transparent and without content, IE doesn't recognize events on it):
input,select { padding: 0; margin:0; height: 17px; width: 120px; }
img { padding: 0; margin: 0; }
#superlayer { position: fixed; top: -500px; left: -500px; width: 4000px; height: 3000px; display: none; z-index: 9999; background: transparent url("superlayer.gif"); }
.input { border: 1px solid black; }
.drop { border:none; width: 100px; position: relative; top:-4px; left:0px; }
.dropborder { border: 1px solid black; height:18px; padding:0px; background: #fff;position:relative; top: 0px; left:0px; }
.droplist { display: none; background: #ffffff; border: 1px solid black; position: relative; top: 0px; left: 0px; z-index: 10000 !important; }
.dropelement { background: #ffffff; z-index: 10000 !important; }
.dropelement:hover { background: #0000ff; color: #ffffff; }
JavaScript
So far, so good. Now we get into action, by using some neat JavaScript:
<script type="text/javascript">
<!--
document.onclick=checkIfOutside;
function checkIfOutside(clickedElement)
{
var target = (clickedElement && clickedElement.target) || (event && event.srcElement);
var hideLayer = document.getElementById('superlayer');
var hideObjects = new Array();
hideObjects[0] = "superlayer";
hideObjects[1] = "droplist1";
if(target==hideLayer) {
for (x in hideObjects)
{
document.getElementById(hideObjects[x]).style.display='none';
}
}
}
function OpenDropBox(dropList)
{
document.getElementById(dropList).style.display='block';
document.getElementById("superlayer").style.display='block';
}
function ChangeDropFormAndClose(displayField,valueField,dropList,displayValue,valueValue)
{
document.getElementById(displayField).value=displayValue;
document.getElementById(valueField).value=valueValue;
document.getElementById(dropList).style.display='none';
document.getElementById("superlayer").style.display='none';
}
//-->
</script>explanations:
The function OpenDropBox() is easy to understand: If the user clicks our DIV for the text and dropdown-image we display the droplist he just tried to open and the superlayer.
ChangeDropFormAndClose() now puts the values into their fields (the text field and the hidden field) and "throws away" both the dropdown box and the superlayer.
The cool trick now comes with document.onclick=checkIfOutside and the function checkIfOutside(). The first makes sure that every click gets checked and the function now closes all objects I registered in an array, including the superlayer, when the superlayer gets clicked.
The goodWith this little bit of CSS and JavaScript it is possible to create select boxes that look (almost) exactly the same on Opera, Firefox and IE (tested with IE7). This solution gives you the possibility to edit the look and feel of the dropdown-box.
The bad
onFocus="blur();" doesn't seem work on Opera. This means, that a user could enter a different text (but he can't change the submitted value by this). So it is not a save solution!
Furthermore this type of select-box field can't be used when you have to make sure that the page is fully accessible, as the dropdown values are by no means connected to the text-field.