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 と同じですが、タブを閉じて再度開いた場合は初回扱いに戻ります。「同じセッション内での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 のデータは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));
});
});
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)
sessionStorage はタブを閉じると消え、localStorage はブラウザを閉じても残ります。「同じタブ内での2ページ目以降は閉じたい」なら sessionStorage、「次の日に再訪問しても閉じた状態にしたい」なら localStorage を使います。{ 0: true, 1: false, 2: true } を JSON.stringify() で文字列化してlocalStorage に保存し、読み出し時に JSON.parse() で復元します(セクション4参照)。localStorage.clear() をコンソールで実行する方法もあります。count = parseInt(localStorage.getItem("visit_count") || "0") + 1 として回数を取得し、保存します(セクション5参照)。
