Welcome to wasabicube. Skip to navigation or skip to content.

Firefox/Mozilla flicker-free drop-down

1162 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

1488 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.

JPEG: Initial CorelDRAW image

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.

JPEG: Image with “That Wicked Worn Look” applied

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:

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.

JPEG:genuine wasabicube

Stripey tables revisited

1593 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.

*Acknowledgments

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

1599 days ago by Peter Asquith —

Background


Update
This article has been superseded by an improved version!

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.