LDIR: LoaD_Increment_Repeat http://blog.peter-ryan.co.uk The (mostly techie) ramblings of Peter Ryan. Wed, 18 May 2011 17:17:30 +0000 en-US hourly 1 http://wordpress.org/?v=3.8.1 iPhone doesn’t support :hover? Or does it? http://blog.peter-ryan.co.uk/2008/05/19/iphone-doesnt-support-hover-or-does-it/ http://blog.peter-ryan.co.uk/2008/05/19/iphone-doesnt-support-hover-or-does-it/#comments Mon, 19 May 2008 15:45:26 +0000 http://blog.peter-ryan.co.uk/?p=5 When reading up about developing websites for iPhone (and iPod Touch), everyone points out how Safari on this platform works pretty much like the desktop version except that the touch interface means some things, for example hover events, do not work. Okay, that makes sense to me.

However, whilst working on other code, I had noticed a few… anomalies! Check out this example page. There is a single CSS rule:

p:hover {
	background-color: red;
}

This rule does get triggered on an iPhone if the element has a click event handler that returns true. This includes <a>nchor elements, which will work even with JavaScript disabled.

It’s a bit difficult to exploit this behaviour however. I did try to have the rule act like a toggle – enabling and disabling on successive clicks, but iPhone does not (as far as I can tell) support blur() or focus() functions.

What I’d be interested in knowing is if this functionality is by design, or if it is simply a feature of WebKit?

]]>
http://blog.peter-ryan.co.uk/2008/05/19/iphone-doesnt-support-hover-or-does-it/feed/ 0
Using CSS3 :target selectors http://blog.peter-ryan.co.uk/2008/03/14/using-css3-target-selectors/ http://blog.peter-ryan.co.uk/2008/03/14/using-css3-target-selectors/#comments Fri, 14 Mar 2008 00:52:43 +0000 http://blog.peter-ryan.co.uk/2008/03/14/using-css3-target-selectors/ This is a quick post to present a JavaScript that provides CSS3 :target pseudo selector like functionality for browsers that do not provide native :target support.

function() {
    var cssClass = 'target';

    // Initialise targeted fragments if any.
    var target = document.getElementById(window.location.hash.slice(1));
    if (target) {
        target.className += ' ' + cssClass;
    }

    // Click event handler function generator. This is passed a "frag" argument
    //   that is a reference to the target element.
    var reCSS = new RegExp("\\b" + cssClass + "\\b");
    function newTargetClickHandler(frag) {
        return function() {
            if (target) {
                target.className = target.className.replace(reCSS, '');
            }
            target = frag;
            target.className += ' ' + cssClass;
        }
    }

    // Run thru <a> elements and add an onclick handler to those that reference
    //   document fragments within the current page.
    var reURI = new RegExp('^' + window.location.href.match(/^[^#]+/)[0] + '#([^#]+)$');
    var elems = document.getElementsByTagName('a');
    for (var i=0; i<elems.length; i++) {
        if (elems[i].href && elems[i].href.match(reURI)) {
            elems[i].onclick = newTargetClickHandler(document.getElementById(RegExp.$1));
        }
    }
};

When the user clicks on a link that points to a fragment within the current page, this code will add a CSS class of “target” to the targeted element, and will remove the same “target” class from any previously targeted element.

Originally I was using the CSS3 :target pseudo selector and the .target class selector together in the same rule set, but I found that Opera (9.26) would not apply the rules presumably because it considered it invalid.

/* THIS DOES NOT WORK! */
h2:target,
h2.target {
    color: red;
}

I’m not sure if this is correct behavior, but regardless of cause, I found I had to use a duplicate set of CSS rules; one for both modes of selection.

h2:target {
    color: red;
}
h2.target {
    color: red;
}

And basically… that’s it! You can see it in action on this test page, and I hope to add a follow up post soon…. time allowing.

You download the the JavaScript here:
Full-fat script with white-space and comments [1621 bytes]
Minified script [1101 bytes]

]]>
http://blog.peter-ryan.co.uk/2008/03/14/using-css3-target-selectors/feed/ 3
Suckerfish menus with hide delay http://blog.peter-ryan.co.uk/2007/12/08/suckerfish-menus-with-hide-delay/ http://blog.peter-ryan.co.uk/2007/12/08/suckerfish-menus-with-hide-delay/#comments Sat, 08 Dec 2007 19:38:40 +0000 http://blog.peter-ryan.co.uk/2007/12/08/test-post/ You’re using Suckerfish Dropdown menus but you would like to prevent the dropdown menus from disappearing the moment the users mouse steps 1 pixel outside the dropdown?

This question is especially relevant with multi-level dropdown menus; multi-level menus and laptop track-pads are something I’ll never get used to!

The code presented below is designed to be a drop-in replacement for the standard suckerfish Javascript. The original code was only required to make MSIE work correctly, the replacement code targets all browsers. If Javascript has been disabled by the user, then the CSS will function as before.

sfHover = function() {
	var timeout = 600;
	var cssClass = "sfhover";

	var queue = [];
	var reCSS = new RegExp("\\b" + cssClass + "\\b");
	var sfEls = document.getElementById("nav").getElementsByTagName("li");
	for (var i=0; i<sfEls.length; i++) {

		// mouseover and mouseout handlers for regular mouse based interface.
		sfEls[i].onmouseover = function() {
			queueFlush();
			this.className += " " + cssClass;
		}
		sfEls[i].onmouseout = function() {
			queue.push([setTimeout(queueTimeout, timeout), this]);
		}

		// focus and blur handlers for keyboard based navigation.
		sfEls[i].onfocus = function() {
			queueFlush();
			this.className += " " + cssClass;
		}
		sfEls[i].onblur = function() {
			queue.push([setTimeout(queueTimeout, timeout), this]);
		}

		// click event handler needed for tablet type interfaces (e.g. Apple iPhone).
		sfEls[i].onclick = function(e) {
			if (this.className.search(reCSS) == -1) {
				// CSS not set, so clear all sibling (and decendants) menus, and then set CSS on this menu...
				var elems = this.parentNode.getElementsByTagName("li");
				for (var i=0; i<elems.length; i++) {
					elems[i].className = elems[i].className.replace(reCSS, "");
				}
				this.className += " " + cssClass;
			} else {
				// CSS already set, so clear all decendant menus and then this menu...
				var elems = this.getElementsByTagName("li");
				for (var i=0; i<elems.length; i++) {
					elems[i].className = elems[i].className.replace(reCSS, "");
				}
				this.className = this.className.replace(reCSS, "");
			}
			if (e && e.stopPropagation)
				e.stopPropagation();
			else
				window.event.cancelBubble = true;
		}
	}

	queueFlush = function () {
		while (queue.length) {
			clearTimeout(queue[0][0]);
			queueTimeout();
		}
	}

	queueTimeout = function() {
		if (queue.length) {
			var el = queue.shift()[1];
			el.className = el.className.replace(reCSS, "");
		}
	}
}
addLoadEvent(sfHover);

The code also includes handlers for focus and blur events, to allow site visitors to tab through the menus without using a mouse.

And finally, a click event handler is added to parent menus so that they can be opened on devices that don’t support hover events such as the iPhone/iPod Touch. This might cause a problem if your parent menu item is also a link however!

Oh… and finally finally, the above code calls the an addLoadEvent() function to force sfHover to run on page load. If you don’t already have a similar function, here’s one you can use:

function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			oldonload();
			func();
		}
	}
}

UPDATE 2008-05-19: I have uploaded a very basic example page here, and the JavaScript is available for download here.

]]>
http://blog.peter-ryan.co.uk/2007/12/08/suckerfish-menus-with-hide-delay/feed/ 14