The Pinball Effect

The Pinball Effect

Got something to say?

Share your comments on this topic with other web professionals

In: Articles

By Adam Khan

Published on June 12, 2006

Links should be big enough to hit with a dirty, sticky mouse.”
Andrew Morrall

“…one of the most ignored principles in design…”
Bruce Tognazzini

Yadda × 3: Preamble

It’s quicker and easier to use a bigger link than a smaller one—this is obvious. There’s even a mathematical formula, Fitts’ Law, to calculate just how much quicker. Presented below is a simple way to transform an entire area of a Web page into a link from within it, effectively expanding the link’s size, using Cascading Style Sheets, JavaScript and the Document Object Model. I call this the Pinball Effect because the cursor lights up various areas of the screen sort of like a pinball does zipping around the playfield.

The Pinball Effect is ideal for items in detailed lists, such as entries on a blog’s index pages (see the example). It degrades gracefully if the client’s scripting is off. And it adds no inline JavaScript to mess up your pristine HTML. I call the affected area the Pinball Scoop, the link within it the Pinball Sinkhole. And rest easy, this flip metaphor plunges no further.

Yalla × 2: Get On With It

First we’ll add the scoops and sinkholes to the page. Simply add pinball-scoop to the class definition of each of the areas that should light up, and pinball-sinkhole to the class definition of the desired link within each area.

Snippet from pinball-effect.html

     <div class="blog-teaser pinball-scoop">       <h2><a class="a-class pinball-sinkhole"      href="http://crockford.com/javascript/survey.html">A Survey of the JavaScript     Programming Language</a> by Douglas Crockford</h2>       <p><a href="http://java.sun.com/pr/1995/12/pr951204-03.html">JavaScript</A> was     developed by Brendan Eich at Netscape as the in-page scripting language for     Navigator 2. It is a remarkably expressive dynamic programming language. Because of     its linkage to Web browsers, it instantly became massively popular. It never got a     trial period in which it could be corrected and polished based on actual use. The     language is powerful and flawed.</p>     </div>      <div class="blog-teaser pinball-scoop">       <h2><a class="some-other-class-perhaps pinball-sinkhole"      href="http://www.bigempire.com/filthy/lifeaquatic.html">Filthy Critic: The Life     Aquatic</a></h2>       <p>Director Anderson sure as shit loves making movies and cramming them with     details, contraptions and fantastic visuals. He even loves dialog and writes bits     that other writers would kill to have. It's just that he seems to be getting so     Goddamned disinterested in people that he can't give them any sort of emotional trip     that makes the physical one worth following. He did the same thing with <a     href="http://www.bigempire.com/filthy/royaltenenbaums.html">Royal Tenenbaums</a>,     where he spent so much time sketching the characters' quirks that he never bothered     letting them express anything.</p>     </div>

That’s it, that’s the only inline addition to the HTML, so if scripting is off then nothing happens; degradation is graceful.

Second, what allows us to set mouseover and onclick behavior without inline JavaScript is the JavaScript file containing the pinballEffect function and its subfunctions (with thanks to Peter-Paul Koch’s Quirksmode Mouseovers tutorial). The function traverses the document, teasing out any elements with the pinball-scoop class and giving them the subfunctions treatment whenever triggered by mouse behavior.

Here’s the code:

pinball-effect.js

 var W3CDOM = (document.createElement && document.getElementsByTagName); window.onload = pinballEffect;  function pinballEffect() { 	if (!W3CDOM) return; 	var allElements = document.getElementsByTagName('*'); 	var originalBackgrounds=new Array(); 	for (var i=0; i<allElements.length; i++) 	{ 		if (allElements[i].className.indexOf('pinball-scoop') !=-1) 		{ 			allElements[i].onmouseover = mouseGoesOver; 			allElements[i].onmouseout = mouseGoesOut; 			allElements[i].onclick = mouseGoesClick; 		} 	} }  function mouseGoesOver() { 	originalClassNameString = this.className; 	this.className += " pinball-on"; 	this.style.cursor = "pointer"; 	this.style.cursor = "hand";  }  function mouseGoesOut() { 	this.className = originalClassNameString; }  function mouseGoesClick() { 	var allThisAreasElements = this.getElementsByTagName('*'); 	for (var j=0; j<allThisAreasElements.length; j++) 	{ 		if (allThisAreasElements[j].className.indexOf('pinball-sinkhole') != -1) 		{ 			var url = allThisAreasElements[j].href; 			window.location = url; 		} 	} }  pinballEffect();

In the pinballEffect function, line 1 stops us from even trying if the browser can’t handle it. (Have I mentioned degradation? Grace?) The mouseGoesClick function is similar to its parent pinballEffect function, but rather than traversing the document seeking Pinball Scoops, it traverses a particular scoop seeking its sinkhole.

If there’s no click and the mouse goes out, the mouseGoesOut function restores the scoop element’s class name string to whatever it was before the mouseGoesOver function appended the pinball-on class to it. This allows our elements to have any number of other classes, which is nice.

Note that the regular expression in mouseGoesClick requires that that the sinkhole URL be within double quotes. And if you accidentally put more than one sinkhole link within a single scoop it’ll grab whichever comes first. I suspect.

The mouseover cursor style can also be set in the CSS, but the browser seems to react more quickly from the JavaScript. To cover any browser disparities, I added it to both. And in case you didn’t know, Internet Explorer requires a hand rather than a pointer.

Save the code as a file and call it just above your </body> tag:

<script type="text/javascript" src="pinball-effect.js"></script>

Now of course you need some CSS to actually show the difference between off and on states. The following is what I used for the example:

pinball-effect.css

 body { color: #000; }  .blog-teaser { width: 27em; padding: 0px; background-color: #aaa; margin-bottom: 1ex; }  .pinball-on { background-color: yellow; }  h2, p { padding: 10px; margin: 0px; }

Again, save it and call it from somewhere in the header:

<link rel="stylesheet" type="text/css" media="screen" href="pinball-effect.css" />

Play with Others

There’s another, simpler technique to enlarge the clickable area around a link using CSS only. The Denton Method is designed for inline links, so it complements the Pinball Effect, which is more appropriate for titles. Just incorporate this into your stylesheets:

     p a:hover {   background-color: #you-choose;   position:relative;   z-index: 1;   padding: .4em 0 .55em 0; }

Speaking of padding, I will now round out this article with yet another person’s work. In More Nifty Corners, Alessandro Fulciniti ingeniously uses no graphics—CSS and JavaScript only—to bestow upon any and all elements rounded corners. (He has recently released a newer and more powerful version, Nifty Corners Cube, but it does not yet play pinball well.)

How do you think he does it? I don’t know, but just add a call to a copy of his More Nifty Corners CSS to your header:

<link rel="stylesheet" type="text/css" media="screen" href="nifty-corners.css" />

And add a call to a copy of the More Nifty Corners JavaScript file to that great thriving JavaScript reef just above your </body> tag:

 <script type="text/javascript" src="nifty-corners.js"></script>  <script> window.onload=function(){ if(!NiftyCheck())     return; Rounded("div.pinball-area","all","white","transparent","smooth");} </script>

If you want to use the newer Nifty Corners Cube, it’ll round your corners before the mouseover, but not during it. It does work just fine with mouseover behavior other than changing the background color, such as changing the text color. To upgrade to Cube, remove the Nifty CSS—the new code calls its own styling autonomously—and move the Pinball and Cube JavaScript calls from just above the </body> tag to the document’s header, placing the Cube call last.

Insert Coin

OK, now that you understand what I’m talking about, just download the pinball-effect.zip file containing all the required files:

  • pinball-effect.html
  • pinball-effect.js
  • pinball-effect.css
  • nifty-corners.js
  • nifty-corners.css
  • denton.css

Better Next Time

The script could be improved by checking that the sinkhole URL is correctly formed, only activating onmouseover and onclick behavior if it is; after all, we don’t want to perpetuate and even exaggerate errors—but for now we will.

Techniques Abused Above

Links of interest

Got something to say?

Share your comments  with other professionals (4 comments)

Related Topics: CSS, DOM, Scripting, Web Design

Adam Khan is a Web developer and Nokia 6630 fan. He is currently building Planadu.