Bad Poetry

Entries categorized as ‘Tutorial’

Placing a background image in each corner

October 3, 2008 · 5 Comments

I recently saw a discussion on CSS-D about multiple background images, and while it doesn’t exactly answer the question I thought I’d share a tip that some of you may find useful. At least until multiple backgrounds with CSS3 is properly supported.

So, what we want to do here is put a background image in each of the four corners of the body. The mark-up we need:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
	<head>
		<title>Example: A background image in each corner</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<link rel="stylesheet" type="text/css" href="css/style.css" />
	</head>
	<body>
		<div id="outer_container">
			<div id="container">
			</div>
		</div>
	</body>
</html>

Unfortunately the extra DIVs are required as a hook for the background images, but we can reduce the number required down to two by using the HTML element and the BODY element as hooks for two of the images.

And the CSS:

*			{ margin: 0; padding: 0; }
html			{ background: #fff url(../images/top_left.gif) top left no-repeat; height: 100%; }
body			{ background: url(../images/top_right.gif) top right no-repeat; height: 100%; }
#outer_container	{ background: url(../images/bottom_left.gif) bottom left no-repeat; height: 100%; }
#container		{ background: url(../images/bottom_right.gif) bottom right no-repeat; min-height: 100%; _height: 100%; }

The only thing really to note is that _height: 100%; is a hack for IE6 to mimic the behaviour of min-height: 100%;, and will cause the stylesheet to fail validation. You can put that in an IE only stylesheet if that sort of thing bothers you.

Here is our working example. This technique has been tested to work in Firefox, Opera, Safari for Windows, IE7, and IE6.

Also, just as a note this technique can cause some freaky results when page-zoom is used in IE7, but to a lesser or greater extent this sort of thing will always choke a little in IE7 with page-zoom.

Categories: CSS · HTML · Tutorial · Web Development
Tagged: , , , , ,

Long Lost Nephew of Suckerfish

September 4, 2008 · 2 Comments

I needed to create a CSS-based drop-down list that would work cross-browser and had some extra features for better usability including a mouse-off delay and keyboard accessibility.

I was very familiar with the suckerfish menu, but it didn’t meet my needs to I decided to scrap it and start from scratch. So here I’ll go through what I came up with.

Our HTML structure is the standard nested list format that we all know and love:

<ul id="nav">
	<li>
		<a href="#">Home</a>
	</li>
	<li>
		<a href="#">News</a>
	</li>
	<li>
		<a href="#">Photos</a>
		<ul>
			<li>
				<a href="#">Reader Shots</a>
			</li>
			<li>
				<a href="#">Wallpapers</a>
				<ul>
					<li>
						<a href="#">800 x 600</a>
					</li>
					<li>
						<a href="#">1024 x 768</a>
					</li>
					<li>
						<a href="#">1280 x 1024</a>
					</li>
				</ul>
			</li>
			<li>
				<a href="#">Photo Galleries</a>
			</li>
		</ul>
	</li>
	<li>
		<a href="#">Videos</a>
	</li>
	<li>
		<a href="#">Results</a>
		<ul>
			<li>
				<a href="#">National</a>
			</li>
			<li>
				<a href="#">International</a>
			</li>
		</ul>
	</li>
</ul>

Once we have our HTML structure the first thing we’re going to do is set the styles for how the menus should look when they’re expanded. In this case we’re going with some very simple styles, but you can make this as complicated as you like.

#nav,
#nav li ul				{ list-style: none; margin: 0; padding: 0; width: 150px; }
#nav li					{ padding: 0 3px 3px 0; position: relative; }
#nav li a				{ border: 1px solid #000; display: block; text-decoration: none; width: 145px; }

#nav li ul				{ left: 150px; position: absolute; top: 0; }
#nav li a				{ background: #fff; color: #000; }

Example 1: The basic structure for our menu, but no functionality yet

Now we have our menu in place we’ve got to get it acting like a dropdown. We’re using a negative margin-left to achieve this, and then setting the margin to 0 when the list item is hovered over:

#nav li:hover ul li ul,
#nav li ul				{ margin-left: -9999px; }

#nav li ul li ul,
#nav li:hover ul,
#nav li ul li:hover ul			{ margin-left: 0; }

#nav li a,
#nav li:hover ul li a,
#nav li ul li:hover ul li a		{ background: #fff; color: #000; }

#nav li:hover a,
#nav li a:hover,
#nav li ul li:hover a,
#nav li ul li a:hover,
#nav li ul li:hover ul li:hover a,
#nav li ul li:hover ul li a:hover	{ background: #000; color: #fff; }

Example 2: Basic CSS Dropdown Menu

The next step is to make it keyboard accessible in modern browsers (everything except IE). We can do this by using a combination of the :focus pseudo class and the + combinator to provide some basic keyboard functionality. It isn’t relevant yet, but I’ve seperated selectors using the + combinator from other selectors because IE6 ignores all of the selectors in a list if one is using the + combinator.

#nav li:hover ul li ul,
#nav li ul				{ margin-left: -9999px; }
#nav li a:focus + ul li ul		{ margin-left: -9999px; }

#nav li ul li ul,
#nav li:hover ul,
#nav li ul li:hover ul,
#nav li.hover ul li a:focus,
#nav li ul li.hover ul li a:focus	{ margin-left: 0; }
#nav li a:focus + ul,
#nav li ul li a:focus + ul		{ margin-left: 0; }

#nav li a,
#nav li:hover ul li a,
#nav li ul li:hover ul li a		{ background: #fff; color: #000; }

#nav li:hover a,
#nav li a:hover,
#nav li a:focus,
#nav li a:active,
#nav li ul li:hover a,
#nav li ul li a:hover,
#nav li ul li:hover ul li:hover a,
#nav li ul li:hover ul li a:hover	{ background: #000; color: #fff; }

#nav li ul li a:focus,
#nav li ul li ul li a:focus		{ margin-left: 9999px; }

As you can see in our example page there is a lot to be desired for keyboard users, but it’s a good start. We will use JavaScript to provide better usability for keyboard users, but we’ll get to that later.

Example 3: CSS-based dropdown menu that is keyboard accessible in modern browsers

If you’ve had a look at any of these examples in IE6 you probably will have seen that the menu doesn’t work. At all. We need to use JavaScript to fix our IE6 issues, so while we’re at it let’s add some usability aids, such as a mouse-off delay.

All of this is done by the function below. It is completely parameterised so you can apply it to any number of dropdown lists and change the timing, etc.

//	dropDownId	string	ID of the UL containing the drop down
//	hoverClass	string	Class to be applied to the LIs on mouse over
//	mouseOffDelay	int	Delay from when the mouse is lifted from the drop down until hoverClass is removed (in milliseconds)
function drop_down(dropDownId, hoverClass, mouseOffDelay) {
	if(dropDown = document.getElementById(dropDownId)) {
		var listItems = dropDown.getElementsByTagName('li');
		for(var i = 0; i < listItems.length; i++) {
			listItems[i].onmouseover = function() {
				this.className += ' ' + hoverClass;
			}
			listItems[i].onmouseout = function() {
				var that = this;
				setTimeout(function() {
					that.className = that.className.replace(hoverClass, "")
				}, mouseOffDelay);
				this.className = that.className;
			}
		}
	}
}

And we call the function like so:

drop_down('nav', 'hover', 250);

In our examples we have used Simon Willison’s great Add Load Event function to call the function on page load, however you can use any method you like.

Now we need to change our CSS to use our new .hover class:

#nav li:hover ul li ul,
#nav li ul,
#nav li.hover ul li ul			{ margin-left: -9999px; }
#nav li a:focus + ul li ul		{ margin-left: -9999px; }

#nav li.hover ul,
#nav li ul li ul,
#nav li ul li.hover ul,
#nav li:hover ul,
#nav li ul li:hover ul,
#nav li.hover ul li a:focus,
#nav li ul li.hover ul li a:focus	{ margin-left: 0; }
#nav li a:focus + ul,
#nav li ul li a:focus + ul		{ margin-left: 0; }

#nav li a,
#nav li:hover ul li a,
#nav li.hover ul li a,
#nav li ul li:hover ul li a,
#nav li ul li.hover ul li a		{ background: #fff; color: #000; }

#nav li:hover a,
#nav li.hover a,
#nav li a:hover,
#nav li a:focus,
#nav li a:active,
#nav li ul li:hover a,
#nav li ul li.hover a,
#nav li ul li a:hover,
#nav li ul li:hover ul li:hover a,
#nav li ul li.hover ul li.hover a,
#nav li ul li:hover ul li a:hover	{ background: #000; color: #fff; }

Example 4: JavaScript enhancements allow IE6 users to use the menu and adds a usability improvement

The final piece of the puzzle is to make our menu keyboard accessible for all browsers and more usable to-boot. We do this by mimicking the effect of hovering of a list-item when you are focused on it’s child anchor. Inside our loop we’ll insert the following piece of script:

var anchor = listItems[i].getElementsByTagName('a');
anchor = anchor[0];
anchor.onfocus = function() {
	if(this.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName == 'LI') {
		this.parentNode.parentNode.parentNode.parentNode.parentNode.className += ' ' + hoverClass;
	}
	if(this.parentNode.parentNode.parentNode.nodeName == 'LI') {
		this.parentNode.parentNode.parentNode.className += ' ' + hoverClass;
	}
	if(this.parentNode.nodeName == 'LI') {
		this.parentNode.className += ' ' + hoverClass;
	}
}
anchor.onblur = function() {
	if(this.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName == 'LI') {
		this.parentNode.parentNode.parentNode.parentNode.parentNode.className = this.parentNode.parentNode.parentNode.parentNode.parentNode.className.replace(hoverClass, "");
	}
	if(this.parentNode.parentNode.parentNode.nodeName == 'LI') {
		this.parentNode.parentNode.parentNode.className = this.parentNode.parentNode.parentNode.className.replace(hoverClass, "");
	}
	if(this.parentNode.nodeName == 'LI') {
		this.parentNode.className = this.parentNode.className.replace(hoverClass, "");
	}
}

This script finds the first anchor and assigns onfocus and onblur events to it (the keyboard equivalent to onmouseover and onmouseout, except that it can only be applied to focusable elements i.e. links and form controls).

When we tab onto a link we want to assign our hoverClass to the anchors parent LI, and depending how deep it is we want to apply hoverClass to it’s great grandparent LI and it’s great great great grandparent LI. This allows us to style all of it’s parents, helping to give keyboard users a better indication of where they are.

Example 5: Final JavaScript enhancements make the menu more accessible to keyboard users on all browsers

Please grab the finished CSS and JavaScript files.

Check out the finished product, kick the tyres, and let me know what you think. Feel free to use abuse and modify as you need. Attribution is always appreciated.

Categories: CSS · HTML · JavaScript · Tutorial · Web Development
Tagged: , , , , , , , ,