2016/09に公開
jQueryのslideToggleを使ったアコーディオンと関連した小技をご紹介します。
電子部品とか多少でも扱ったことのある方は「トグルスイッチ」など「トグル」という言葉を聞いたことがあると思います。「トグル」とは一般的に同じ操作によって二つの状態を交互に切り替えられるような仕組みのことをいいます。プログラミングの世界でも聞くことがある言葉です。
各見出し部分をクリックすると開閉します。
IE7/8でも動作します(ただし、webフォントを使っているので、IE7では表示されない部分があります)。
<dl> <dt>見出し1</dt> <dd>内容1(テキストや画像など)</dd> <dt>見出し2</dt> <dd>内容2(テキストや画像など)</dd> <dt>見出し3</dt> <dd>内容3(テキストや画像など)</dd> </dl>
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
webページを読み込んだときに表示しておく見出し(dt)と非表示にしておくその内容(dd)をdlタグを利用して組んでおきます。
dt{
cursor: pointer; /* PCの場合クリックできる部分と分かりやすいように、マウスオーバーでポインターになるように設定。*/
/*何もしていないときの見出しの設定*/
}
dt.open{
/*アコーディオンを開いたときの見出しの設定*/
}
dd{
display: none; /*内容部分は最初非表示にしておく*/
/*アコーディオンを開いたときの内容部分の設定*/
}
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
アコーディオンを開閉したときの状態をそれぞれcssで設定しておきます。
サンプルの場合は、背景色を変えるようにしました。
最初に読み込んだときに開いておきたい場合は、(このサンプルなら)該当するddタグをdisplay: block;にしておきます。
アコーディオンはこのようなシンプルなコードで実現できます。
$(function(){
$('dt').on('click', function() {
$(this).next().slideToggle();
$(this).toggleClass('open');
});
});
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
dtタグをクリックするたびに、クリックしたdtタグ(this)のすぐ次に来るタグ(next() = dd)を上下にスライドさせています。
その際、クリックしたdtタグ(this)にclass[open](開いたときの見出しの設定)を追加したり削除したりさせます。
slideToggleの()内では、開閉のスピードを設定したり、コールバック関数を追加できたりします。
アコーディオンが開いた(閉じた)直後に何らかの処理を加えたい場合などにはコールバック関数で処理を追加してみてください。
htmlの構造・cssは変更していません。
上のコードに処理を追加して、アコーディオンの開閉の状態によって表示を変えます(ここではdtタグのテキストを変えます)。
$(function(){
$('dt').on('click', function() {
$(this).next().slideToggle();
$(this).toggleClass('open');
var check = $(this).attr('class');
if(check.indexOf('open') != -1) $(this).text('クリックして閉じる');
else $(this).text('クリックして開く');
});
});
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
クリックしたdtタグ(this)のclass属性に[open]が含まれるかどうかで開閉の状態を検出し、テキストを差し替えます。
htmlの構造・cssは変更していません。
最初のコードにsiblingsを使った処理を追加して、見出しのどれかをクリックしてアコーディオンをクリックすると、他は閉じるようにします。
$(function(){
$('dt').on('click', function() {
$(this).next().slideToggle();
$(this).toggleClass('open');
$(this).next().siblings('dd').slideUp();
$(this).siblings('dt').removeClass('open');
});
});
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
クリックしたdtタグ(this)の次のタグ(ddタグ)の兄弟要素で指定したタグ(thisの次のddタグ以外のddタグ)に対してslideUp(開いてある内容部分を閉じる)処理を追加し、さらにクリックしたdtタグ(this)以外のdtタグからclass[open]を削除する処理を追加しています。
スマートフォンなどでメニューを常に表示しておくと専有面積が大きすぎて邪魔なため、あらかじめ非表示にしておいてタップで開閉してもらったりすることがあると思います。
その際、メニューを開いたときのトリガー以外の部分をタップしてもメニューを閉じられるとタップ面積が広い分、操作しやすくなるかもしれません。
htmlの構造はdt・ddタグをそれぞれ一つずつにしただけです。cssは変更していません。
closestを用いて、アコーディオン部分以外をタップ(クリック)しても閉じるようにします。
$(function(){
$('dt').on('click', function() {
$(this).next().slideToggle();
$(this).toggleClass('open');
});
$(document).on('click', function(evt){
if( !$(evt.target).closest('dt, dd').length ){
$('dd').slideUp();
$('dt').removeClass('open');
}
});
});
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
htmlページのどこかをクリックしたら、アコーディオンを閉じる処理を追加しています。その際、closestをつかってアコーディオン部分を除くようにしています。
例えばスマートフォンで画像のキャプション(説明文)が長すぎるとスクロールが長くなるため、一行だけ表示して続きを読みたい人だけタップしてみてもらえればいいかなぁという場合に、slideToggleでは難しいので、他の方法を探ります。
キャプション部分をクリックすると開閉します。
IE7/8でも動作します(ただし、webフォントを使っているので、IE7では表示されない部分があります)。
このサンプルで使用している画像は、ダミー画像を生成するPlacehold.jpを利用しております。ご利用の際は提供元の利用規約をよく読んでご利用ください。
<figure>
<img src="画像のパス" alt="">
<figcaption>画像の説明</figcaption>
</figure>
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
想定として画像のキャプションということにしていますが、状況はこれに限りません。従って、使用するタグもfigcaptionに限りません。
同一ページにアコーディオンにするfigcaptionとしないfigcaptionが混在する場合は、アコーディオンにするものを識別できるように、figcaptionタグやその親タグなどにセレクタとして任意のclass名やid名をつけてください。
figcaption{
overflow: hidden;
cursor: pointer; /* PCの場合クリックできる部分と分かりやすいように、マウスオーバーでポインターになるように設定。*/
/*その他必要な装飾*/
}
figcaption.open{
/*必要であればキャプションを開いたときの装飾*/
}
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
一行だけ表示した際に余計なものが表示されないよう、figcaptionにoverflow: hiddenを設定しておきます。
ここで初期値としてのキャプションの高さをcssで指定してしまわないことがコツです。
$(function(){
var dh = '1.5em'; //デフォルトの高さ
var figcap = $('figcaption');
var h= new Array(); //figcaptionの高さを格納する配列
figcap.each(function(index) { //ページ内に複数のfigcaptionタグがある場合はすべての高さを控えておく
h.push($(this).innerHeight() + "px");
});
figcap.css('height', dh); //最初に一度すべてのfigcaptionの高さを一行分の高さ(デフォルトの高さ)にしておく
figcap.on('click', function() {
var index = figcap.index(this);
var thisClass = $(this).attr('class');
if(thisClass.indexOf('open') != -1){
$(this).stop().animate({height:h[index]},'fast');
$(this).addClass('open');
} else {
$(this).stop().animate({height:dh},'fast');
$(this).removeClass('open');
}
});
//おまけ(リサイズしたらリロードする)
var timer = false;
$(window).on('resize', function(){
if (timer !== false) { //リサイズ中に何度も処理が行われるのを防ぐ
clearTimeout(timer);
}
timer = setTimeout(function() {
location.reload();
}, 20);
});
});
※黒い部分をダブルクリックするとソースを選択できるので、コピーして使ってください。
最後のはおまけです。ページ全体をリロードするのは美しくないと思うので、他に良い方法があったらそちらの処理を行ってください。
また、この処理をすることで古いブラウザでは不具合があるかもしれないので、古いブラウザではこの処理をしないようにするなど、工夫が必要かもしれません。
ここまで、さんざんアコーディオンを実現するテクニックをご紹介してきましたが、コーディングのテクニックよりも何よりも、デザインするよりもっと以前に、考えることがあります。
そのページでアコーディオンを使うことが、本当に良いことなのか?
なぜ、そこでアコーディオンなのか?
もしかしたら、1ページにまとめたいコンテンツの量が多すぎて、スクロールが長すぎるからちょっとでも短くしたくて、アコーディオンを導入するのかもしれません。
もしそうなら、本当にそれがユーザーのためになるのか?そのページで一番大事なことは伝えられるのか?
デザイン・設計に入る前に、仕様書段階で考えてみてください。
ファーストビューでアコーディオンが全部(または一部)閉じていれば、隠れている情報はユーザーにはわかりません。それは気付かれなくても良いような情報ですか?
アコーディオンの仕組みをとっさに理解できるユーザーばかりではありません。クリック(タップ)したくなるようなデザインで補完できますか?
デバイスの違いは考慮しましたか?アコーディオンをPCで操作するのとスマートデバイスで操作するのでは、ユーザーのストレスは違ってくるはずです。
そもそも、今時の(そのwebページのターゲット)ユーザーはスクロールをそんなにめんどくさく感じていないかもしれません。むしろアコーディオンをいちいちクリック(タップ)する方が面倒かもしれませんよ?
いちいち開いてみたけれど、そのユーザーにとっては大したことのない情報だったとき、がっかり感・徒労感でユーザーの心証を悪くしませんか?
デザインや技術を駆使して、ある程度の問題は解決できるかもしれません。でも、本当にそのページでアコーディオンを使うことがベストの方法か、もっと違う方法があるのではないか、導入前に考えてみてください。
そして、導入後も考え続けてください。最新の技術(トレンド)、デザイナーやコーダーやシステム屋さんなどそのページに携わる人たちの意見、ユーザーの反応なども鑑みて、もっと良い方法を探り続けてください。
ご紹介した記事は、恒久的な示唆も含まれていれば、記事が書かれた時点でのトレンド的な内容のものもあります。あくまでも参考にとどめて、今現在の業界のトレンドはどうなのか、制作しているwebページにあてはまることなのか、何よりユーザーにとって見やすいか、使いやすいか、大事なことが伝わる(目的の行動に誘導できる)のかといったことを優先的に考えてください。