Firefox/Mozilla flicker-free drop-down
1090 days ago by Peter Asquith —
Background
This article was inspired by Jason Kottke who recently installed a CSS- and DOM-based drop-down list on his homepage.
The approach taken is that the list, a <ul>,
is initially declared with display: none; in CSS.
A block element (that represents the ‘landing zone’)
has a DOM call attached to its onmouseover
event that changes the display attribute of the
<ul>’s style to block.
The <ul>, in turn, has its
onmouseout attribute set to return the
style’s display attribute back to
none.
The problem
Unfortunately, in Firefox for Windows the drop-down suffers from wild flickering as you move the mouse down the list. This is not ideal and it got me working on a solution …
After a spell of tinkering with my take on Jason’s drop-down list, I established that the problem wasn’t only confined to Firefox but to Mozilla 1.7.7 as well — so it’s a fair bet that it’s a problem on all Gecko-based browsers, for Windows at least (it isn’t a problem on Firefox for BeOS).
The problem appears to be related to the way Gecko
handles the onmouseout event. As the mouse is
moved down the list the onmouseout event is
called for the <ul> even though the mouse
hasn’t left the confines of the
<ul>. The effect is that the drop-down is
briefly hidden then re-shown — hence the flicker.
It’s possible it has something to do with the mouse
entering the area taken up by each <li>
that causes the onmouseout to trigger. In any
case there is a solution:
The solution
The answer is to take advantage of the browsers’
innate ability to trigger the showing/hiding of the list
via CSS rather than the DOM. This is achieved by using the
:hover pseudo-class on a containing block
element.
Suppose the containing block has an id of
dropdown and the <ul> has an
id of droplist:
<div id="dropdown">
<span>My dropdown list</span>
<ul id="droplist">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
We can cause the droplist to appear by setting the following CSS rule:
#dropdown:hover droplist {
display: block;
}
This will reveal the list as the mouse moves over the dropdown element and will remain showing as long as the mouse remains over (the now enlarged) dropdown.
However, there’s just a tiny problem with this
scheme! Internet Explorer, bless it’s little cotton
socks, doesn’t know what to make of :hover
on any element other than <a>, so it
ignores it and the drop-down does not drop
down.
After much preamble, then, we’re at the heart of
the solution. The idea is to use the onmouseover and
onmouseout events only if there’s
no other choice. This means that browsers that know how
to :hover can do their native thing and
those that don’t can use the DOM.
So, how do we know if the browser we’re dealing
can play dice? The answer is a DOM routine that is called
from the page’s onload attribute
and a global variable to keep track of whether, or not, the
browser knows how to :hover —
<script type="text/javascript">
//<!--
//<![CDATA[
var g_bH = false;
function init(p_strId) {
g_bH = false;
var l_E = document.getElementById(p_strId);
if(l_E && document.defaultView) {
if(document.defaultView.⇒
getComputedStyle(l_E, 'hover')) {
g_bH = true;
}
}
l_E = null;
}
//]]>
//-->
</script>
(The ⇒ signifies that the line would, but for display considerations, continue on the same line.)
The script shown here would be placed in the <head>
block of the page, but could just as well be included from a linked
JavaScript file.
The page’s <body> would read:
<body onload="init('dropdown');">
The code fragment if(document.defaultView.getComputedStyle(l_E, 'hover')) {
relies on two things: firstly that the element’s
:hover attribute appears in the CSS
#dropdown:hover droplist {...}
in this case and, secondly, that the browser implements
the document.defaultView.getComputedStyle()
directive (which IE cannot).
If the :hover declaration is in the CSS
and the browser understands then we set a global variable
g_bH to record the result. We could call a
function every time we wanted to know, but it’s
more efficient to set a global since the CSS entry and
the browser’s capability won’t change
underneath us.
Now it’s just a simple matter of adding the onmouseover
and onmouseout attributes to the dropdown <div>:
<div id="dropdown"
onmouseout="if(!g_bH){document.⇒
getElementById('droplist').style.display='none';}"
onmouseover="if(!g_bH){document.⇒
getElementById('droplist').style.display='block';}">
Now, when the mouse hovers over the dropdown <div>
either the browser will show the droplist <ul>
because it is responding the the CSS rule, or set the
droplist’s style.display if if can not. When
the mouse leaves the dropdown again the CSS rule will be
envoked if the variable g_bH is false, or the style.display
will be set if not.
See the accompanying example for details of how this could be implemented. Feel free to use this implementation if you find it of any use.
The weathered look
1416 days ago by Peter Asquith —
Background
The inspiration for this article came from Cameron Moll’s That Wicked Worn Look series, and from a reader’s enquiry about how I used Corel PHOTO-PAINT’s Weather effect to age an image.
Implementation
The starting point I usually take when creating graphics for the Web is to create a vector image in CorelDRAW.

By trial and error I’ve found it best to scale the image by 400%, say, before exporting it to PHOTO-PAINT. Once there I scale it back to its original size. This gives a much smoother result than importing CorelDRAW images directly.
Next, in PHOTO-PAINT, I pretty much follow Cameron Moll's first tutorial in order to create the creases and worn edges.

Once happy with the edges, I apply the PHOTO-PAINT’s Weather effect (Effects | Creative | Weather). With a bit of experimentation I've found that a good result comes from applying the effect twice:
- Apply the effect with an angle of say 80 degrees with a strength of 15, size of 1
and a randomize value of, say, 165.

- The apply it again at an angle of 90 degrees, with a higher strength, say 85,
again with a size of 1 and a randomize value of 194, for example.

Note: play around with the Randomize button until you get a scratch pattern that looks natural for each application of the effect.
Perhaps the key thing I’ve discovered is to have the two angles of weathering - it somehow looks more convincing than having all the scratches going in the same direction.

Stripey tables revisited
1521 days ago by Peter Asquith —
Background
This is an update of an earlier article, which was inspired by David F Miller’s Zebra tables article for A List Apart.
In order to make data tables easier to read it’s useful to ‘stripe’ every other line with a subtle background colour so the eye can track easily across each column for a given row.
The JavaScript function described below is the one I use to stripe the Waxheads’ results table.
My solution* is a short function that sets the class of
either the odd or even rows of a table. Thus, you can have full control
over the guide stripes’ appearance via the page’s stylesheet.
As in David’s example, if the row already has a class
defined then the function won’t replace it with the guide stripe
class. Unlike David’s example, the row is updated
whether, or not, it has a background colour set as I feel the background
colour of the row should be being set via either the row’s or the
table’s style.
Implementation
Striping a table is straightforward. Firstly, include the javascript
in a <script> block. Alternatively, and better if you’re
going to stripe tables on more than one page, load the JavaScript from an
external file using:
<script language="JavaScript" type="text/javascript" src="myJavaScript.js">
Next, identify your table with an id attribute. For instance:
<table id="myTable" summary="Stripey table">
Now, either directly from a <script> block within the
page, or from the onload attribute in the <body>
tag, call, for example:
tableStripe('myTable', 'myStripeClass', true)
(So, from the onload attribute it would be:
<body onload="javascript:tableStripe('myTable', 'myStripeClass', true)">
The parameters passed to tableStripe() are, in order, the
id of the table, the class name to apply to the row and, finally, a
Boolean to determine whether to apply the class to the odd (true) or even
(false) rows.
The JavaScript source is fairly succinct:
function tableStripe(p_strId, p_strClass, p_bOdd) {
var l_Table = document.getElementById(p_strId);
if(l_Table.rows) {
for(var l_iIndex = (p_bOdd ? 0 : 1);⇒
l_iIndex <. l_Table.rows.length;⇒
l_iIndex += 2) {
var l_Row = l_Table.rows.item(l_iIndex);
if(!hasClass(l_Row)) {
l_Row.className = p_strClass;
}
}
}
}
(The ⇒ signifies that the line would, but for display considerations, continue on the same line.)
Handily, the DOM provides a rows attribute in the
table class, which is a list of all the table’s row
elements in the order in which they appear. We simply traverse the
list and, depending on whether we want to apply our class to odd or
even rows and, if the row hasn’t already got a class attribute, we
set the row’s className attribute to our supplied class
name.
The rows are indexed from zero. We set our starting index to zero for an odd start and one for an even start and then traverse the list in steps of two. If the current row doesn᾿already have a class we apply our own.
For a working example, view the Waxheads ’ results page’s source code.
This article is a work in progress. I’ve noted that both this technique, and David’s don’t work for IE5.01/Win, I will look to see if there’s a work-around that can be applied in that case - let me know if you find other issues with other browsers.
I’m grateful to my friend Nigel Caughey for entering into a game of ‘optimisation tennis’ with me that transformed my initial algorithm into the one shown here.
In addition, I’ve borrowed David’s hasClass()
function, for the IE compatibility reasons he describes in his comment:
// this function is needed to work around
// a bug in IE related to element attributes
function hasClass(p_Element) {
var l_bRet = false;
if (p_Element.getAttributeNode("class") != null) {
l_bRet = ⇒
p_Element.getAttributeNode("class").value;
}
return l_bRet;
}
For more information about the DOM see Document Object Model (DOM) Level 2 HTML Specification
Stripey tables
1527 days ago by Peter Asquith —
Background
This article was inspired by David F Miller’s Zebra tables article at A List Apart.
I’ve created a JavaScript function to stripe the Waxheads’ results table. I’d been intending to automate the tedious process of adding guide stripes to the Waxheads’ tables for a while but, until seeing David’s article, hadn’t found the impetus.
My solution is a short function that sets the class of
either the odd or even rows of a table. Thus, you can have full control
over the guide stripes’ appearance via the page’s stylesheet.
As in David’s example, if the row already has a class defined then
the function won’t replace it with the guide stripe class.
Implementation
To stripe your table is pretty straightforward. Firstly, identify your
table with an id attribute. For instance:
<table id="myTable" summary="Striped table">
Now, either directly from a <script> block within the
page, or from the onload attribute in the <body>
tag, call, for example:
tableStripe('myTable', 'myGuideStripeClass', true)
The parameters are, in order, the id of the table, the class name to apply to the row and, finally, a Boolean to determine whether to apply the class to the odd (true) or even (false) rows.
The JavaScript source is fairly succinct.
Handily, the DOM provides a rows attribute in the
table class, which is a list of all the table’s row
elements in the order in which they appear. We simply traverse the
list and, depending on whether we want to apply our class to odd or
even rows and, if the row hasn’t already got a class attribute, we
set the row’s className attribute to our supplied class
name.
The rows are indexed from zero, so we set our starting index (zero for an odd start and one for an even start) and then traverse the list in steps of two, checking whether the row already has a class and, if not, applying our own.
I’ve borrowed David’s hasClass() function, for
the IE compatibility reasons he describes in his comment.
For more information about the DOM see Document Object Model (DOM) Level 2 HTML Specification
This article is a work in progress. I’ve noted that both this technique, and David H Miller’s don’t work for IE5.01/Win, I will look to see if there’s a work-around that can be applied in that case - let me know if you find other issues with other browsers.
Copyright © 1997-2008, Peter S Asquith. Most rights reserved.