「Cookie を有効にしてください」メッセージを考える

ログインが必要なシステムなどで、 Cookie を無効にしているユーザーに対する「Cookie を有効にしてください」的なメッセージですが、私自身普段は Cookie を無効にしているため、さまざまなサイトでよく見かけます。

しかし、メッセージの内容や表示の仕方に疑問を感じることも多く、どういった出し方が良いかを具体的なコードも提示しつつ考えてみたいと思います。

なお、当記事はあくまで私の「こうだったら自分が使いやすい」という経験から書いています。当然異論もあるでしょうが、「こういう風に考えている人もいる」と捉えていただければ幸いです。

前提

  • Cookie が有効でないと目的が達成できないシステムを想定(Cookie が有効だとより快適だけど、無効でも最低限操作できる、というものは今回考えない)。
  • メッセージの表示は JavaScript で行う(スクリプト無効環境は考慮しない)。

メッセージの文言

よく見かける例はこういうのです。

このサイトでは Cookie を使っています。 Cookie を有効にしてください。

どのブラウザでも、デフォルト設定では Cookie は有効です。つまり、 Cookie が無効なユーザーというのは、何らかの理由で意図的に無効にしているものと想定できます。そういうユーザーに対し、設定を再度変更させて Cookie を有効にしてもらうには下記2点の情報を提示すべきかと思います。

  • なぜ Cookie を有効にしなければならないのか
  • 具体的に何を許可して、何は許可しないままで良いのか(どのドメインに対して? サードパーティ Cookie は? リファラーなど Cookie 以外の設定は?)

これらを考慮すると、次のようなメッセージが良いのではないでしょうか。

当ページでは○○のためにファーストパーティ Cookie を使用しています。「example.com」ドメインに対して Cookie を有効にしてください。

ポイントは以下の3つ。

  • 理由を明記します。例えば「セッションIDの格納のため」など。これがアクセス解析用途であれば「別に無効のままでもいいかな」となるでしょうし、セッションIDで使うと言われたら有効にしないと先へ進めないことが容易に想像つきます。なお、「セッションID」という単語を知らないユーザーもいるかもしれませんが、専門用語はよほど難解なものでなければ気にせず使って良いと考えます。意図的に Cookie を無効にしているユーザーはリテラシーも高いはずだからです。
  • Cookie を無効にしているユーザーにとって、「サードパーティ Cookie」が使われているか否かは重要な点かと思います。使っていなければ、ファーストパーティ Cookie だけを有効にすればいいことが分かる文言にします。
  • どのドメインに対して有効にすればいいかが分かるようにします。 Cookie を無効にしているユーザーも、すべてのサイトに対してブロックしているわけではなく(今日日そんな状態ではSNSの一つも利用できません)、ドメインごとに有効/無効の設定をしているものと思われます。サービスによっては、入口のページと送信ボタンを押した後のページでドメインが違うこともありますが、そういう場合は許可すべきドメインをすべて列挙してほしいところです[1]

実装

前提条件に書いたとおり、今回は「Cookie が有効でないと目的が達成できないシステム」を想定します。そのため、メッセージは必ず目に留まるようにした方が良いでしょう。一方で、ユーザーから「Cookie を有効にしないまま、そのページを離脱する」という選択肢を奪ってはいけません。

この要件を両立する方法はいくつか考えられますが、今回はページロード時に自動的にダイアログを表示するようにしてみました。ダイアログ内には閉じるボタンがあるので、内容を読んだら非表示にすることができます。

オリジナル画像
図1Cookie 無効環境向けメッセージの表示イメージ

HTML

ダイアログにはdialog 要素(html.spec.whatwg.org)を使うことができます。

<dialog id="js_cookie_dialog" hidden=""><div class="inner">
  <p>当ページでは○○のためにファーストパーティ Cookie を使用しています。「example.com」ドメインに対して Cookie を有効にしてください。</p>
  <p><button type="button" class="js_dialog_close">閉じる</button></p>
</div></dialog>

この dialog 要素をページロード時に JavaScript で showModal() することで、「閉じる」ボタンを押さない限り他の操作はできないようになります。

なお、2017年4月時点では dialog 要素は Chrome しか対応していないため、未対応ブラウザのために hidden 属性を指定し、また内側にスタイル付けのための div 要素を挿入します。

CSS

最低限それっぽくなるような指定のみを記述しています。

Chrome だけならもっと簡素な指定で済むのですが、 dialog 要素未対応ブラウザでも極力同じ見た目(メッセージボックスを上下左右中央に表示し、それ以外のエリアは透過でグレーアウトする)を確保するために、いろいろやっています。

dialog {
  /* ↓リセット */
  margin: 0;
  padding: 0;
  border: none;
  color: inherit;
  /* ↑リセット */
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, .1); /* <dialog> 未対応ブラウザ用 */
  z-index: 2147483647; /* <dialog> 未対応ブラウザ用 */
  overflow-y: auto;
}

dialog:not([hidden]) {
  display: flex;
}

dialog::backdrop {
  background: rgba(0, 0, 0, .1);
}

dialog > .inner {
  padding: 1em;
  border: 2px solid #000;
  max-width: 36em;
  background: #fff;
}

JavaScript

ページロード時[2]に Cookie の有効/無効を判定し、無効だったらモーダルダイアログを表示(showModal)します。 dialog 要素に対応していない環境では、 hidden 属性を削除することで(CSSで指定したとおり)画面上に表示を行い、 tabIndex = -1 と focus() で自動フォーカスを行います[3]

Cookie 無効/有効の判定にはnavigator.cookieEnabled(developer.mozilla.org)を使います。ただし、詳しい原因は調べていませんが、 IE 11 では Cookie をブロックしていても navigator.cookieEnabled が常に true を返してしまう事象を確認しました。そのため、 cookieEnabled() 関数を用意して、 IE にも対応した判定を行っています。

/**
 * Cookie が有効か調べる
 *
 * @return 有効ならtrue、無効ならfalse
 */
var cookieEnabled = function() {
  if (!navigator.cookieEnabled) {
    return false;
  }

  /* IE 11 は navigator.cookieEnabled が常に true を返すので、仮 Cookie を設定して判定する */
  var TEMP_COOKIE = 'tmp_check=1';

  var nowCookie = document.cookie;
  document.cookie = TEMP_COOKIE; // 仮 Cookie 設定
  if (nowCookie === document.cookie) {
    return false;
  }

  document.cookie = TEMP_COOKIE + ';expires=' + (new Date(0)).toUTCString(); // 仮 Cookie 削除(有効期限に過去日を指定)
  return true;
};

if (!cookieEnabled()) {
  /* Cookie が無効な場合 */
  var supportDialog = window.HTMLDialogElement !== undefined; // <dialog> をサポートしているか

  /* ダイアログの初期処理 */
  var cookieDialogElement = document.getElementById('js_cookie_dialog');
  if (cookieDialogElement !== null) {
    cookieDialogElement.hidden = false; // <dialog> 非対応環境向け

    if (supportDialog) {
      cookieDialogElement.showModal();
    } else {
      cookieDialogElement.tabIndex = -1;
      cookieDialogElement.focus();
    }
  }

  /* 閉じるボタンを押したときの処理 */
  var closeButtonElements = cookieDialogElement.querySelectorAll('.js_dialog_close');
  for (var i = 0, leni = closeButtonElements.length; i < leni; i++) {
    closeButtonElements[i].addEventListener('click', function() {
      cookieDialogElement.hidden = true; // <dialog> 非対応環境向け

      if (supportDialog) {
        cookieDialogElement.close();
      }
    });
  }
}
  • [1]以前、Google Play のサービスでドメインを明示されているメッセージを見かけて感動したことがあります。
  • [2]省略していますが、実際は 'DOMContentLoaded' イベントなどの中で実行する必要があります。
  • [3]<dialog> 未対応環境ではそのまま Tab キーを押すと本来操作できない裏側のリンクやボタンにフォーカスが合ってしまいます。ページ内のすべてのフォーカス可能要素に tabIndex= -1 を設定し、閉じるボタンを押したときは戻すようにすればその辺の対応も可能ですが、今回はそこまでの対策は行っていません。