[2023-12-12 更新]
Bootstrap などの CSS フレームワークではおなじみの Collapse (コラプス) ですが、いまでは HTML のマークアップだけでも実現できるのはご存じでしょうか。Collapse とは、タイトル部分をクリックすることで、そのコンテンツの表示・非表示を切り替える仕組みで、折り畳みウィジェットとも呼ばれます。
さらに、CSS フレームワークではおなじみの Accordion (アコーディオン) も HTML のマークアップだけで実現できるようになりました。
今回は折り畳みウィジェットやアコーディオンに必要な details
要素と summary
要素のマークアップ、JavaScript での扱い方、そして、スタイリングについて解説します。
折り畳みウィジェットとは
折り畳みウィジェットは、もともと英語で Disclosure widget と呼ばれているもので、英語圏では、expander、disclosure triangle などとも呼ばれます。折り畳みウィジェットはウェブだけでなく、デスクトップアプリや OS の機能としても良く見かけます。
ウェブ制作の業界では、人気の CSS フレームワークである Bootstrap の影響でしょうか、Collapse (コラプス) という名前のほうが良く知られているのかもしれません。また Bootstrap の Accordion(アコーディオン) も折り畳みウィジェットの派生と言えます。他には Vuetify のように Expansion panels という呼び方もあります。
details 要素と summary 要素の使い方
折り畳みウィジェットを HTML マークアップだけで作るには、details
要素と summary
要素を使います。これは説明を読むより見た方が早いでしょう。
<details>
<summary>詳細情報</summary>
<p>ここに詳細情報が入ります。</p>
</details>
すでにどのメジャーブラウザーでも details
要素と summary
要素はサポートされているため、見た目は異なるかもしれませんが、下に「▶ 詳細情報」と表示されているはずです。
詳細情報
ここに詳細情報が入ります。
そして「▶ 詳細情報」の部分をクリックすると、そのコンテンツが下に現れるはずです。実際にはスタイリングが必要になりますが、たったこれだけで折り畳みウィジェットが作れます。
以降、「▶ 詳細情報」の部分を「概要部」、コンテンツ部分を「詳細部」と呼びます。
details
要素と summary
要素から折り畳みウィジェットをどのように作られるのかを知っておきましょう。まず details
要素の中で最初に見つかった summary
要素を概要部とします。次に概要部として使われた summary
要素を除外した残りのコンテンツで詳細部を構成します。
もし details
要素の中に summary
要素がなければ、ブラウザーが適当な文言で概要部を勝手に作ります。実際には Chrome、Edge、Firefox、Safari で「▶ 詳細」となります。
これまでの解説を読んで、恐らく次のようなマークアップは許されるのかと勘違いするかもしれません。次のマークアップでは、details
要素の中で、概要部になるべき summary
要素が最後にマークアップされています。
<details>
<p>ここに詳細情報が入ります。</p>
<summary>詳細情報</summary>
</details>
実はこれでも期待通りに折り畳みウィジェットが作られます。しかし HTML 構文エラーです。HTML 仕様では、summary
要素は、親となる details
要素の最初の子要素でなければいけないと規定されているからです。
HTML 仕様上、ブラウザーの挙動としては summary
要素のマークアップ位置に柔軟性を持たせていますが、マークアップのルールとしては厳格に決められていますので、注意してください。
最初から展開したいなら open 属性
前述の実例をご覧の通り、details
要素で作った折り畳みウィジェットは、デフォルトでは折りたたまれた状態になります。これを展開した状態にしたいなら、open
属性を使います。
<details open>
<p>ここに詳細情報が入ります。</p>
<summary>詳細情報</summary>
</details>
以下に実例を掲載しますが、いかがでしょうか。すでに詳細部が展開した状態になっているはずです。
ここに詳細情報が入ります。
詳細情報
open
属性は論理属性です。値を持たず、属性が存在するか存在しないかだけで機能します。open="false"
や open="none"
とマークアップしても、折り畳みウィジェットは展開された状態になりますので注意してください。
JavaScript から開閉を制御する
open
属性を JavaScript から操作して折り畳みウィジェットの開閉状態を制御することができます。また、open
属性の状態を JavaScript から読み取ることもできます。次の例ではボタンを押すことで、折り畳みウィジェットの開閉状態を反転します。
<button id="b1">開閉</button>
<details id="w1">
<summary>詳細情報</summary>
<p>ここに詳細情報が入ります。</p>
</details>
document.getElementById('b1').addEventListener('click', () => {
const el = document.getElementById('w1');
el.open = !el.open;
}, false);
詳細情報
ここに詳細情報が入ります。
開閉のイベント
JavaScript から details
要素で作った折り畳みウィジェットの開閉のイベントをキャッチすることができます。折り畳みウィジェットが操作されると、details
要素の DOM オブジェクトで toggle
イベントが発生します。
次のサンプルは、details
要素の DOM オブジェクトに toggle
イベントのリスナーをセットしています。イベントを受け取ると、details
要素の開閉状態をコンソールに出力します。
<p id="s2">-</p>
<details id="w2">
<summary>詳細情報</summary>
<p>ここに詳細情報が入ります。</p>
</details>
document.getElementById('w2').addEventListener('toggle', (event) => {
if(event.target.open === true) {
document.getElementById('s2').textContent = '展開されました';
} else {
document.getElementById('s2').textContent = '折りたたまれました。';
}
}, false);
–
詳細情報
ここに詳細情報が入ります。
スタイリング
これまでのサンプルをご覧いただいた通り、ブラウザーのデフォルトスタイルはとてもそっけないもので、この状態のまま使うことはないでしょう。ここからは折り畳みウィジェットの CSS によるスタイリングを紹介します。
ブラウザのデフォルトスタイルでは折り畳みウィジェットの概要部と詳細部の境目が分かりませんので、背景と境界に色を付けてみましょう。
<details open>
<summary>概要部</summary>
<p>詳細部</p>
</details>
details {
background-color: #eeeeee;
border: 1px solid #dddddd;
}
details>summary {
background-color: #dddddd;
border: 1px solid #cccccc;
}
概要部
詳細部
details
要素のデフォルトスタイルの display
プロパティは block
のため、折り畳みウィジェットは横いっぱいに広がっているはずです。また、パディングが無いせいか、少し見づらいのではないでしょうか。少しパディングを調整してみましょう。
details {
...
padding: 0.5em;
}
details>summary {
...
padding: 0.5em;
}
概要部
詳細部
今度はあえてウィジェットを折りたたんだ状態にしていますが、期待とは少し違ってないでしょうか。折りたたんでいるにもかかわらず、details
要素のパディング領域が見えています。折りたたんだ状態なら、summary
要素だけを見せたいところです。そうなると、details
要素にパディングを入れないほうが良さそうです。マークアップも少し変えてみましょう。
<details open>
<summary>概要部</summary>
<div class="body">
<p>詳細部</p>
</div>
</details>
details {
background-color: #eeeeee;
border: 1px solid #dddddd;
}
details>summary {
background-color: #dddddd;
border: 1px solid #cccccc;
padding: 0.5em;
}
details>div.body {
padding: 0.5em;
}
概要部
詳細部
これで、ウィジェットを折りたたんだときには summary
要素しか見えなくなりました。しかし、どうしても気になるのは summary
要素にある三角のマークでしょう。このマークを制御しているのは、summary
要素の list-style-type
プロパティです。
details
要素に open
属性が存在するか否かで summary
要素の list-style-type
プロパティの値を切り替えれば、summary
要素のマークを自由に変更することができます。
details>summary {
...
list-style-type: "\1F60C";
}
details[open]>summary {
list-style-type: "\1F61D";
}
概要部
詳細部
Safari 以外のメジャーブラウザーなら、ウィジェットの概要部にスマイリーが表示されているのではないでしょうか。Safari の場合は残念ながらマークはデフォルトのままになります。ただし、macOS でも Chrome であれば期待通りにスマイリーが表示されるはずです。
name 属性でアコーディオンを作る
details
要素には name
属性をセットすることができます。name
属性の値が同じ details
要素は 1 つのグループとみなされてアコーディオンを形成します。このアコーディオンは、個々のウィジットを独立して開閉できるものではなく、1 つを開くと残りはすべて閉じるユーザーインタフェースです。英語ではこれを Exclusive accordion と呼ぶようです。
では、HTML マークアップを見てみましょう。
<div>
<details name="sample" open>
<summary>アコーディオン項目 #1</summary>
<div>
<p>1 つ目のアコーディオン項目の本文です。</p>
</div>
</details>
<details name="sample">
<summary>アコーディオン項目 #2</summary>
<div>
<p>2 つ目のアコーディオン項目の本文です。</p>
</div>
</details>
<details name="sample">
<summary>アコーディオン項目 #3</summary>
<div>
<p>3 つ目のアコーディオン項目の本文です。</p>
</div>
</details>
</div>
アコーディオン項目 #1
1 つ目のアコーディオン項目の本文です。
アコーディオン項目 #2
2 つ目のアコーディオン項目の本文です。
アコーディオン項目 #3
3 つ目のアコーディオン項目の本文です。
このサンプルには 3 つの details
要素がマークアップされています。すべての details
要素に name
属性がセットされていますが、いずれも値は "sample"
です。これら 3 つの details
要素が 1 つのグループを形成しています。1 つの項目を開けば、他の項目は閉じ、必ず 1 つしか開いていない状態にすることができます。
WHATWG HTML 仕様では、アクセシビリティ上の観点から、同じグループの details
要素は何かしらの要素 (section 要素など) でグループ化するべきと言っています。上記サンプルでは div
要素で囲んでいます。
上記サンプルでは 3 つの details
要素のうち 1 つだけに open
属性をマークアップしています。同じ name
属性をセットした details
要素の中で open
要素をマークアップしてもよいのは 1 つに限られますので注意してください。もし複数の details
要素に同じ値の name
属性をマークアップしたとしても、開いた状態でレンダリングされるのは最初の 1 つだけです。
一見、便利そうなアコーディオンではありますが、使いどころには注意しましょう。状況によってはユーザーにとって不便になるからです。たとえば比較検討に使われる情報なら、他が自動的に閉じてしまうのは困ります。基本的には、それぞれの項目が独立したものの場合に利用するのが良いでしょう。FAQ などでは役に立ちそうです。
この name 属性を使ったアコーディオンですが、2023 年 12 月現在、Chrome、Edge、Safari がサポートしています。Firefox ではまだ利用することができません。最新の情報は caniuse.com を参照してください。
まとめ
CSS フレームワークなどが作り出すウィジェットが優れている点を挙げるとしたら、開閉時のアニメーションでしょうか。残念ながら details
要素と summary
要素によるウィジェットには開閉時のアニメーションの機能は用意されていません。
個人的な好みを言うと、アニメーションは好きではないため、CSS フレームワークを使っていても開閉時のアニメーションはオフにしていました。そう考えると、少なくとも私にとっては details
要素と summary
要素によるウィジェットやアコーディオンで何ら困ることはありません。もし CSS フレームワークを使わない、または、使えない状況においては、きっと details
要素と summary
要素は役に立つことでしょう。
今回は以上で終わりです。最後まで読んでくださりありがとうございました。それでは次回の記事までごきげんよう。