LoginSignup
0
0

More than 1 year has passed since last update.

【js】アコーディオンスニペット

Posted at

Vanilla JSで作るアコーディオン

多階層のアコーディオンも可能です。

See the Pen アコーディオン by __m-sato__ (@__m-sato__) on CodePen.

html

 <dl class="accordion_wrap">
		<div class="accordion_item">
			<dt class="accordion_title js-accordion-trigger">質問文などのテキストが入ります。</dt>
			<dd class="accordion_content">
				回答テキストが入ります。
			</dd>
		</div>
		<div class="accordion_item">
			<dt class="accordion_title js-accordion-trigger">多階層にもできます。</dt>
			<dd class="accordion_content">
				<dl class="accordion_wrap">
					<div class="accordion_item">
						<dt class="accordion_title js-accordion-trigger">多階層にもできます。</dt>
						<dd class="accordion_content">
							<dl class="accordion_wrap">
								<div class="accordion_item">
									<dt class="accordion_title js-accordion-trigger">質問文などのテキストが入ります。</dt>
									<dd class="accordion_content">
									回答テキストが入ります。
									</dd>
								</div>
							</dl>
						</dd>
					</div>
				</dl>
				<dl class="accordion_wrap">
					<div class="accordion_item">
						<dt class="accordion_title js-accordion-trigger">質問文などのテキストが入ります。</dt>
						<dd class="accordion_content">
							回答テキストが入ります。回答テキストが入ります。回答テキストが入ります。回答テキストが入ります。回答テキストが入ります。回答テキストが入ります。回答テキストが入ります。
						</dd>
					</div>
				</dl>
			</dd>
		</div>
	 </dl>

js-accordion-triggerクラスの次の兄弟要素をアコーディオンのコンテンツとして開閉している処理をjsで書いています。なのでjs-accordion-triggerクラスがアコーディオンスイッチ、次の兄弟要素が開閉される要素の構造で記述していただければokです。

sass

@charset "UTF-8";

/* 簡易リセットCSS */
* {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}

 /* アコーディオン全体 */
.accordion_wrap {
	max-width: 800px;
	margin: 0 auto;
	width: 95%;
}

 /* アコーディオン */
.accordion_item {
	border: 1px solid #ccc;
	margin-top: 10px;
}

 /* アコーディオンのタイトル */
.accordion_title {
	position: relative;
	padding: 15px 60px 15px 20px;
	font-weight: bold;
	cursor: pointer;
	 /* (+)アイコン */
	&::before,
	&::after {
		content: "";
		position: absolute;
		right: 20px;
		top: 0;
		bottom: 0;
		margin: auto 0;
		background-color: black;
		width: 20px;
		height: 2px;
		transition: transform ease 0.2s, opacity ease 0.2s;
	}
	&::after {
		transform: rotate(90deg);
	}
}
 /* アコーディオン展開時の(-)アイコン */
.accordion_title.is-active {
	&::before {
		transform: rotate(180deg);
	}
	&::after {
		transform: rotate(180deg);
		opacity: 0;
	}
}

 /* アコーディオンのコンテンツ */
.accordion_content {
	padding: 0 20px 15px 20px;
	display: none;
}

js


/* =================================================== */
// slideUp, slideDown, slideToggle関数を定義
/* =================================================== */

// 要素をスライドしながら非表示にする関数(jQueryのslideUpと同じ)
const slideUp = (el, duration = 300) => {
	el.style.height = el.offsetHeight + "px";
	el.style.transitionProperty = "height, margin, padding";
	el.style.transitionDuration = duration + "ms";
	el.style.transitionTimingFunction = "ease";
	el.style.overflow = "hidden";
	el.style.height = 0;
	el.style.paddingTop = 0;
	el.style.paddingBottom = 0;
	el.style.marginTop = 0;
	el.style.marginBottom = 0;
	setTimeout(() => {
		el.style.display = "none";
		el.style.removeProperty("height");
		el.style.removeProperty("padding-top");
		el.style.removeProperty("padding-bottom");
		el.style.removeProperty("margin-top");
		el.style.removeProperty("margin-bottom");
		el.style.removeProperty("overflow");
		el.style.removeProperty("transition-duration");
		el.style.removeProperty("transition-property");
		el.style.removeProperty("transition-timing-function");
	}, duration);
};

 // 要素をスライドしながら表示する関数(jQueryのslideDownと同じ)
const slideDown = (el, duration = 300) => {
	el.style.removeProperty("display");
	let display = window.getComputedStyle(el).display;
	if (display === "none") {
		display = "block";
	}
	el.style.display = display;
	let height = el.offsetHeight;
	el.style.overflow = "hidden";
	el.style.height = 0;
	el.style.paddingTop = 0;
	el.style.paddingBottom = 0;
	el.style.marginTop = 0;
	el.style.marginBottom = 0;
	el.offsetHeight;
	el.style.transitionProperty = "height, margin, padding";
	el.style.transitionDuration = duration + "ms";
	el.style.transitionTimingFunction = "ease";
	el.style.height = height + "px";
	el.style.removeProperty("padding-top");
	el.style.removeProperty("padding-bottom");
	el.style.removeProperty("margin-top");
	el.style.removeProperty("margin-bottom");
	setTimeout(() => {
		el.style.removeProperty("height");
		el.style.removeProperty("overflow");
		el.style.removeProperty("transition-duration");
		el.style.removeProperty("transition-property");
		el.style.removeProperty("transition-timing-function");
	}, duration);
};

 // 要素をスライドしながら交互に表示/非表示にする関数(jQueryのslideToggleと同じ)
const slideToggle = (el, duration = 100) => {
	if (window.getComputedStyle(el).display === "none") {
		return slideDown(el, duration);
	} else {
		return slideUp(el, duration);
	}
};

 /* =================================================== */
 // DOM操作
 /* =================================================== */
// Triggerを全て取得
const accordionTriggers = document.querySelectorAll(".js-accordion-trigger");
for (let accordionTrigger of accordionTriggers) {
	accordionTrigger.addEventListener("click", () => {
		const accordionContent = accordionTrigger.nextElementSibling
		slideToggle(accordionContent);
		accordionTrigger.classList.toggle("is-active");
	})
}

jqueryで書いた場合

$('.js-accordion-trigger').on('click', function() {
	$(this).toggleClass('is-active');
	$("+.accordion_content", this).slideToggle(100);
	return false;
})

jqueryでアコーディオンをする場合はこれだけです。html構造も同じのまま、
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>をheadタグ内に記述するなどしてjqueryを読み込ませて上記記述をすれば完了です。

htmlだけでもできる

	<details>
		<summary>質問文</summary>
		<p>回答文</p>
	</details>

これだけでも一応アコーディオンできます。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0