CommentOut

【javascript/CSS】クリックで開閉するアコーディオン表示の作り方 【javascript/CSS】クリックで開閉するアコーディオン表示の作り方

【javascript/CSS】クリックで開閉するアコーディオン表示の作り方

公開日:  最終更新日:

WEBデザインのスタンダードがモバイルファーストになってしばらく経ちましたが、アコーディオン表示は長いコンテンツを短くまとめたり、特定の人にしか関係性ないようなコンテンツを普段しまっておく手段として、非常に高い需要があります。

今回はそんなアコーディオン表示の作り方をご紹介します。

Javascriptを使ったアコーディオン表示のサンプル

まず、以下のサンプルを見てください。
青いボタンをクリックすると、アコーディオンエリアが開閉します。

See the Pen
アコーディオン表示の作り方
by Uilou (@uilou754)
on CodePen.0

これは余計な処理を省いた最もプリミティブなサンプルではないかなと思います。
これらはjavascriptによって、開閉しています。

Javascriptを使ったアコーディオン表示の作り方

まず、HTMLは以下のような構造を作ってください。

<div class="accordion">
		<div class="accordion__button">詳しくはこちら</div>
		<div class="accordion__content">
			  テキストが入ります。
		</div>
</div>

div.accordionがアコーディオン部分のコンテナーになります。
div.accordion__buttonが開閉操作のトリガーとなるボタンです。
そして、div.accordion__buttonにクリックイベントが発生すると、div.accordion__contentが開閉します。

アコーディオン表示を実現するためのJavascript:クリックイベント

まず最初に、開閉のトリガーとなるクリックイベントを検知します。
クリックイベントを検知しているのは、.on(‘click’)イベント部分です。

$(element).on('click', function() {
    // クリックされた時の処理を記述
});

上記のコードで、elementがクリックされた時に、function内部の処理を実行させることが出来ます。

今回のアコーディオンの例では以下のようになります。

$('.accordion > .accordion__button').on('click', function() {
    // クリックされた時の処理
});

div.accordionの中のdiv.accordion__buttonがトリガーとなるので、div.accordion__buttonを指定します。

アコーディオン表示を実現するためのJavascript:開閉動作

そして、開閉の動きの部分ですが、これもjavascriptで作ってしまうのが非常に楽です。

$(element).slideToggle();

これだけで、開閉処理ができます。

slideToggle()は、先ほどのonclickイベントのfunction()の中で実行されるため、$(element)の所には$(this)が使えます。いや、使うべきです。
なぜなら、アコーディオンブロックが同じページに2つ以上存在する時、普通にセレクタで指定していると両方反応してしまいます

以下のサンプルを触ってみてください。

See the Pen
アコーディオン表示が2つ以降ある場合
by Uilou (@uilou754)
on CodePen.0

セレクタで指定すると、同じページアコーディオンが2つ以上あると、全てのアコーディオンが条件に一致してしまうので、全部一緒に動いてしまうんです。
そのため、$(this)を使って、イベントが発生した要素だけを動かす必要があるんです。

ただし、$(this)だと取得できるのは、クリックされたボタンの方が取得されます。
でも、開閉したいのはボタンではなく、その下の要素ですよね?
そこで使うのが『.next()』です。これは兄弟要素を取得する関数です。

$(element).next(selector).slideToggle();

単純に『$(element).next()』だけでも次の要素を取得することができるのですが、『$(element).next(selector)』とすることで、selectorの条件に一致する兄弟要素を取得することができます。

HTMLの所で、ボタンとコンテンツをコンテナーの中に入れていたのは、この兄弟要素を検索する時に、共通のコンテナーの中に入ってた方が都合が良い(検索しやすい)からなんです。

さて、先ほどのクリック処理と組み合わせると、以下の通りです。

$(element).on('click', function() {
    $(element).next(selector).slideToggle();
});

ここまでで、簡単なアコーディオンは作れるようになりました。

Javascriptを使ったアコーディオン表示の完成形

さらに、開閉状態を表す『.is-open』をボタンにつけたり、外したりする処理や、開閉状態に応じて矢印が回転する処理などを付け加えた完成版を載せておきます。

See the Pen
Untitled
by Uilou (@uilou754)
on CodePen.0

これでアコーディオンは完璧ですね。

Javascriptを使っても、そんなに複雑ではないですが、Javascriptは全くわからん!という人向けにCSSだけでアコーディオンを作る方法もご紹介します。

CSSのみで作るアコーディオン表示のサンプル

中には「Javascriptは使いたくない!CSSだけで作れる方法を教えて!」という方もいらっしゃると思うので、CSSだけでアコーディオン表示を作る方法も教えます。

See the Pen
Untitled
by Uilou (@uilou754)
on CodePen.0

CSSのみで作るアコーディオン表示の作り方

Javascriptでアコーディオン表示を作った時には、Javascriptを使ってclassの付け外しを行いましたが、CSSだけの場合、classの操作ができません

しかし、アコーディオンには『開いた状態』と『閉じた状態』があります。
これはマウスホバーなどのイベントとは関係なく、『状態』を保持しておく必要があるということです。

このようなイベント外の『状態』を持たせることは、CSSの苦手とすることですが、それを実現するために使うのが、『チェックボックス』です。

チェックボックスにも『チェック状態』と『チェックされていない状態』が存在し、マウスが離れただけでは状態変化が起きません。再度クリックされるまで状態を保持し続ける特性があります。

もし、あなたが『Javascriptを使わずに色んな動きを作れるようになりたい』と思っているのであれば、これはよく覚えておいてほしいのですが、『状態』を保存しておく必要がある場合にはチェックボックスを活用するということです。
なので、今回もこれを利用します。

以下のHTMLを見てください。

<div class="accordion">
		<input type="checkbox" id="accordion-1" class="accordion__status" />
		<label class="accordion__button" for="accordion-1">電車でお越しの方</label>
		<div class="accordion__content">
			    ○○線○○駅で降りて、駅のロータリーで○○行きのバスに乗車してください。<br>
			    ○○バス停で降りて、西に5分ほど歩くと到着です。
		</div>
</div>

注目すべきはinputとlabelです。
inputはチェックボックスです。inputのid属性labelのfor属性には同じ値が入っています。
こうすることで、labelがクリックされた時でも、inputの状態が切り替わるようになります。

そして、以下のCSSを見てください。

.accordion {
	display: block;
	margin: 15px 0px;
	overflow: hidden;
	border-radius: 10px;
}
.accordion > .accordion__status {
	display: none;
}
.accordion > .accordion__button {
	display: block;
	padding: 10px 20px;
	position: relative;

	color: white;
	font-size: 16px;
	font-weight: 500;
	background: #30b0ff;
	
	&::before {
		display: block;
		width: 8px;
		height: 8px;
		position: absolute;
		top: 50%;
		right: 25px;

		content: '';
		border-top: 3px solid white;
		border-right: 3px solid white;
		transform: translateY(-75%) rotate(135deg);
	}
}
.accordion > .accordion__content {
	display: block;
	padding: 0px 20px;
	height: auto;
	max-height: 0px;
	border-left: 1px solid #30b0ff;
	border-right: 1px solid #30b0ff;
	border-bottom: 1px solid #30b0ff;
	border-bottom-left-radius: 10px;
	border-bottom-right-radius: 10px;
	transition: padding 1s ease, max-height 1s ease;
}
.accordion > .accordion__status:checked + .accordion__button::before {
	transform: translateY(-25%) rotate(-45deg);
}
.accordion > .accordion__status:checked + .accordion__button + .accordion__content {
	padding: 10px 20px;
	height: auto;
	max-height: 100px;
}

先ほど
inputのclassにはaccordion__statusが
labelのclassにはaccordion__buttonが付いていましたね。

.accordion > .accordion__status {
	display: none;
}
.accordion > .accordion__button {
	display: block;
	padding: 10px 20px;
	position: relative;

	color: white;
	font-size: 16px;
	font-weight: 500;
	background: #30b0ff;
}

inputタグ(チェックボックス)がdisplay: none;により、非表示化されています。
これによって、以下の状態になります。

  • チェックボックスを使っているが表示されない
  • チェックボックスをクリックしなくてもlabelをクリックするとチェックボックスの状態が切り替わる

これはinputタグがプログラミングの変数のような状態になっていることを指します。

あとはチェックボックスの状態を見て、チェックされていなければコンテンツをたたみ、チェックされていればコンテンツを表示するだけです。

.accordion > .accordion__content {
	display: block;
	padding: 0px 20px;
	display: block;
	padding: 0px 20px;
	height: auto;
	max-height: 0px;
	border-left: 1px solid #30b0ff;
	border-right: 1px solid #30b0ff;
	border-bottom: 1px solid #30b0ff;
	border-bottom-left-radius: 10px;
	border-bottom-right-radius: 10px;
	transition: padding 1s ease, max-height 1s ease;
}
.accordion > .accordion__status:checked + .accordion__button + .accordion__content {
	padding: 10px 20px;
	height: auto;
	max-height: 100px;
}

この部分ですね。

ただし、ここでも注意点があります。
CSSのheightは0pxとautoではアニメーションしません。
そのため、どうするかというと、heightはautoのまま変更せず、max-heightをちょっと大きめに定義しておき、たたむ時に0pxにすることで、heightをアニメーションさせることができます

やはり、アコーディオンは1ページで複数出てくる可能性があるので、他の場所に影響を与えないように、クラス名のみではなく、兄弟要素参照(.classname + .classname)で指定してあげましょう。

宣伝
WordPressサイトのテンプレート編集やトラブル対応、バグ修正、簡単なJavascriptの作成(カルーセルやバリデーション等)など、小規模なスポット対応を受け付けております。
もしお困りごとがありましたら、お問い合わせフォームよりご相談ください。

この記事を書いた人

uilou

uilou

プログラマー

基本的に、自分自身の備忘録のつもりでブログを書いています。 自分と同じ所で詰まった人の助けになれば良いかなと思います。 システムのリファクタリングを得意としており、バックエンド、フロントエンド、アプリケーション、SQLなど幅広い知識と経験があります。 広いだけでなく、知識をもっと深堀りしていきたいですね。