もくじ
jQueryを使わずにJavaScriptでアコーディオンメニューを実装する方法を解説します。
HTML・CSS・JavaScriptのコードをコピペするだけで使える、アニメーション付きのアコーディオンの作り方を紹介します。
jQueryが使用できない環境でも、アクセシビリティに配慮したアコーディオンメニューを実装できるよう、コードを公開しています。
スムーズな開閉アニメーションも実装済みです。
アコーディオンをjQueryで実装する方法は以下の記事で紹介しています。
-   
- 【jQuery】アコーディオン(開閉ボタン)を実装する方法 - もくじ【サンプル】jQueryでアコーディオンメニューを実装【コピペOK】jQueryを使用したアコーディオンメニューの実装コード【サンプル】jQueryでアクセシビリティ対応済みのアコーディオンメニ ... 
アコーディオンをHTMLのみで実装する方法は以下の記事で紹介しています。
-   
- 【CSS不要】HTMLのみでアコーディオン(開閉ボタン)を実装する方法 - もくじ【サンプル】HTMLのみでアコーディオンメニューを実装【実装コード】HTMLのみでアコーディオンメニューを実装detailsタグとsummaryタグにCSS当ててデザインを調整【サンプル】CSS ... 
アコーディオンをHTMLとCSSのみで実装する方法は以下の記事で紹介しています。
-   
- 【HTML・CSS】アコーディオンメニューをHTMLとCSSのみで実装する方法 - もくじ単体用アコーディオン(折りたたみメニュー)【サンプル】単体用アコーディオン【コピペOK】HTML・CSSのみで単体用アコーディオンを実装単体用アコーディオンを複数利用する方法2段のアコーディオン ... 
【実装例】jQuery未使用のアコーディオンメニュー(開閉ボタン)のサンプル
Q. JavaScriptでアコーディオン(開閉ボタン)を実装する方法は?
A. 「【コピペOK】jQuery未使用のアコーディオンメニューの実装コード」より、HTML・CSS・JavaScriptをコピペすることでアコーディオン(開閉ボタン)を実装できます。
Q. はじめからアコーディオンを開いた状態にする方法は?
HTMLにis-activeを追加することで可能です。
class="accordion js-accordion"にis-activeを追加
【コピペOK】jQuery未使用のアコーディオンメニューの実装コード
下記HTML・CSS・JavaScriptをコピペすることでアコーディオンを実装することができます。
Copyをクリックするとコピーできます。
<div class="accordion js-accordion">  <div class="accordion-summary js-accordion-toggle">    <p class="accordion-ttl">Q. テキスト</p>    <div class="accordion-toggle-icon">      <span class="accordion-toggle-line"></span>      <span class="accordion-toggle-line"></span>    </div>  </div>  <div class="accordion-panel js-accordion-panel">    <div class="accordion-details">      <div class="accordion-details-inner">        <p class="accordion-txt">A. テキスト</p>        <p class="accordion-txt">※テキスト</p>      </div>    </div>  </div></div><div class="accordion js-accordion is-active">  <div class="accordion-summary js-accordion-toggle">    <p class="accordion-ttl">Q. テキスト</p>    <div class="accordion-toggle-icon">      <span class="accordion-toggle-line"></span>      <span class="accordion-toggle-line"></span>    </div>  </div>  <div class="accordion-panel js-accordion-panel">    <div class="accordion-details">      <div class="accordion-details-inner">        <p class="accordion-txt">A. テキスト</p>        <p class="accordion-txt">※テキスト</p>      </div>    </div>  </div></div>.accordion * {  box-sizing: border-box;}.accordion {  margin-bottom: 30px;  background: #ffefef;  border-radius: 5px;}.accordion-summary {  display: block;  position: relative;  width: 100%;  padding: 1em 3.2em 1em 2em;  font: inherit;  text-align: left;  background: transparent;  border: none;  cursor: pointer;}.accordion-summary:active {  background: transparent;}.accordion-ttl {  margin: 0;  font-size: 16px;}.accordion-toggle-icon {  position: absolute;  top: 50%;  right: 1.5em;  width: 1em;  height: 1em;  transform: translateY(-50%);}.accordion-toggle-line {  display: block;  position: absolute;  top: 50%;  left: 50%;  width: 0.8em;  height: 2px;  background: #333;}.accordion-toggle-line:nth-child(1) {  transform: translate(-50%, -50%);}.accordion-toggle-line:nth-child(2) {  transform: translate(-50%, -50%) rotate(90deg);  transition: 0.3s linear;}.accordion.is-active .accordion-toggle-line:nth-child(2) {  opacity: 0;}.accordion-panel {  display: none;}.accordion.is-active .accordion-panel {  display: block;}.accordion-details {  padding: 0 1.5em 1.5em;}.accordion-details-inner {  padding: 1.5em;  background: #fff;  border-radius: 5px;}.accordion-txt {  margin: 0;  font-size: 16px;}const accordionToggle = document.querySelectorAll('.js-accordion-toggle');accordionToggle.forEach(function (element) {  element.addEventListener('click', function () {    const accordion = element.closest('.js-accordion');    if (!accordion) return;    const accordionPanel = accordion.querySelector('.js-accordion-panel');    if (!accordionPanel) return;    slideToggle(accordionPanel, 500);  });});function slideUp(element, duration = 400) {  if (element.dataset.sliding === 'true') return;  element.dataset.sliding = 'true';  element.style.display = 'block';  element.closest('.js-accordion').classList.remove('is-active');  const height = element.offsetHeight;  element.style.height = height + 'px';  element.offsetHeight;  element.style.overflow = 'hidden';  element.style.transition = `height ${duration}ms ease`;  requestAnimationFrame(() => {    element.style.height = '0px';  });  setTimeout(() => {    element.style.display = 'none';    element.style.removeProperty('height');    element.style.removeProperty('overflow');    element.style.removeProperty('transition');    element.dataset.sliding = 'false';  }, duration);}function slideDown(element, duration = 400) {  if (element.dataset.sliding === 'true') return;  element.dataset.sliding = 'true';  element.closest('.js-accordion').classList.add('is-active');  element.style.removeProperty('display');  let display = window.getComputedStyle(element).display;  if (display === 'none') display = 'block';  element.style.display = display;  const height = element.scrollHeight;  element.style.height = '0px';  element.offsetHeight;  element.style.overflow = 'hidden';  element.style.transition = `height ${duration}ms ease`;  requestAnimationFrame(() => {    element.style.height = height + 'px';  });  setTimeout(() => {    element.style.removeProperty('height');    element.style.removeProperty('overflow');    element.style.removeProperty('transition');    element.dataset.sliding = 'false';  }, duration);}function slideToggle(element, duration = 400) {  const isActive = element.closest('.js-accordion').classList.contains('is-active');  if (isActive) {    slideUp(element, duration);  } else {    slideDown(element, duration);  }}【実装例】アクセシビリティ対応済みのアコーディオンメニュー(開閉ボタン)のサンプル
A. 「【コピペOK】アクセシビリティ対応済みのアコーディオンメニューの実装コード」より、HTML・CSS・JavaScriptをコピペすることでアクセシビリティ対応のアコーディオン(開閉ボタン)を実装できます。
class="accordion js-accordion"にis-activeを追加とaria-expanded="false"をaria-expanded="true"に変更、hidden="until-found"を削除することで可能です。
【コピペOK】アクセシビリティ対応済みのアコーディオンメニューの実装コード
下記HTML・CSS・JavaScriptをコピペすることでアコーディオンを実装することができます。
アクセシビリティ対応のアコーディオンには以下の属性が必要です。
| 属性 | 役割 | 
|---|---|
| id | 各アコーディオンの一意の識別子 | 
| aria-expanded | アコーディオンの開閉状態(true/false) | 
| aria-controls | 制御対象のパネルのID | 
| aria-labelledby | 読み上げソフト(スクリーンリーダー)が指定したIDの要素の内容を読んでくれる | 
| role="region" | パネルの役割を指定 | 
| hidden="until-found" | 初期状態での非表示設定。この属性は以下の特徴があります 
 | 
これらの属性により、スクリーンリーダーなどの支援技術を使用するユーザーがアコーディオンの状態を理解し、操作できるようになります。
hidden="until-found"のブラウザ別対応状況はこちら
hidden="until-found"がブラウザに対応していない場合、通常のhidden属性として解釈されます。
Copyをクリックするとコピーできます。
<div class="accordion js-accordion">  <button id="accordion-summary-1" class="accordion-summary js-accordion-btn" aria-expanded="false" aria-controls="accordion-panel-1">    <span class="accordion-ttl">Q. テキスト</span>    <span class="accordion-toggle-icon" aria-hidden="true">      <span class="accordion-toggle-line"></span>      <span class="accordion-toggle-line"></span>    </span>  </button>  <div id="accordion-panel-1" class="accordion-panel-other js-accordion-panel" role="region" aria-labelledby="accordion-summary-1" hidden="until-found">    <div class="accordion-details">      <div class="accordion-details-inner">        <p class="accordion-txt">A. テキスト</p>        <p class="accordion-txt">※テキスト</p>      </div>    </div>  </div></div><div class="accordion js-accordion is-active">  <button id="accordion-summary-2" class="accordion-summary js-accordion-btn" aria-expanded="true" aria-controls="accordion-panel-2">    <span class="accordion-ttl">Q. テキスト</span>    <span class="accordion-toggle-icon" aria-hidden="true">      <span class="accordion-toggle-line"></span>      <span class="accordion-toggle-line"></span>    </span>  </button>  <div id="accordion-panel-2" class="accordion-panel-other js-accordion-panel" role="region" aria-labelledby="accordion-summary-2">    <div class="accordion-details">      <div class="accordion-details-inner">        <p class="accordion-txt">A. テキスト</p>        <p class="accordion-txt">※テキスト</p>      </div>    </div>  </div></div>.accordion * {  box-sizing: border-box;}.accordion {  margin-bottom: 30px;  background: #ffefef;  border-radius: 5px;}.accordion-summary {  display: block;  position: relative;  width: 100%;  padding: 1em 3.2em 1em 2em;  font: inherit;  text-align: left;  background: transparent;  border: none;  cursor: pointer;}.accordion-summary:active {  background: transparent;}.accordion-ttl {  margin: 0;  font-size: 16px;}.accordion-toggle-icon {  position: absolute;  top: 50%;  right: 1.5em;  width: 1em;  height: 1em;  transform: translateY(-50%);}.accordion-toggle-line {  display: block;  position: absolute;  top: 50%;  left: 50%;  width: 0.8em;  height: 2px;  background: #333;}.accordion-toggle-line:nth-child(1) {  transform: translate(-50%, -50%);}.accordion-toggle-line:nth-child(2) {  transform: translate(-50%, -50%) rotate(90deg);  transition: 0.3s linear;}.accordion.is-active .accordion-toggle-line:nth-child(2) {  opacity: 0;}.accordion-details {  padding: 0 1.5em 1.5em;}.accordion-details-inner {  padding: 1.5em;  background: #fff;  border-radius: 5px;}.accordion-txt {  margin: 0;  font-size: 16px;}const accordionBtn = document.querySelectorAll('.js-accordion-btn');accordionBtn.forEach(function (element) {  element.addEventListener('click', function () {    const accordion = element.closest('.js-accordion');    if (!accordion) return;    const accordionPanel = accordion.querySelector('.js-accordion-panel');    if (!accordionPanel) return;    toggleAccordionPanel(accordionPanel, 500);  });});function openAccordionPanel(element, duration = 400) {  if (element.dataset.sliding === 'true') return;  element.dataset.sliding = 'true';  const accordion = element.closest('.js-accordion');  accordion.classList.add('is-active');  element.removeAttribute("hidden");  const height = element.scrollHeight;  element.style.height = '0px';  element.offsetHeight;  element.style.overflow = 'hidden';  element.style.transition = `height ${duration}ms ease`;  const accordionBtn = accordion.querySelector('.js-accordion-btn');  accordionBtn.setAttribute('aria-expanded', 'true');  requestAnimationFrame(() => {    element.style.height = height + 'px';  });  setTimeout(() => {    element.style.removeProperty('height');    element.style.removeProperty('overflow');    element.style.removeProperty('transition');    element.dataset.sliding = 'false';  }, duration);}function closeAccordionPanel(element, duration = 400) {  if (element.dataset.sliding === 'true') return;  element.dataset.sliding = 'true';  const accordion = element.closest('.js-accordion');  accordion.classList.remove('is-active');  const height = element.offsetHeight;  element.style.height = height + 'px';  element.offsetHeight;  element.style.overflow = 'hidden';  element.style.transition = `height ${duration}ms ease`;  const accordionBtn = accordion.querySelector('.js-accordion-btn');  accordionBtn.setAttribute('aria-expanded', 'false');  requestAnimationFrame(() => {    element.style.height = '0px';  });  setTimeout(() => {    element.style.removeProperty('height');    element.style.removeProperty('overflow');    element.style.removeProperty('transition');    element.dataset.sliding = 'false';    element.setAttribute('hidden', 'until-found');  }, duration);}function toggleAccordionPanel(element, duration = 400) {  const isHidden = element.hasAttribute('hidden');  if (isHidden) {    openAccordionPanel(element, duration);  } else {    closeAccordionPanel(element, duration);  }}Q & A
対応しています。
使用しているリセットCSSによっては、hidden属性にdisplay: none;が設定されている可能性があります。
hidden属性にdisplay: none;が設定されている場合、以下のように記述することで改善されることがあります。
[hidden]:not([hidden='until-found']) {
  display: none;
}
まとめ
- jQueryなしでアコーディオンを実装する方法を解説しました。
- アクセシビリティ対応のポイントも紹介しました。
- コピペで使えるHTML・CSS・JavaScriptのサンプル付きです。
アコーディオンをjQueryで実装する方法は以下の記事で紹介しています。
-   
- 【jQuery】アコーディオン(開閉ボタン)を実装する方法 - もくじ【サンプル】jQueryでアコーディオンメニューを実装【コピペOK】jQueryを使用したアコーディオンメニューの実装コード【サンプル】jQueryでアクセシビリティ対応済みのアコーディオンメニ ... 
アコーディオンをHTMLのみで実装する方法は以下の記事で紹介しています。
-   
- 【CSS不要】HTMLのみでアコーディオン(開閉ボタン)を実装する方法 - もくじ【サンプル】HTMLのみでアコーディオンメニューを実装【実装コード】HTMLのみでアコーディオンメニューを実装detailsタグとsummaryタグにCSS当ててデザインを調整【サンプル】CSS ... 
アコーディオンをHTMLとCSSのみで実装する方法は以下の記事で紹介しています。
-   
- 【HTML・CSS】アコーディオンメニューをHTMLとCSSのみで実装する方法 - もくじ単体用アコーディオン(折りたたみメニュー)【サンプル】単体用アコーディオン【コピペOK】HTML・CSSのみで単体用アコーディオンを実装単体用アコーディオンを複数利用する方法2段のアコーディオン ... 



