detailsとsummaryタグでtoggleを作る

今回の目的はdetailssummaryを使ってtoggleを作ろうと思います。あまりdetailssummaryはうまく使われていないことが多い。HTMLのデフォルトのUIでtoggleが作れる優れものになります。

toggleはスライドのアニメーションで動くものを作成します。
jQueryのslideToggleのイメージがつきやすいと思います。

HTMLテンプレート

<details class="c-toogle">
  <summary>Toggleの開閉ボタン</summary>
  <div class="c-toogle_body">
      <!-- Toggleの内容 -->
  </div>
</details>

JavaScriptテンプレート

document.addEventListener("DOMContentLoaded", () => {
  const TOGGLE_SELECTOR = ".c-toggle";
  const CONTENT_SELECTOR = ".c-toogle_body";
  const ANIMATION_SETTINGS = {
    duration: 300,
    easing: "ease-out",
  };

  const generateKeyframes = (element, isOpening) => {
    const height = `${element.scrollHeight}px`;
    return isOpening
      ? [
          { height: "0", opacity: 0 },
          { height, opacity: 1 },
        ]
      : [
          { height, opacity: 1 },
          { height: "0", opacity: 0 },
        ];
  };

  const runAnimation = (element, isOpening) => {
    return element.animate(
      generateKeyframes(element, isOpening),
      ANIMATION_SETTINGS
    );
  };

  const setDetailsState = (details, isOpen) => {
    if (isOpen) {
      details.setAttribute("open", "");
    } else {
      details.removeAttribute("open");
    }
  };

  const setupToggle = (details) => {
    const summary = details.querySelector("summary");
    const content = details.querySelector(CONTENT_SELECTOR);

    if (!summary || !content) {
      console.warn("Required elements not found", details);
      return;
    }

    summary.addEventListener("click", (event) => {
      event.preventDefault();
      const isOpening = !details.hasAttribute("open");

      if (isOpening) {
        setDetailsState(details, true);
      } else {
        content.style.height = `${content.scrollHeight}px`;
        content.offsetHeight; // Trigger reflow
      }

      const animation = runAnimation(content, isOpening);

      animation.onfinish = () => {
        if (isOpening) {
          content.style.height = "auto";
        } else {
          setDetailsState(details, false);
          content.style.height = "";
        }
      };
    });
  };

  const init = () => {
    const allDetails = document.querySelectorAll(TOGGLE_SELECTOR);
    allDetails.forEach(setupToggle);
  };

  init();
});

JavaScriptのコード説明

  1. 初期化:
    • DOMコンテンツが読み込まれた後に実行されます。
    • .c-toggleクラスを持つ全ての要素に対してトグル機能をセットアップします。
  2. トグル機能:
    • ユーザーがsummary要素をクリックすると、関連するコンテンツが開閉します。
    • 開閉の状態はdetails要素のopen属性で管理されます。
  3. アニメーション:
    • コンテンツの開閉時にスムーズなアニメーションを適用します。
    • Web Animations APIを使用して、高さと不透明度のアニメーションを実現しています。
  4. キーフレーム生成:
    • generateKeyframes関数で、開閉状態に応じたアニメーションのキーフレームを動的に生成します。
  5. アニメーション実行:
    • runAnimation関数で、生成されたキーフレームを使用してアニメーションを実行します。
  6. 状態管理:
    • setDetailsState関数で、details要素のopen属性を適切に設定または削除します。
  7. トグルのセットアップ:
    • 各トグル要素に対して、クリックイベントリスナーを設定します。
    • クリック時に、コンテンツの開閉状態を切り替え、適切なアニメーションを実行します。
  8. アニメーション完了後の処理:
    • 開く場合: コンテンツの高さをautoに設定し、自然な高さを維持します。
    • 閉じる場合: open属性を削除し、高さのスタイルをリセットします。
  9. エラー処理:
    • 必要な要素(summary.c-toogle_body)が見つからない場合、警告をコンソールに出力します。

このコードは、アコーディオンやエクスパンダブルセクションなど、開閉可能なUI要素を実装する際に使用できます。アニメーションを用いることで、ユーザーエクスペリエンスを向上させています。

Contact

どんなことでも、お気軽にお問合せください

お問い合わせフォーム