【jQuery】初回アクセス時のみアコーディオンを開く完全ガイド|sessionStorage・localStorage・Cookie比較

FAQページのアコーディオンを「初めて訪れたユーザーには開いた状態で見せたい」というUX要件はよくあります。実装の鍵はブラウザの状態保存機能(sessionStorage・localStorage・Cookie)で「すでに訪問済みかどうか」を記録することです。

この記事でわかること

  • sessionStorage / localStorage / Cookie それぞれで「初回判定」を実装する方法
  • 3つの保存方法の違いと用途別の選び方
  • アコーディオンの開閉状態を保存して次のページ訪問時に復元する方法
  • 複数のアコーディオン項目の状態をまとめて保存・復元する実装
  • URLハッシュで特定の項目を強制的に開く方法
スポンサーリンク

1. sessionStorageで実装(タブを閉じるとリセット)

sessionStorage はブラウザタブを閉じるとデータが消えます。「同じタブで2回目以降のページ遷移では閉じた状態にしたい」場合に最適です。

<div class="accordion">
  <div class="ac-header">Q1. 返品・交換はできますか?</div>
  <div class="ac-body">商品到着後7日以内であれば返品・交換を承ります。</div>
</div>
<div class="accordion">
  <div class="ac-header">Q2. 配送はどのくらいかかりますか?</div>
  <div class="ac-body">通常2〜3営業日でお届けします。</div>
</div>
$(function () {
  var KEY = 'faq_visited';  // sessionStorageのキー名

  if (!sessionStorage.getItem(KEY)) {
    // 初回アクセス: 最初のアコーディオンを開く
    $('.ac-body').first().show();
    $('.ac-header').first().addClass('is-open');
    sessionStorage.setItem(KEY, '1');  // 訪問済みフラグをセット
  }
  // 2回目以降: 全て閉じた状態(何もしない)

  // アコーディオンのクリック動作
  $('.ac-header').on('click', function () {
    var $body   = $(this).next('.ac-body');
    var isOpen  = $body.is(':visible');
    $('.ac-body').slideUp(200);
    $('.ac-header').removeClass('is-open');
    if (!isOpen) {
      $body.slideDown(200);
      $(this).addClass('is-open');
    }
  });
});
sessionStorageとlocalStorageの最大の違い
sessionStorage はタブを閉じるとデータが消えます。ページをリロードしても消えない点は localStorage と同じですが、タブを閉じて再度開いた場合は初回扱いに戻ります。「同じセッション内での2回目表示を抑制したい」場合に適しています。

2. localStorageで実装(ブラウザを閉じても維持)

localStorage のデータはブラウザを閉じても残ります。「一度でも訪問したことがあれば以降は閉じた状態にしたい」場合に使います。

基本版(ブラウザ履歴を消すまで永続)

$(function () {
  var KEY = 'faq_visited_permanent';

  if (!localStorage.getItem(KEY)) {
    // 真の初回アクセス(ブラウザ履歴を消すまでリセットされない)
    $('.ac-body').first().show();
    $('.ac-header').first().addClass('is-open');
    localStorage.setItem(KEY, '1');
  }
});

有効期限付き版(30日後に自動リセット)

「30日経ったら再び初回扱いにしたい」場合は、フラグの代わりにタイムスタンプを保存して期限を判定します。

$(function () {
  var STORAGE_KEY = 'faq_visited_ts';
  var DAYS        = 30;  // 30日後にリセット
  var now         = Date.now();
  var stored      = localStorage.getItem(STORAGE_KEY);
  var isFirst     = !stored || (now - parseInt(stored, 10)) > DAYS * 86400000;

  if (isFirst) {
    $('.ac-body').first().show();
    $('.ac-header').first().addClass('is-open');
    localStorage.setItem(STORAGE_KEY, now);  // 現在時刻を保存
  }
});
localStorageにはセキュリティ情報を保存しない
localStorage のデータはJavaScriptから誰でも読み書きできるため、パスワードや個人情報は絶対に保存しないでください。「訪問済みフラグ」や「UIの状態」のような非機密情報の保存にとどめましょう。

3. Cookieで実装(有効期限を日数で設定)

CookieはサーバーにもHTTPヘッダーとして送られます。「7日間は初回扱いにしない」のように有効期限を日数単位で設定したい場合に使います。Cookie操作の詳細はjQueryでCookieを操作する完全ガイドを参照してください。

// js-cookie ライブラリ使用時
// <script src="https://cdn.jsdelivr.net/npm/js-cookie@3/dist/js.cookie.min.js"></script>

$(function () {
  var COOKIE_NAME = 'faq_visited';

  if (!Cookies.get(COOKIE_NAME)) {
    // 初回アクセス
    $('.ac-body').first().show();
    $('.ac-header').first().addClass('is-open');
    Cookies.set(COOKIE_NAME, '1', { expires: 7 });  // 7日間有効
  }
});

// ===== ライブラリなしの素のCookie操作 =====
function setCookie(name, value, days) {
  var expires = '';
  if (days) {
    var d = new Date();
    d.setTime(d.getTime() + days * 24 * 60 * 60 * 1000);
    expires = '; expires=' + d.toUTCString();
  }
  document.cookie = name + '=' + value + expires + '; path=/';
}

function getCookie(name) {
  var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
  return match ? match[2] : null;
}

$(function () {
  if (!getCookie('faq_visited')) {
    $('.ac-body').first().show();
    setCookie('faq_visited', '1', 7);  // 7日間
  }
});

4. 開閉状態を保存して次の訪問時に復元する

「初回だけ開く」ではなく、ユーザーが操作した開閉状態を保存して次回訪問時に同じ状態を再現するパターンです。

$(function () {
  var STORAGE_KEY = 'accordion_state';

  // ===== 保存した状態を復元 =====
  var savedState = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');

  $('.accordion').each(function (i) {
    if (savedState[i] === true) {
      $(this).find('.ac-body').show();
      $(this).find('.ac-header').addClass('is-open');
    }
  });

  // ===== クリック時に状態を保存 =====
  $('.ac-header').on('click', function () {
    var $acc  = $(this).closest('.accordion');
    var $body = $(this).next('.ac-body');
    var index = $('.accordion').index($acc);
    var state = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');

    var isOpen = $body.is(':visible');
    $body.slideToggle(200);
    $(this).toggleClass('is-open');

    state[index] = !isOpen;  // 開閉状態を反転して保存
    localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
  });
});
状態をJSONでlocalStorageに保存する
localStorage には文字列しか保存できないため、オブジェクトを保存する際はJSON.stringify() で文字列化し、読み出す際は JSON.parse() で復元します。|| "{}" のフォールバックで、キーが存在しない場合(初回)のエラーを防いでいます。

5. 初回・2回目・N回目で表示を変える

「初回だけ全て開く」「3回目まではヒントを表示」「以降は閉じる」のように訪問回数によって動作を変えるパターンです。

$(function () {
  var KEY   = 'faq_visit_count';
  var count = parseInt(localStorage.getItem(KEY) || '0', 10);
  count++;
  localStorage.setItem(KEY, count);

  if (count === 1) {
    // 初回: 全て開く + ヒントを表示
    $('.ac-body').show();
    $('.ac-header').addClass('is-open');
    $('#first-visit-hint').show();

  } else if (count <= 3) {
    // 2〜3回目: 最初の1つだけ開く
    $('.ac-body').first().show();
    $('.ac-header').first().addClass('is-open');

  } else {
    // 4回目以降: 全て閉じた状態
    // (何もしない)
  }

  console.log('訪問回数:', count);
});

6. URLハッシュで特定の項目を強制的に開く

example.com/faq/#q2 のようにURLにハッシュがある場合は、初回フラグに関係なく対象の項目を開くと親切です。

$(function () {
  var KEY  = 'faq_visited';
  var hash = location.hash;  // '#q2' など

  if (hash) {
    // URLハッシュがある場合は優先的に対象を開く
    var $target = $(hash);
    if ($target.length) {
      $target.find('.ac-body').show();
      $target.find('.ac-header').addClass('is-open');
      // 対象にスクロール
      $('html, body').animate({ scrollTop: $target.offset().top - 80 }, 400);
    }

  } else if (!sessionStorage.getItem(KEY)) {
    // ハッシュなし + 初回の場合に最初の項目を開く
    $('.ac-body').first().show();
    $('.ac-header').first().addClass('is-open');
    sessionStorage.setItem(KEY, '1');
  }
});

7. 3つの保存方法の比較と選び方

方法 持続期間 容量 サーバー送信 向いている用途
sessionStorage タブを閉じるまで 5MB程度 なし タブ内の一時的な状態
localStorage ユーザーが消すまで 5MB程度 なし 長期的な設定・履歴保存
Cookie 有効期限を設定 4KB 毎リクエストに付与 日数指定の初回判定・サーバー連携
おすすめの選び方

  • 同じタブで2回目のページ遷移から閉じたい → sessionStorage
  • ブラウザを再起動しても記憶させたい → localStorage(期限付きにしたい場合はタイムスタンプで管理)
  • サーバー側でも初回判定したい・有効期限を厳密に設定したい → Cookie

まとめ

「初回アクセス時のみ開く」の実装は、ブラウザの状態保存APIとアコーディオンの初期化処理を組み合わせるだけです。要件に合わせて sessionStorage・localStorage・Cookie を使い分けてください。

関連記事: jQueryアコーディオンの実装完全ガイド(排他制御・アイコン回転) / jQueryでCookieを操作する完全ガイド(js-cookieライブラリ)

よくある質問(FAQ)

QsessionStorageとlocalStorageはどう使い分けますか?
AsessionStorage はタブを閉じると消え、localStorage はブラウザを閉じても残ります。「同じタブ内での2ページ目以降は閉じたい」なら sessionStorage、「次の日に再訪問しても閉じた状態にしたい」なら localStorage を使います。
Qプライベートモード(シークレットウィンドウ)でも動作しますか?
AsessionStorage はプライベートモードでも利用できますが、localStorage はブラウザによって制限されることがあります(特にiOS Safari)。プライベートモードでの動作を保証したい場合はCookieを使うか、try-catchでストレージへのアクセスエラーを処理してください。
Q複数の項目の開閉状態を全て保存・復元するには?
A各アコーディオンのインデックスをキーにしたオブジェクト{ 0: true, 1: false, 2: true }JSON.stringify() で文字列化してlocalStorage に保存し、読み出し時に JSON.parse() で復元します(セクション4参照)。
Q開発中にlocalStorageやCookieをリセットするには?
Aブラウザの開発者ツール(F12)→「Application(アプリケーション)」タブから「Storage」→「localStorage」「sessionStorage」「Cookies」を選択してクリアできます。または localStorage.clear() をコンソールで実行する方法もあります。
Q訪問回数によって表示を変えることはできますか?
AlocalStorageに訪問回数を数値で保存して判定できます。ページ読み込み時に count = parseInt(localStorage.getItem("visit_count") || "0") + 1 として回数を取得し、保存します(セクション5参照)。