JavaScript

JavaScriptでCookieを扱う方法|「次回は表示しない」ポップアップをデモで解説

みなと
UI実装担当
UI実装担当

お知らせポップアップ、一度閉じたら次から出さない仕様にしたい…

Webサイトを見ていると、「お知らせ」や「キャンペーン情報」などのポップアップが表示され、一度閉じると次回からは表示されなくなる、という挙動を見たことがある方も多いのではないでしょうか。

このような「次回は表示しない」という仕組みは、JavaScriptとCookieを使うことで、比較的シンプルに実装できます。

本記事では、ポップアップを一度閉じると、次回以降は表示されなくなるデモを題材に、JavaScriptでCookieを操作する基本的な考え方と実装方法を解説します。実際に動くデモを用意しているので、コードを読むだけでなく、操作しながら挙動を確認できるのもポイントです。

こんな方におすすめ
  • Cookieは聞いたことがあるけれど、どう使えばいいのか分からない。
  • 実務でよく見る挙動を、自分でも実装してみたい。

そんな方に向けて、できるだけシンプルに、実務でも応用しやすい形で紹介していきます。

Cookieとはなにか

Cookie(クッキー)とは、ブラウザに小さなデータを保存する仕組みです。Webページを閉じたり、ブラウザを再起動したあとでも情報を保持できるため、ユーザーの状態を記憶しておきたい場面でよく使われます。

JavaScriptからもCookieを操作できるため、

  • ユーザーが一度行った操作を覚えておく
  • 次回アクセス時の表示を切り替える

といったシンプルな制御に向いています。

Cookieが使われる代表的なケース

実務では、次のような用途でCookieが使われています。

  • ログイン状態の保持
  • サイトの表示設定(言語・テーマなど)
  • お知らせやキャンペーンの表示制御

今回のデモで扱う「ポップアップを一度閉じたら、次回からは表示されなくなる」という挙動も、この中のひとつです。

Cookieを実際に確認してみよう

Cookieは「ブラウザに保存されるデータ」ですが、文章で説明されるだけでは、少しイメージしづらいかもしれません。

ここでは、一般的なWebサイトで保存されているCookieを確認する方法を紹介します。どのサイトでも共通の手順なので、ぜひ一度自分のブラウザで試してみてください。

Chromeのデベロッパーツールで確認する方法

Google Chromeでは、デベロッパーツールを使ってCookieの中身を確認できます。

  1. Chromeで任意のWebページを開く
  2. デベロッパーツールを開く
    • Windows:F12またはCtrl + Shift + I
    • Mac:Cmd + Option + I
  3. 上部メニューからアプリケーションタブを選択する
  4. 左側のメニューでストレージ → Cookieを開く
  5. 表示されたドメインをクリックする

すると、そのページで保存されているCookieの一覧が表示されます。

Cookie一覧で確認できる項目

Cookie一覧では、次のような情報を確認できます。

NameCookieの名前
Value保存されている値
Expires / Max-Age有効期限
Path / DomainCookieが有効な範囲

これらの情報によって、

  • どんなデータが保存されているのか
  • いつまで有効なのか

を把握できます。

Chromeのデベロッパーツールでは、CookieのexpiresはUTC(世界標準時)で表示されます。日本時間(JST)はUTCより9時間進んでいるため、表示されている時刻に9時間足したものが、日本時間での有効期限になります。

JavaScriptからCookieを確認する方法

Cookieは、JavaScriptからも確認できます。デベロッパーツールのコンソールタブを開き、次のコードを実行してみてください。

document.cookie

実行すると、現在のページで利用可能なCookieが、次のような文字列として表示されます。

cookieName=value; anotherCookie=example

document.cookieで取得できるのは、Cookieの「名前」と「値」だけです。有効期限(expires)や有効な範囲などの情報は取得できません。

Cookieは文字列として取得される

document.cookieの戻り値は、名前=値; 名前=値のような単なる文字列です。そのため、JavaScriptでCookieを扱う場合は、

  • ;で区切ってCookieを分割する
  • =で名前と値を分ける

といった文字列処理を行ったほうが安全です。

スワン
スワン

今回のデモでも、document.cookieの文字列を分割し、目的のCookieだけを取り出す処理を行っています。このあたりの処理は、後半で詳しく見ていきます。

完成デモの紹介

ここからは、今回作成した完成デモを実際に触ってみましょう。

ページを開くと、一定時間後にポップアップが表示され、「閉じる」をクリックすると、次回以降は表示されなくなります。まずは細かい説明を読む前に、実際の挙動を確認してみてください。

一定時間後にポップアップが表示されるデモページの画面

このデモでは、ポップアップを閉じたかどうかをCookieに保存し、ページを再読み込みした際に、その状態をもとに表示を制御しています。

一度「閉じる」をクリックしたあとにページを更新すると、ポップアップが表示されなくなることが確認できるはずです。Cookieを削除すると、再び表示されるようになります。

みなと
みなと

前のセクションで紹介した手順でCookieの変化を確認してみると、仕組みがより理解しやすくなります。

コード全体(HTML / CSS / JavaScript)

ここからは、今回のデモで使用しているコード全体を確認していきます。

まずは細かい処理を気にせず、「どんな構造で実装されているのか」を把握することを意識して、HTML・CSS・JavaScriptの順に見てみてください。

HTMLコード

HTMLでは、ポップアップの構造と、JavaScriptから操作するための要素を定義しています。見た目の制御や表示・非表示の切り替えはCSSとJavaScriptに任せ、HTML自体はできるだけシンプルな構造にしています。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="format-detection" content="telephone=no">
    <title>Cookieのデモ</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <div class="wrapper">
      <header class="header"><!-- ヘッダー(省略) --></header>
      <div class="keyvisual"><!-- キービジュアル(省略) --></div>
      <div class="contents"><!-- コンテンツ(省略) --></div>
      <footer class="footer"><!-- フッター(省略) --></footer>
    </div>

    <!-- ポップアップ本体(Cookieで表示/非表示を制御) -->
    <div class="popup">
      <!-- ポップアップを閉じるボタン -->
      <button class="popup-close" type="button">閉じる<span></span></button>
      <!-- ポップアップの内容エリア -->
      <div class="popup-body">
        <p class="popup-text">このお知らせはサンプルです。<br>「閉じる」をクリックすると、<br>次回からは表示されません。</p>
      </div>
    </div>

    <script src="js/script.js"></script>
  </body>
</html>

CSSコード

CSSでは、ポップアップの見た目とアニメーションを設定しています。初期状態では非表示にしておき、JavaScriptでクラスを付け替えることで、表示・非表示を切り替える仕組みになっています。

/* ポップアップ本体(初期状態では非表示) */
.popup {
  position: fixed;
  right: 0;
  bottom: 0;
  z-index: 100;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
  background: #f9e8ed;
  color: #c11a51;

  /* 初期状態は非表示 */
  visibility: hidden;
  opacity: 0;
  transform: translateY(100px);
  transition: visibility 0ms 1000ms, opacity 1000ms, transform 1000ms;
}

@media (min-width: 768px) {
  .popup {
    width: 400px;
  }
}

@media (max-width: 767px) {
  .popup {
    width: 270px;
  }
}

/* 閉じるボタン */
.popup-close {
  display: block;
  width: 100%;
  border: none;
  background: #c11a51;
  color: #fff;
  font: inherit;
  font-size: 14px;
  line-height: 1;
  text-align: center;
  cursor: pointer;
  appearance: none;
  transition: background-color 400ms;
}

@media (min-width: 768px) {
  .popup-close {
    height: 35px;
  }
}

@media (max-width: 767px) {
  .popup-close {
    height: 28px;
  }
}

/* 閉じるボタンの×アイコン */
.popup-close > span {
  display: inline-block;
  position: relative;
  width: 14px;
  height: 14px;
  margin-left: 7px;
  vertical-align: -12%;
}

.popup-close > span::before,
.popup-close > span::after {
  content: "";
  display: block;
  position: absolute;
  left: 0;
  top: 6.5px;
  width: 100%;
  height: 1px;
  background: #fff;
}

.popup-close > span::before {
  transform: rotate(-45deg);
}

.popup-close > span::after {
  transform: rotate(45deg);
}

/* ホバー・タップ時 */
.popup-close:hover,
.popup-close:active {
  background: #890631;
}

/* ポップアップ本文エリア */
.popup-body {
  display: flex;
  justify-content: center;
  align-items: center;
}

@media (min-width: 768px) {
  .popup-body {
    height: 200px;
  }
}

@media (max-width: 767px) {
  .popup-body {
    height: 150px;
  }
}

/* ポップアップ内テキスト */
.popup-text {
  font-weight: 700;
  line-height: 1.7;
  text-align: center;
}

@media (min-width: 768px) {
  .popup-text {
    font-size: 18px;
  }
}

@media (max-width: 767px) {
  .popup-text {
    font-size: 16px;
  }
}

/* 表示状態(JSで is-visible を付与) */
.popup.is-visible {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition: visibility 0ms, opacity 1000ms, transform 1000ms;
}

/* ==============================
  その他の装飾は本題外のため省略
============================== */

JavaScriptコード

JavaScriptでは、Cookieの確認・保存処理と、ポップアップの表示制御を行っています。ページ読み込み時にCookieをチェックし、条件に応じてポップアップを表示するかどうかを判断しています。

// DOMの読み込みが完了してから処理を開始
document.addEventListener('DOMContentLoaded', () => {
  // 設定値をまとめたオブジェクト
  const props = {
    cookieKey: 'popup_closed', // 表示状態を保存するCookie名
    expiresDays: 3, // Cookieの有効期限(日)
    showDelayMs: 3000, // ポップアップを表示するまでの時間(ms)
  };

  // 指定したキーのCookieを取得する関数
  const getCookie = (key) => {
    const cookies = document.cookie.split(';').map(v => v.trim());
    for (const c of cookies) {
      const [k, ...rest] = c.split('=');
      if (k === key) return decodeURIComponent(rest.join('='));
    }
    return null;
  };

  // Cookieを保存する関数
  const setCookie = (key, value, days) => {
    const expires = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toUTCString();
    const cookie = `${key}=${encodeURIComponent(value)}; expires=${expires}; path=/;`;
    document.cookie = cookie;
  };

  // 初期化処理
  function init() {
    // すでに「閉じた」状態が保存されていれば何もしない
    if (getCookie(props.cookieKey) === 'true') return;

    const popup = document.querySelector('.popup');
    const close = document.querySelector('.popup-close');
    if (!popup || !close) return;

    // 一定時間後にポップアップを表示
    setTimeout(() => {
      popup.classList.add('is-visible');
    }, props.showDelayMs);

    // 閉じるボタンをクリックしたらCookieを保存して非表示にする
    close.addEventListener('click', () => {
      setCookie(props.cookieKey, 'true', props.expiresDays);
      popup.classList.remove('is-visible');
    }, { once: true }); // クリックイベントは1回だけ実行
  }

  init();
});

コードのポイント解説

ここからは、今回のデモで特に重要なコードのポイントを解説します。処理の流れを意識しながら、ひとつずつ確認していきましょう。

ポイント1:Cookieを取得して、処理を分岐している

まず注目したいのが、「『閉じる』をクリック済みかどうか」を判定している部分です。

if (getCookie(props.cookieKey) === 'true') return;
const getCookie = (key) => {
  const cookies = document.cookie.split(';').map(v => v.trim());
  for (const c of cookies) {
    const [k, ...rest] = c.split('=');
    if (k === key) return decodeURIComponent(rest.join('='));
  }
  return null;
};

この処理でやっていること

このコードでは、指定した名前のCookieが存在するかどうかを確認しています。getCookie() は、document.cookieに保存されているCookieの中から、指定したキー名に一致するものを探し、その値を返す関数です。

getCookie(props.cookieKey)

この結果が'true'の場合は、

return;

によって、その後の処理を行わずに終了します。この判定が最初にあることで、後述のポップアップの表示処理自体が実行されません。

スワン
スワン

これが、一度閉じたら次回からは表示されなくなるという挙動を成立させている、もっとも重要なポイントです。

getCookie関数の考え方

document.cookieは、次のような文字列としてCookieを返します。

cookieA=valueA; cookieB=valueB

このように、すべてのCookieが1つの文字列としてまとめて返ってくるため、そのままでは、特定のCookieの名前や値を判別しづらくなります。

そのため、getCookieでは、

  1. ;でCookieを分割する
  2. =で名前と値を分ける
  3. 指定した名前と一致するものを探し、その値を返す

という手順で処理しています。

今回のデモでは、閉じるボタンをクリックしたときに、名前が「popup_closed」、値が「true」のCookieが保存されます。そのため、getCookieでは、この「popup_closed」という名前のCookieが存在するかどうかを調べ、その値が「true」であれば「閉じる」をクリック済みだと判断しています。

なぜ文字列のままCookieを扱わないの?

Cookieを文字列のまま検索してしまうと、意図しないCookieに一致してしまう可能性があります。

たとえば、自分が判定したいCookie以外にも、次のようなCookieが存在した場合を考えてみてください。

  • page_popup_closed=true
  • popup_closed=true_v2

この状態で単純に「popup_closed=true」を含むかどうかを調べると、本来判定したいCookie以外にも一致してしまいます。

Cookieの名前や値を重複しないようにすれば文字列検索でも問題になることは少ないですが、安全に判定するなら「;」や「=」で分割してチェックする方法が無難です。

ポイント2:表示・非表示をクラスの付け替えで制御している

次に注目したいのが、ポップアップの表示・非表示を制御している部分です。

今回のデモでは、JavaScriptで直接スタイルを変更するのではなく、クラスの付け替えによって表示を切り替えるという方法を取っています。

setTimeout(() => {
  popup.classList.add('is-visible');
}, props.showDelayMs);

close.addEventListener('click', () => {
  setCookie(props.cookieKey, 'true', props.expiresDays);
  popup.classList.remove('is-visible');
}, { once: true });

一定時間後にポップアップを表示する

まず、次の処理ではsetTimeoutを使って、ページ表示から一定時間後にポップアップを表示しています。

setTimeout(() => {
  popup.classList.add('is-visible');
}, props.showDelayMs);

ここで行っているのは、

  • is-visibleクラスを付与する
  • 実際の表示・アニメーションはCSSに任せる

というシンプルな処理です。表示を遅らせることで、ページを開いた直後にいきなりポップアップが出るのを避け、ユーザー体験を損ねにくくしています。

みなと
みなと

今回のデモでは挙動を確認しやすいように3秒にしていますが、実務では10秒前後など、もう少し長めに設定することもよくあります。

「閉じる」クリック時の処理

次に、「閉じる」ボタンをクリックしたときの処理です。

popup.classList.remove('is-visible');

この1行で、ポップアップは非表示になります。ここでも、JavaScriptはクラスを外しているだけで、実際の見た目の変化はCSS側で制御されています。

{ once: true }を指定している理由

イベントリスナーの最後に指定している{ once: true }は、このクリック処理を一度だけ実行するための指定です。

close.addEventListener('click', () => {
  // 処理
}, { once: true });

今回のデモでは、「閉じる」ボタンは一度クリックできれば十分です。連続クリックによって同じ処理が何度も実行されるのを避けるため、{ once: true }を付けています。

ポイント3:Cookieを保存して、状態を記憶している

最後に解説するのが、「閉じる」をクリックしたという状態をCookieに保存している部分です。

この処理によって、ページを再読み込みしたあとでも「すでに閉じられている」という状態を判断できるようになります。

setCookie(props.cookieKey, 'true', props.expiresDays);
const setCookie = (key, value, days) => {
  const expires = new Date(
    Date.now() + days * 24 * 60 * 60 * 1000
  ).toUTCString();

  const cookie = `${key}=${encodeURIComponent(value)}; expires=${expires}; path=/;`;
  document.cookie = cookie;
};

「閉じた」という状態をCookieに保存している

「閉じる」ボタンをクリックしたとき、次の1行でCookieを保存しています。

setCookie(props.cookieKey, 'true', props.expiresDays);

ここでは、

  • Cookieの名前
  • 保存する値
  • 有効期限(日数)

をまとめて指定しています。今回のデモでは、「ポップアップを閉じた(popup_closed)」という状態をtrueという値でシンプルに表しています。

setCookie関数の考え方

setCookie関数は、指定した内容をもとにCookieを保存するための関数です。

const setCookie = (key, value, days) => {
  const expires = new Date(
    Date.now() + days * 24 * 60 * 60 * 1000
  ).toUTCString();

  const cookie = `${key}=${encodeURIComponent(value)}; expires=${expires}; path=/;`;
  document.cookie = cookie;
};

ここでは、Cookieの名前・値・有効期限を組み立てて、最後にdocument.cookieに代入することで、ブラウザにCookieを保存しています。

有効期限を指定して、表示しない期間を決めている

setCookie関数の中では、指定された日数をもとに、有効期限(expires)を計算しています。

const expires = new Date(
  Date.now() + days * 24 * 60 * 60 * 1000
).toUTCString();

この有効期限を過ぎると、そのCookieは自動的に削除されます。つまり、「閉じる」をクリック済みという情報が消えるため、次にページを開いたときには、再びポップアップが表示されるようになります。

なお、この中で行っている日付の計算については、今回のデモでは細かく理解できなくても問題ありません。

days * 24 * 60 * 60 * 1000

という部分で、「指定した日数分だけ先の日時」を計算していますが、「daysに数値を渡すと、その日数分を有効期限として設定できる」という点が分かっていれば十分です。

path=/の意味

Cookieの文字列の最後についている、

path=/

は、このCookieをサイト全体で有効にするための指定です。path=/を付けておくことで、トップページ、下層ページのどちらからでも、同じCookieを参照できるようになります。

みなと
みなと

LPなど特定のディレクトリ内だけで使うCookieの場合は、影響範囲を抑えるために、path=/lp/campaign/のようにパスを限定しておいたほうが安全なこともあります。

まとめ

この記事では、「次回は表示しない」ポップアップを例に、JavaScriptでのCookie操作を解説しました。

  • Cookieの確認方法
  • Cookieの取得・保存の考え方
  • 状態を使って表示を制御する流れ

を、デモとコードを通して確認できたと思います。

Cookieはシンプルな仕組みですが、状態をまたいで挙動を変えたい場面では、今でも十分に使える技術です。ぜひ、今回のデモをベースに、表示条件や有効期限を調整しながら、実務に合わせて応用してみてください。

押していただけると励みになります!

ABOUT ME
みなと
みなと
フロントエンドエンジニア
東京のWeb制作会社で15年以上働いている現役フロントエンドエンジニアです。これまで、いろんなプロジェクトに関わりながら、フロントエンド開発やWebデザインに取り組んできました。このブログでは、今までの経験を活かして、Web制作に役立つ情報やノウハウをシェアしていきたいと思います。初心者の方から、現場で働く方まで、誰でも参考にできる内容をお届けしますので、ぜひ覗いてみてください。
記事URLをコピーしました