tooltip技術解説

実用的に使えるツールチップを目指した jquery.tooltip2 及び jquery.ui.tooltip2 の実装について説明したいと思います。
http://rtilabs.net/files/2011_03_25/tooltip/

ポップアップしたツールチップにフォーカスを当てるには?

ふつーに作ると、ポップアップしたツールチップにフォーカスを当てることができません。

//ダメな例

//イベント設定
_bindevent: function(showoption)
{
	var self = this;
	this.tooltip
		.bind("mouseover focus",function(event){ self.show(event); return false; })
		.bind("mouseout blur" ,function(event){ self.hide(event); return false; })
	this.element
		.bind("mouseover focus",function(event){ self.show(event); return false; })
		.bind("mouseout blur" ,function(event){ self.hide(event); return false; })
},

//表示する.
show: function(event) {
	this.tooltip.show();
},

//非表示にする
hide: function(event) {
	this.tooltip.hide();
},

これは、 mouseoutのタイミングでツールチップを削除しているからです。


赤の領域にマウスカーソルが入ってきたらツールチップを出す。
赤の領域からマウスカーソルが去ったらツールチップを消す。


赤の領域でツールチップを出したとして、ツールチップ事態にフォーカスを立てに行くには、
一度、赤の領域をでないとダメで、赤の領域を離れた瞬間に mouseout が発動され、ツールチップを消してしまいます。


よって、ふつーに作ると、ツールチップにマウスカーソルを移動できません。

対策

対策として、 mouseout の処理を遅延させることで対策が可能です。
mouseout が発生したらすぐにツールチップを消すのではなく、内部でタイマーを生成します。

//表示する.
show: function(event) {
	//遅延非表示タイマーが有効なら、もう今すぐ表示するから無効にする.
	if (this.hideDelayTimer){
		 clearTimeout(this.hideDelayTimer);
	}
	//現在そもそも表示しているか?
	if (this.shown) {
		//すでに表示済み.
		return;
	}
	//表示フラグを有効にする.
	this.shown = true;

	//表示用の関数の実行
	this.tooltip.show();
},

//非表示にする
hide: function(event) {
	var self = this;

	//遅延表示タイマーが有効作り直す.
	if (this.hideDelayTimer){
		 clearTimeout(this.hideDelayTimer);
	}
	//タイマーを作ってゆっくり消す。
	//すぐに消してしまうと、ツールチップにフォーカスをできないため。
	this.hideDelayTimer = setTimeout(function () {
		this.hideDelayTimer = null;
		self.shown = false;

		self.tooltip.hide();
	}, this.options.hideDelayTime );
},

タイマーをつくることで、ツールチップを削除する数秒の猶予を与えます。
その間に、再び mouseover が発生すれば、タイマーは消去されなかったことになります。


こうすることで、赤の領域との間にある領域にマウスが入り込んでもしばらくはツールチップは削除されずに残るわけです。
よって、ツールチップ自体にフォーカスを移動させることができます。

pure css で矢印を作るには?

tooltip2 の特徴である pure css吹き出しについて説明します。
pure css吹き出しを作る方法は数年前からある border テクニックを利用しています。


border がでかいのを作る。

<div style="border: 30px solid red;width: 100px;height: 20px;"></div>



border に色を付けてみる。

<div style="border: 30px solid red;
     border-left-color:yellow;
     border-right-color:pink;
     border-top-color:green;
     border-bottom-color:red;
     width: 100px;height: 20px;
     "></div>



border の基本色を通過にして入るところだけ残してみよう。

<div style="border: 30px solid transparent;
            border-bottom-color:red;
            width: 100px;height: 20px;
           "></div>



幅を調整して、ほらできた!!

<div style="border: 30px solid transparent;
            border-bottom-color:red;
            width: 0px;height: 0px;
           "></div>

こんな感じで、ボーダーを利用して、がんばって矢印を作成しています。


半分こ

半分の矢印の場合は、削りたい方向のborder を border-xxx: none と指定して落としてあげることでできます。

<div style="border: 30px solid transparent;
            border-bottom-color:red;
            border-left:none;
            width: 0px;height: 0px;
           "></div>

こんなふうに作れますね。


IE6 が transparentに未対応なんですが・・・・

はい、そうですね。
しかし filter の chroma で逃げる方法があります。
ひとつだけ通過色を生贄に指定します。
通過色は今後使えなくなるので、とてもへんてこりんな色を指定します。
今回は fuchsia を指定してみました。

まずこうやって、 transparent にしたいところを fuchsia にします。

<div style="border: 30px solid fuchsia;
            border-bottom-color:red;
            border-left:none; 
            width: 0px;height: 0px;
           "></div>

次にフィルター chroma を追加して、この色は画面に出さない!!って指定すると・・・
ほらできました。(IE6で見てね)

<div style="border: 30px solid fuchsia;
            border-bottom-color:red;
            border-left:none;
            width: 0px;height: 0px;
            filter=chroma(color=fuchsia)
           "></div>

画像バージョン

pure css でボーダーぶちぬきの矢印を作るには?

このようなボーダーをぶち抜いている矢印はどうやって作るんでしょうか?

これは、大きな矢印と小さな矢印を貼り合わせることで作成しています。

div を2毎作ります。

<div style="border: 30px solid transparent;
            border-bottom-color:red;
            width: 0px;height: 0px;
           "></div>
<div style="border: 28px solid transparent;
            border-bottom-color:green;
            width: 0px;height: 0px;
           "></div>



小さい矢印の方が手前に来るので、 zIndex を補正します。

<div style="border: 30px solid transparent;
            border-bottom-color:red;
            width: 0px;height: 0px;
           "></div>
<div style="border: 28px solid transparent;
            border-bottom-color:green;
            width: 0px;height: 0px;
            z-index: 1
           "></div>


あとは貼りあわせて完成です。
座標調整はがんばる必要がありますw





borderの所に食い込ませて表示するとこんな感じになる

pure css で思っているみたいな円形はどう作るのか?

この思っているみたいな円形はどうやって作るんでしょうか?
css3 だと border-radius があります。
border-radiusを利用すると、このように角を丸くできます。

<div style="border: 5px solid red;
            width: 100px;height: 20px;
            border-radius:10px;
            -moz-border-radius:10px;
            -webkit-border-radius:10px;
            -ms-border-radius:10px;
           "></div>


これで幅高を縮めていくと・・・円形になりました。

<div style="border: 5px solid red;
            width: 10px;height: 10px;
            border-radius:10px;
            -moz-border-radius:10px;
            -webkit-border-radius:10px;
            -ms-border-radius:10px;
           "></div>

こんな感じで円形をつくることができます。

IE9未満のborder-radiusはどうするの?

MSIE9 から css3 の border-radius がサポートされました。
-ms-border-radius は、ちゃんとうまく動作します。

しかし、世の中、そんなに甘くなくて、IE8やIE6の人もいるでしょう。
その場合は、vml を利用して border-radius で作ったみたいな円形をつくることができます。


vmlを利用するには、まずこんなふうにおまじないをする必要があります。(めんどい!)

if (!document.namespaces.v) { 
	document.namespaces.add('v', 'urn:schemas-microsoft-com:vml');
	document.namespaces.add('o', 'urn:schemas-microsoft-com:office:office');
}


そして、 あとは、vmlの roundrect を利用して角丸の四角形を作ります。
border-radius のときのように幅高を調整すると、円形を書くことができます。

<v:roundrect style="width:30; height:30; behavior: url(#default#VML);"
             arcsize="30"
             fillcolor="white"
             strokecolor="green"
             strokeweight="5"
/>

はてなダイアリーなのでvmlが描画できず、、、画像を貼っておきますね。

やったね!

デザイン拡張性を求めて。

tooltip2 ではカスタマイズ性を第一に考えてクラスを設計しています。
まずは、デザインの拡張性の配慮について説明します。
吹き出しはディフォルトで ui-tooltip のcssクラスを持っています。
よって、ページのすべての吹き出しの色を css で簡単に統一させることができます。

.ui-tooltip {
	background:		white;
	color:			black;
}

ただし、このツールチップの色はちょっと違うだろうということもありますよね。
その場合は、個別にクラス名を指定してデザインを変えることもできます。

.mymy-tooltip {
	background:		white;
	color:			yellow;
}
$('#div11').tooltip2({ className: 'mymy-tooltip' });

cssクラスなんて作るなんて面倒。javascript で直接変更したいんだ!という人もいます。
そのときは css プロパティで色などの情報を直接与えることができます。

$('#div11').tooltip2({ css: { background: 'blue', border: '4px solid pink' } });

このような柔軟なデザインができるようにプログラムはこのようになっています。

//ツールチップの土台の修飾(一部省略)
this.tooltip
	//基本クラスui-tooltip と、
	//ユーザが指定したクラスがあれば追加。
	.addClass("ui-tooltip  " + this.options.className)
	//ユーザーが指定したcssがあれば最後に適応
	.css(this.options.css);

uiはデザインが結構絡む微妙なところなので、細かいカスタムができるように徹底的に配慮しています。

アニメーション拡張性を求めて。

アニメーションはUIの幹線の部分であり、さまざまなアニメーションが考えられます。
tooltipのアニメーションの指定は2つあります。

まずは文字列で指定する方法です。
jquery.ui.effect に登録されている名前を指定することで簡単に面白い効果を得られます。

$('#div11').tooltip2({ show: 'blind', hide: 'explode' });

もう一つは、関数を指定する方法です。
このように関数を指定することで、どのような表示するかをプログラム可能です。

$('#div11').tooltip2({ show: function(){ this.show('slow'); }, hide: function(){ this.hide('slow'); } );


tooltip2 のアニメーションの部分は以下のように定義されています。

//表示用の関数の実行
$.isFunction( this.options.show ) ? 
	this.options.show.apply(this.tooltip) : 
	this.tooltip.show(this.options.show);

関数だったら、関数を実行し、
そうでなければ、文字列で指定されたものとして show() メソッドを呼び出しています。