GODRICH

本人確認 画面UI 9選 — そのまま使える認証カード

本人確認 画面とは、カメラへのアクセス許可や認証コードの入力、本人確認直後のプロフィール設定まで、ユーザーが本人であることを証明する一連の流れで使われる一時的な画面のことです。ここでは権限リクエストから認証コード入力、ログアウト確認まで、その流れの9段階でそのまま貼り付けて使えるUI部品を紹介します。

自動再生 · タイルを押すとその項目へ · すべて1つのzip

9つは目立つ順ではなく、実際にユーザーが本人確認を進める順番で並べています。まずアクセス権限を求め、人間かどうかを確認し、届いた認証コードを入力し、コードが届かないときは秘密の質問や複数の復旧方法に切り替えます。認証が終わればプロフィール入力・連携アカウント管理・セッション延長・ログアウト確認へと続きます。各デモは画面中央にカード一枚だけを置いているので、認証フロー全体ではなくこの一枚だけを自分のプロジェクトへそのまま移せます。

01権限リクエストモーダル

カメラや位置情報へのアクセス許可を求めるとき、アイコンが弾むように動き、「許可」ボタンが色で塗りつぶされて「拒否」より強調されます。本人確認の前にカメラ・マイクのアクセスを求める画面や、アプリ初回起動時の通知権限案内に向いています。

@keyframes 아이콘 바운스포커스 트랩aria-modal
(function(){
  var scene = document.querySelector('.perm-scene');
  var modal = scene.querySelector('.perm-scene__modal');
  var deny = scene.querySelector('.perm-scene__btn--ghost');
  var allow = scene.querySelector('.perm-scene__btn--primary');
  function close(){ scene.classList.remove('is-demo'); scene.classList.add('is-closed'); }
  deny.addEventListener('click', close);
  allow.addEventListener('click', close);
  modal.addEventListener('keydown', function(e){
    if (e.key === 'Escape') close();
  });
}());

02キャプチャ確認チェックボックス

チェックボックスを押すとローディングが少し回ってから緑のチェックがぽんと弾んで表示され、続けて「確認済み」バッジが現れます。認証コード送信前に人間かどうかを確かめる段階や、無料体験申し込みフォームのスパム防止に使われます。

@keyframes spin → scalerotate(560deg) 스피너:checked 상태
.captcha__input:checked ~ .captcha__box .captcha__check {
  opacity: 1;
  transform: scale(1);
  transition: opacity $dur-quick $ease-out, transform $dur-quick $ease-pop;
}
.captcha__input:checked ~ .captcha__box { border-color: $color; }
.captcha__input:focus-visible ~ .captcha__box { outline: 2px solid $color; outline-offset: 2px; }

@keyframes capt-check {
  0%, 28%   { opacity: 0; transform: scale(.4); }
  40%       { opacity: 1; transform: scale(1.15); }
  46%, 84%  { opacity: 1; transform: scale(1); }
  92%, 100% { opacity: 0; transform: scale(.4); }
}

03認証コード入力グリッド

6つの数字マスが並び、1マスに入力すると自動的に次のマスへ移動し、そのマスの枠が一瞬青く光ります。SMSで届いた6桁の認証コード入力欄や、2段階認証コード入力画面に向いています。

input 이벤트 자동 이동paste 이벤트 6자리 분배inputmode=numeric
boxes.forEach(function(box, i){
  box.addEventListener('input', function(){
    box.value = box.value.replace(/[^0-9]/g, '').slice(0, 1);
    if (box.value && boxes[i + 1]) boxes[i + 1].focus({ preventScroll: true });
  });
  box.addEventListener('keydown', function(e){
    if (e.key === 'Backspace' && !box.value && boxes[i - 1]) boxes[i - 1].focus({ preventScroll: true });
  });
  box.addEventListener('paste', function(e){
    e.preventDefault();
    var digits = (e.clipboardData.getData('text') || '').replace(/[^0-9]/g, '').split('');
    boxes.forEach(function(b, j){ b.value = digits[j] || ''; });
    (boxes[Math.min(digits.length, boxes.length) - 1] || boxes[0]).focus({ preventScroll: true });
  });
});

04秘密の質問確認カード

事前に登録した質問がカードに強めの色でふわっと表示されたあと、入力欄の枠がオレンジがかった色から薄いベージュへゆっくり冷めるように変わります。OTPが届かないときの代替認証ステップや、管理者アカウントの二次確認画面に使われます。

@keyframes sq-panelbox-shadow 글로우aria-label
.sq-card__input:focus-visible { border-color: $subject-blue; box-shadow: 0 0 0 3px rgba($subject-blue, .25); }

@keyframes sq-panel {
  0%, 8%    { background: mix($color, white, 24%); box-shadow: 0 0 0 3px rgba($color, .3), 0 0 34px 18px rgba($color, .3), $shadow-raised; }
  23%, 77%  { background: $stage-paper; box-shadow: $shadow-raised; }
  92%, 100% { background: mix($color, white, 24%); box-shadow: 0 0 0 3px rgba($color, .3), 0 0 34px 18px rgba($color, .3), $shadow-raised; }
}
@keyframes sq-input {
  0%, 8%    { border-color: $color; box-shadow: 0 0 0 4px rgba($color, .22), 0 0 20px 10px rgba($color, .25); }
  23%, 77%  { border-color: #d8d2c4; box-shadow: none; }
  92%, 100% { border-color: $color; box-shadow: 0 0 0 4px rgba($color, .22), 0 0 20px 10px rgba($color, .25); }
}

05アカウント復旧方法の選択カード

メール・SMS・秘密の質問の3つの選択肢がラジオカードとして並び、選ぶとそのカードだけが暗い背景の上で明るく浮き上がります。パスワードを忘れたときに復旧手段を選ぶ最初の画面や、アカウントロック解除前の確認ステップに向いています。

role=radiogroup:has(:checked)@keyframes picker-cycle
.recovery__card:has(.recovery__input:checked) {
  background: mix($color, $stage-ink, 26%);
  border-color: $color;
  box-shadow: 0 0 0 3px rgba($color, .3), 0 0 24px 12px rgba($color, .28);
  transform: scale(1.04);
}
.recovery__card:has(.recovery__input:focus-visible) { outline: 2px solid $color; outline-offset: 2px; }

.recovery.is-demo .recovery__card { animation: picker-cycle $duration $easing infinite; }
.recovery.is-demo .recovery__card:nth-child(1) { animation-delay: 0ms; }
.recovery.is-demo .recovery__card:nth-child(2) { animation-delay: 660ms; }
.recovery.is-demo .recovery__card:nth-child(3) { animation-delay: 1320ms; }

06オンボーディングウィザードのステップカード

認証後にプロフィールを入力するカードで、次へを押すと今のカードが左へスライドし、次のパステルカラーのカードが入れ替わりに現れます。会員登録の認証直後に続くプロフィール設定ステップや、初回起動オンボーディングの入力カードに使われます。

transform: translateX 슬라이드커스텀 프로퍼티 --step@keyframes wiz-track
(function(){
  var track = document.querySelector('.wizard__track');
  var dots = Array.prototype.slice.call(document.querySelectorAll('.wizard__dot'));
  var btn = document.querySelector('.wizard__next');
  var step = 0;
  btn.addEventListener('click', function(){
    step = step === 0 ? 1 : 0;
    track.style.transform = 'translateX(' + (step === 0 ? '0%' : '-50%') + ')';
    dots.forEach(function(d, i){ d.classList.toggle('is-active', i === step); });
    btn.textContent = step === 0 ? 'Next' : 'Back';
  });
}());

07連携アカウント一覧

GoogleやGitHubなどのログイン手段が行ごとに並び、接続スイッチを押すとトグルが滑るように切り替わり、行の背景がうっすら色づきます。設定画面でのソーシャルログイン連携管理や、複数アカウントをまとめる統合ログインダッシュボードに向いています。

checkbox 기반 토글transform: translateXfocus-visible 링
.accounts__input:checked ~ .accounts__track { background: $color; }
.accounts__input:checked ~ .accounts__track .accounts__knob { transform: translateX(14px); }
.accounts__input:focus-visible ~ .accounts__track { outline: 2px solid $color; outline-offset: 2px; }
.accounts__row:has(.accounts__input:checked) { background: rgba($subject-mint, .18); }

@keyframes acct-knob-cycle {
  0%, 8%    { transform: translateX(0); }
  14%, 36%  { transform: translateX(14px); }
  42%, 100% { transform: translateX(0); }
}

08セッションタイムアウト警告バナー

画面上部からバナーが滑り降りてきて残り時間が秒単位で減っていき、延長ボタンを押すと残り時間が30秒に戻ります。銀行・決済アプリの自動ログアウト前警告や、管理コンソールのアイドルセッション通知に使われます。

transform: translateY 슬라이드setInterval 카운트다운role=alert
(function(){
  var cnt = document.querySelector('.timeout-banner__count'),
      btn = document.querySelector('.timeout-banner__extend'),
      n = 30,
      timer = setInterval(function(){
        n--; if (n < 0) n = 0; cnt.textContent = n;
      }, 1000);
  btn.addEventListener('click', function(){
    n = 30; cnt.textContent = n;
  });
}());

09ログアウト確認カード

ログアウトボタンを押すとカードが小さく揺れてから確認カードに切り替わり、最終の退出ボタンにカーソルを乗せると背景が濃い赤に変わります。誤って押したログアウトをもう一度確認するカードや、全端末ログアウトを警告するアカウント設定画面に向いています。

@keyframes shake커스텀 프로퍼티 --dangerfocus-visible 링
(function(){
  var card = document.querySelector('.signout-card'),
      cancel = card.querySelector('.signout-card__btn--cancel'),
      danger = card.querySelector('.signout-card__btn--danger');
  cancel.addEventListener('click', function(){ card.classList.remove('is-confirmed'); });
  danger.addEventListener('click', function(){ card.classList.add('is-confirmed'); });
}());

どこで壊れるか — 落とし穴

9つを作っている最中に実際に起きたバグが一つありました。認証コード入力グリッド(03)の自動フォーカス移動で、ただ.focus()を呼ぶだけだと、ブラウザは既定でその要素を画面内にスクロールさせようとします。320px幅のモバイル表示のように入力欄がスクロールコンテナの中にある場合、自動移動のたびに画面がわずかに揺れて見えました。

この揺れがデモ一つの問題で終わらないのには理由があります。このサイトは9つのデモをトップページの一覧と記事内のグリッドにiframeとして埋め込んでいるため、iframeの中で.focus()が既定どおりスクロールを起こすと、そのスクロールが親ページまで伝わります。訪問者が一覧を上へ戻している途中でも、グリッド内の認証コードのマスがフォーカスを受けるたびにページが下へ引き戻されるという動きになります。9つのうちスクリプトから.focus()を呼んでいるのは03だけなので直す箇所は3行でしたが、自動移動・Backspaceでの戻り・貼り付け時の6桁振り分けという3つの経路がすべて同じ呼び出しを通るため、1か所だけ直すと残りの2経路でまた揺れが出ます。デスクトップの幅では入力欄が最初から全部見えているので症状が出ず、320px幅に狭めて初めて再現できた点も、気づきにくさの原因でした。デモの計測は480×300と320×200の2つのビューポートで行っているので、狭いほうの計測がなければこの揺れは見逃していたはずです。そこで{ preventScroll: true }オプションを付け、すでに見えている要素同士を移動するときはスクロールを止めるようにしました(上の03のコードに反映済みです)。この対処はこの項目だけの話にとどまらず、サイト全体の.focus()呼び出しすべてに適用するルールになりました。ダウンロード用パスワードzkv9xjxtで開くzipの中には、この修正を反映したコード一式が入っています。

アクセシビリティ

9つともprefers-reduced-motion: reduceでは、権限モーダルのアイコンバウンス、キャプチャのばねバッジ、認証コード欄の枠の点滅、秘密の質問カードの冷めるアニメーション、選択カードの浮き上がり、ウィザードカードのスライド、連携アカウントのトグル、タイムアウトバナーの出入り、ログアウトカードの揺れといった装飾用のアニメーションをすべて止めますが、状態そのもの(許可・拒否、確認済み、入力値、選択、カウントダウンの数字など)はそのまま残ります。権限リクエストモーダル(01)はrole="alertdialog"aria-modalを備え、Escキーで閉じられます。キャプチャ確認(02)はネイティブチェックボックスのchecked状態で確認済みを伝え、認証コード入力(03)はinputmode=numericで数字キーボードを呼び出します。セッションタイムアウトバナー(08)はrole="alert"で残り時間の変化を即座に読み上げ、連携アカウント一覧(07)とログアウト確認(09)はfocus-visibleのリングでキーボード操作の位置を示します。落とし穴で触れた.focus()のスクロール挙動は、MDNのfocus()ドキュメントpreventScrollオプションの説明にまとまっています。

なお、この9つは画面のUI・アニメーションのパターンであり、実際のサーバー側認証(OTP検証やセッション管理)は行っていません。ログイン・会員登録の画面パターンはログイン・会員登録カードにまとめてあり、このサイト全体が何を扱っているかは紹介ページにあります。

FAQ

本人確認の画面に実際のサーバー側認証ロジックまで含まれますか?

いいえ、含まれていません。この9つは画面の見た目と動きだけを再現したUIパターンで、OTPの検証やセッション管理のようなサーバー連携は含まれません。zipの中のコードをもとに、自分のプロジェクトのAPIと接続する部分は別途実装する必要があります。

完成した認証フロー画面ではなく、この部品一つだけ使ってもいいですか?

はい、そのために9つに分けて作りました。各デモは認証フロー全体ではなく部品一枚だけを画面中央に置いており、zipの中にもその部品一つ分のHTML・SCSS・JSしか入っていないので、自分のプロジェクトの認証画面へそのまま移せます。

認証コード入力欄(03)の自動移動でスマホの画面が揺れることはありますか?

起きません。開発中は.focus()の既定スクロールが原因で320px幅のモバイル表示で画面がわずかに揺れる問題がありましたが、{ preventScroll: true }オプションを付けて修正済みです。zipに入っているコードにはこの修正がすでに反映されています。

解凍パスワードを入力してください

パスワードはこの記事の本文の中にあります。読み進めると出てきます。