読者です 読者をやめる 読者になる 読者になる

IEでlabel内の画像をクリック可能にする

JavaScript

ウノウラボ by Zynga Japan: IEでlabelの子要素に画像を含めるをより汎用的に実装してみます。

まず、修正方針は以下の2点。

  1. HTML側に処理を書かない(onclickは使わない)
  2. IEだけで処理されるようにする

素直に書いてみるとこういった感じになります。

/*@cc_on
window.attachEvent('onload', function(){
	// まず、label内の画像に自分がクリックされたらlabelにクリックを投げる関数を定義する
	var label_img_enclick = function(label) {
		var imgs = label.getElementsByTagName('img');
		for (var i = 0, l = imgs.length;i < l; ++i)
			imgs[i].attachEvent('onclick',function(){
				label.click();
			});
	};
	// ページ内のlabelタグを走査し、for属性を持ち、対応するinput要素が存在する場合、上記関数を適用する
	var labels = document.getElementsByTagName('label');
	for (var i = 0, l = labels.length;i < l; ++i) {
		var label = labels[i], input;
		if (label.htmlFor
				&& (input = document.getElementById(label.htmlFor)) 
				&& /input/i.test(input.tagName)
			 ) {
			label_img_enclick(label);
		}
	}
});
@*/

今回は/*@cc_on@*/でIEだけに適用されるようにしましたが、<!--[if IE]>で分岐しても良いでしょう。
改良の余地はやはりonloadの部分で、読み込みが完全に終わるまで処理が行われません。jQueryなどのライブラリを使えばよいのですが自前で実装するのはあまりやりたくありませんね。
ある意味簡単なのはページの一番下(bodyの閉じタグの直前)にこのscriptを埋め込む方法です。IE限定なので、defer属性を使うという選択肢もあります。script要素のdefer属性の実装 - Thousand Years

CSS expression

(IE8ではexpressionが廃止されているので、バージョンが限定されてしまいますが、)expressionを使うというアイディアもあります。
onload待ちがない、読み込み後に追加された要素にも対応できるといったメリットはありますが、やはりexpressionを実際に使うのは抵抗があると思います。あくまでアイディアの1つということで。

<!--[if IE]>
<style type="text/css">
label img{
zoom:expression((function(img){
	if (!img.__mark) {
		img.attachEvent('onclick',function(){
			img.parentNode.click();
		});
		img.__mark = true;
	}
	return 1;
	})(this));
}
</style>
<![endif]-->

参考: IE の innerHTML や appendChild で要素が挿入された瞬間を取得する方法 - IT戦記