折りたたみJS

HTMLソース側を極力汚さない折りたたみJavaScript

Published on

本ページで示すのは、良くあるJavaScriptによる折りたたみをJavaScriptとDOMとCSSで実現する手順である。jQueryなどの外部ライブラリを必要とせず、このスクリプト単独で動作する。

折りたたみというのは、ある要素をクリックすると隠れていた部分が見え、もう一度クリックするとまた隠れるというヤツである。

demo

例えばこんな感じ

HTMLソース側はclassを付与するだけにとどめ、クリーンでStrictなHTMLコーディングを保ったまま実現できるよう配慮している。また、JavaScriptを切った環境では、要素は折り畳まれず、中身も読むことができるようになっている他、キーボードで操作している場合の対処もしているので、それなりにアクセシビリティも確保してあると言える。

あと、いちいちid振らなくてもいいあたりが良いんじゃないかと思う。

このスクリプトは、以下のブラウザで正常に作動することが確認されている。

このページは、HTMLとCSSの書き方は分かっているが、JavaScriptはそんなに得意ではない(私のような)人向けにTipsとして書いたものだ。

さらに簡潔にするためにtrigger要素に何も書かなくても良いように改良しました。

ソース

まず、以下に最小限の基本ソースコードを示す。

HTML

<element class="show">
    <element class="trigger">trigger</element>
    <element class="target">target</element>
</element>

# "element" は要素の代表。実際にはどの要素でも可

JavaScript

外部ファイル(推奨)にするか、head要素内に書く。

// initialize on page load
window.onload = initExpand;

// toggle class when trigger is clicked
function toggleExpand(t) {
    for (var i=0; i<3; i++) {
        var t = t.parentNode

        if (t.className == 'hide') {
            t.className = 'show';
            break;
        } else if (t.className == 'show') {
            t.className = 'hide';
            break;
        }
    }
}

// initialize
function initExpand() {
    var e = document.getElementsByTagName('*');

    for (var i=0; i<e.length; i++) {
        // change all show classes to hide
        if (e[i].className == 'show') {
            e[i].className = 'hide';
        }
        
        // set JavaScript triggers
        if (e[i].className == 'trigger') {
            e[i].setAttribute('onclick',   'toggleExpand(this)');
            e[i].setAttribute('onkeypress','toggleExpand(this)');
        }
    }
}

window.onloadを使っているので他のスクリプトとバッティングする場合はそれぞれ対処すること。

CSS

.trigger      { cursor:pointer }
.hide .target { display:none }

解説

該当部分のHTMLは以下のような構造になっている。

[.show←→.hide [.trigger] [.target]]
モデル図

基本は、triggerをクリックすることによりそれを包括する.showと.hideが書き変わるという単純なものだ。

以下便宜上、triggerをクラスとして持つ要素をtrigger、targetをクラスとして持つ要素をtargetと呼ぶ。

詳細

HTMLファイルが読み込まれると、まずinitExpand()が作動し、HTML中のshowクラスをhideに書き換える。コレにより、JavaScriptが有効な場合のみ折りたたまれ、初期状態では中身が見えなくなる。さらにtriggerにonclick属性とonkeypress属性を付与しクリッカブルなボタンとして機能するようにする。

triggerをクリックするとtoggleExpand()が作動し、triggerの親要素、またはその更に親の要素のクラスがhideかshowのものを上位3階層分まで探しにいく。見つけると、そのクラスがhideならshowへ、showならhideに書き変える。CSS側で.hide .targetの場合をdisplay:noneにしてあげれば、targetは親要素がhideの間非表示となる。

この折りたたみセットは1ページ中何回出現しても構わない。

CSSで.triggerにはtext-decoration:underlineなどクリッカブルなスタイルを付与すると良い。triggerにshowとhideの時で異なったスタイルを提供することも可能である。

注意点としては、このスクリプトではshowクラスを付与する要素に他のクラスを併記すること<div class="show section">など)はできない。

使用例

demo

このようにtrigger(この場合 "demo" を内容とするh2要素)をクリックするとtargetp要素)が表示される。また、開いてる状態でtriggerを再度クリックすると、また折り畳まれ、targetは非表示になる。

このときtriggerも.hideと.showで別々のスタイルを付与すれば、開いているときと閉じているときでスタイルが変化する。

HTML

<div class="show">
    <h2 class="trigger">demo</h2>
    <p class="target">このようにtrigger …略… は非表示になる。</p>
    <p class="target">このときtriggerも …略… スタイルが変化する。</p>
</div>

CSS

.hide .target        { display:none }

      .trigger       { color:#069 ; cursor:pointer }
      .trigger:hover { color:#c33 }
      .trigger:after { content:url(hide.png) ; padding-left:0.3em }
.hide .trigger:after { content:url(show.png) }

著作権は破棄していませんが、使用、改変は自由です。適当にいじって使って下さい。