JavaScriptとCSSでヘルプボタンと凡例(ツールチップ)表示をする例
前回は「JavaScriptで入力フォームにふきだしのようなツールチップを表示する例」と題して、入力フォームでそれぞれの項目の横にポップアップするツールチップを表示してみましたが、今度は入力パーツがない場合にも使えるヘルプボタンを実装してみたいと思います。
サンプル
見たほうが早いと思うので、早速サンプル。下の丸いハテナアイコンをクリックまたはタップすると凡例表示されます。
🍎 りんご
🍌 バナナ
🍈 メロン
マウスカーソルを載せたときに表示するような従来のツールチップでも良いのですが、前回の記事でも書いたとおり、最近はPCとスマホの両方に対応するのが当たり前になっているので、クリック(タップ)で表示する形にしてみました。
表示された凡例(ツールチップ)はページのどこでも良いのでクリック(タップ)すると消えます。
HTMLの例
<div class="help_area">
<div class="help_icon">?</div>
<div class="tooltip">
■凡例<br>
🍎 りんご<br>
🍌 バナナ<br>
🍈 メロン<br>
</div>
</div>
タグは何でも良いのですが、できるだけシンプルに、かつ多少は汎用性があるようにと考え、help_areaという枠(div)の中にアイコン(help_icon)とツールチップ(tooltip)を含める形にしました。
ヘルプボタンですから、1ページ中に複数置く場合もあるでしょうし、ID指定ではなくクラス名での指定です。
CSSの例
<style>
.help_area {
position:relative;
}
.help_icon {
border-radius:50%;
width:20px;
height:20px;
line-height:20px;
vertical-align:middle;
font-size:12px;
text-align:center;
background-color:#888888;
color:white;
cursor:pointer;
}
.tooltip {
position:absolute;
background-color:rgba(0,0,0,0.5);;
color:white;
border-radius:0.3em;
padding:0.3em;
margin:0.3em 0 0 1em;
display:none;
}
</style>
CSSもシンプルです。
ヘルプアイコンとツールチップを囲んでいる枠はposition:relative;を設定し、ツールチップがその付近に表示されるようにしています。
ヘルプアイコンは20x20pxのサイズで、border-radius:50%;を指定することで丸くしている感じですね。
あんま格好良くないので、実際に使う場合はフリー素材で配布されているSVG形式のアイコンとか使うと良いと思います。
それからツールチップの外観は角丸にしただけの矩形。ふきだしで使うような三角を付けても良かったのですが、CSSが長くなると見ている人がウンザリするかなと思って外しましたw
JavaScriptの例
<script>
document.querySelectorAll('.help_icon').forEach (elm => {
elm.onclick = function () {
event.stopPropagation();
let tooltip = this.parentNode.querySelector('.tooltip');
if (tooltip.style.display == 'block') {
tooltip.style.display = 'none';
} else {
tooltip.style.display = 'block';
}
};
});
document.body.onclick = function () {
document.querySelectorAll('.tooltip').forEach (tooltip => {
tooltip.style.display = 'none';
});
};
</script>
大したことはやっていませんが、一応本命(?)のJavaScript。
前回の例でも querySelectorAll での要素取得は行いましたが、見つかった各要素に対してイベントを設定するのは
for (let i = 0; i < elms.length; i++) { }
のような、よく言えば見慣れた、ぶっちゃけるとなんとなくダサい書き方をしていました。
ので、今回は
document.querySelectorAll('.help_icon').forEach (elm => { } );
というように、forEachで格好つけてみました。特に深い意味はありませんw
どちらかというと大事なのはこの stopPropagation の部分ですかね。
event.stopPropagation();
ヘルプボタンを押す→ツールチップを表示
ヘルプボタンをもう一度押す→ツールチップを非表示
これはわかりやすくて良いのですが、スペースの都合上、ヘルプボタンって小さくせざるを得ないじゃないですか。
それなのにツールチップ表示中にもう一度小さなヘルプボタンを押すのは(画面サイズによっては)なかなかやりづらいでしょう。
凡例表示しているツールチップをクリックすることで閉じる、という動作でも良いのですが、どうせなら画面のどこをクリック(タップ)しても非表示になったほうが直感的じゃないですかね?
そんなふうに考えて、bodyのクリックイベントでツールチップを消すようにしました。
document.body.onclick = function () {
document.querySelectorAll('.tooltip').forEach (tooltip => {
tooltip.style.display = 'none';
});
};
が、しかし、これだけではすべてのクリックイベントをbodyがひろってしまうので、ツールチップを表示するためにヘルプボタンを押したときにもこのイベントが実行され、ツールチップが開く→即閉じる という動作になります。
イベントバブリングってやつですね。
そんなわけで、子要素で発生したクリックイベントを親要素へ伝搬させないよう、stopPropagation();を実行しています。
まとめ
ググればそこら中にあるようなサンプルだと思いましたが、最近の流行りはCSSだけでツールチップを再現する方法のようで、labelタグと非表示にしたチェックボックスを使う例がゴロゴロ見つかりました。
…でも、あのやり方ってちょっとわかりづらくないですかね。:hoverで色変えるくらいならCSSでも良いのですが、:checkedでツールチップを表示したり非表示にしたりというのまでCSSでやるのは少し可読性が良くないかなぁ、と感じました。まぁJavaScriptのほうが見慣れているから、というだけの話かも知れませんw
いずれにせよ、ドヤ顔で公開するようなスクリプトではございませんが、この記事がどこかの誰かのお役に立てば幸いです。