今回はJavaScriptを使って
クリックで要素の表示・非表示を切り替える
通称「アコーディオン」を作っていきます。
まずは完成形はコチラ
See the Pen Untitled by subaru (@subaru_works) on CodePen.
「ここをクリック!」と書かれた部分をクリックすると、
その下に要素がニュッとアニメーションで表示されます。
もう一度クリックすると、再度アニメーションで要素が非表示になります。
HTML
<div class="acc-handle">
…クリックする要素...
</div>
<div class="acc-body">
…アニメーションする要素...
</div>
HTMLはクリックする要素の .acc-handle と
アニメーションする要素の .acc-body を兄弟要素として作成します
それぞれの要素の中身は基本的自由に設定してOKです。
ここで重要なのでは、クリックする要素とアニメーションする要素を隣同士の要素にすることです。
CSS
.acc-handle {
width: 600px;
padding: 1rem;
cursor: pointer;
* {
pointer-events: none;
}
}
.acc-body {
display: none;
width: 600px;
overflow: hidden;
}
こちらは最低限のCSSを抜き出したものになります。
クリックする要素の .acc-handle は、横幅の指定とカーソルの指定
そして、子要素に様々な要素が追加されることを見越して
クリックイベントを制御する pointer-events: none; を設定しています。
これらは無くても動作はします。
アニメーションする要素の .acc-body は、初期表示は「非表示」にしたいので
display: none; としておきます。
また、要素の中身が枠外に表示されないように overflow: hidden; もかけておきます。
JavaScript
いちばん重要なのはJavaScriptです。
const accHandle = document.querySelector(".acc-handle");
accHandle.addEventListener("click", (event) => {
const accbody = event.target.nextElementSibling;
event.target.classList.toggle('is-open');
slideToggle(accbody, 500);
})
まずはクリック時の挙動です。
.acc-handle にイベントリスナーを登録しています。
4行目では、クリックされた要素の兄弟要素を取得して
accbody としておきます。
次の行では、クリックされた要素に is-open のクラスを追加
これはCSSで見た目を変更するために追加しています。
そして、6行目で slideToggle() という別の関数を呼び出しています。
実際のアニメーションはこの関数内で行われています。
アニメーションを実行している関数
アニメーションを実行している関数の中身はこちらです
// slideUp
function slideUp(target, duration = 500) {
target.style.transitionProperty = 'height';
target.style.transitionDuration = duration + 'ms';
target.style.height = `${target.offsetHeight}px`;
target.offsetHeight;
target.style.height = '0';
window.setTimeout(() => {
target.style.display = 'none';
// スタイルをクリア
['height', 'transition-duration','transition-property']
.forEach(prop => target.style.removeProperty(prop));
}, duration);
}
まずは、「閉じる」アニメーションです。
jsで変更させる要素の height を target.offsetHeight で取得しておき
setTimeout を使ってアニメーションを時差で発生させます。
実行しているのは CSSの transition でのアニメーションと同じですが、
発火タイミングをずらすことでCSSだけでは高さを取れない問題を回避しています。
お次は「開く」アニメーション
// slideDown
function slideDown(target, duration = 500) {
target.style.removeProperty('display');
let display = getComputedStyle(target).display;
if (display === 'none') display = 'block';
target.style.display = display;
const height = target.offsetHeight;
target.style.height = '0';
target.offsetHeight;
target.style.transitionProperty = 'height';
target.style.transitionDuration = `${duration}ms`;
target.style.height = `${height}px`;
window.setTimeout(() => {
['height', 'transition-duration','transition-property']
.forEach(prop => target.style.removeProperty(prop));
}, duration);
}
全体の流れは先程の閉じる動作と同じです。
要素の高さを取得してから時差で transition を起こして
高さアニメーションが発火するようにしています
開く、閉じるの挙動を作ることができました
クリックごとに呼び出す「開く」と「閉じる」を判定して
呼び出す関数を自動で変えるように「トグル」の設定を行います。
// slideToggle
function slideToggle(target, duration = 500) {
if (getComputedStyle(target).display === 'none') {
slideDown(target, duration);
} else {
slideUp(target, duration);
}
}
要素が「非表示」の状態であれば slideDown() を呼んで要素を開きます。
そうでない場合は slideUp() を呼んで、要素を閉じます。
完成
以上がJavaScriptで「アコーディオン」を作るほう法でした!
実は、こんなにややこしくJSのコードを書かなくても実行できる方法があります
それは…
jQueryを使うこと!
jQueryを読み込んでいれば、jQueryであらかじめ設定されているslideUp()
、slideDown()
、slideToggle()
で簡単に指定すことができます。
じゃあjQuery使えばいいじゃない?
と思いますよね。
プロジェクト内でjQueryを利用する要素が多い場合や
メンテナンスの頻度が低い場合は
jQueryを読み込んで利用するのでもアリだと思います
しかしjQueryは便利な半面、ライブラリ自体が重くなる場合があります。
これはページ表示時にもたつく原因になる場合もります。
また、jQueryのバージョンの管理が大変になる場合があるため
近年ではjQueryを使わない場面のほうが多くなってきました。
プロジェクトの性質に合わせてjQuery を利用するのか
JavaScriptで実装するのか…選べるようになると便利かと思います。
まとめ
というわけで、今回はJavaScriptでアコーディオンを実装する方法について紹介しました。