入力されたパスワード強度を視覚的に分かるUI
概要
ユーザーが入力するパスワードの強度をリアルタイムで視覚的にフィードバックするUIコンポーネントです。
強度メーターと条件チェックリストにより、ユーザーは安全なパスワードを直感的に作成できます。セキュリティ向上とUX改善に繋がり、会員登録フォームなどに最適です。
単一のHTMLファイルで完結しているため、既存のプロジェクトにも容易に組み込むことが可能です。
デモサイト
ソースコード
まずはソースコードをご覧ください。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>オリジナルパスワード強度チェッカー</title> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet"> <style> @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap'); :root { --color-weak: #e74c3c; --color-medium: #f39c12; --color-strong: #2ecc71; --color-bg: #f4f7f6; --color-card-bg: #ffffff; --color-text: #333; --color-gray: #bdc3c7; --border-radius: 8px; } body { font-family: 'Noto Sans JP', sans-serif; background-color: var(--color-bg); color: var(--color-text); display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; padding: 20px; box-sizing: border-box; } .card { background-color: var(--color-card-bg); padding: 30px 40px; border-radius: var(--border-radius); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); width: 100%; max-width: 400px; } h1 { margin: 0 0 10px; text-align: center; font-size: 24px; } .subtitle { margin: 0 0 30px; text-align: center; color: #7f8c8d; } .form-group { margin-bottom: 20px; } .form-group label { display: block; margin-bottom: 8px; font-weight: 700; } .input-wrapper { position: relative; } .input-wrapper input { width: 100%; padding: 12px 40px 12px 15px; border: 1px solid var(--color-gray); border-radius: var(--border-radius); font-size: 16px; box-sizing: border-box; transition: border-color 0.3s; } .input-wrapper input:focus { outline: none; border-color: #3498db; } .toggle-password { position: absolute; top: 50%; right: 15px; transform: translateY(-50%); cursor: pointer; color: #95a5a6; } .strength-meter { height: 10px; background-color: #ecf0f1; border-radius: 10px; overflow: hidden; margin-top: -10px; } .strength-bar { height: 100%; width: 0; background-color: var(--color-weak); transition: width 0.3s, background-color 0.3s; } .strength-text { font-size: 14px; font-weight: 700; margin: 8px 0 15px; text-align: right; height: 1em; } .requirements-list { list-style: none; padding: 0; margin: 0 0 25px; font-size: 14px; color: #7f8c8d; } .requirements-list li { margin-bottom: 8px; transition: color 0.3s; } .requirements-list li::before { font-family: "Font Awesome 5 Free"; font-weight: 900; content: "\f00d"; margin-right: 10px; color: var(--color-weak); transition: content 0.3s, color 0.3s; } .requirements-list li.valid { color: var(--color-text); } .requirements-list li.valid::before { content: "\f00c"; color: var(--color-strong); } .match-text { font-size: 14px; margin-top: 8px; height: 1em; font-weight: bold; } </style> </head> <body> <main class="card"> <h1>パスワードを新規設定</h1> <p class="subtitle">安全なパスワードを設定してください</p> <form action="#" method="post" id="passwordForm"> <div class="form-group"> <label for="password">パスワード</label> <div class="input-wrapper"> <input type="password" id="password" name="password" placeholder="パスワードを入力" required> <i class="fa-solid fa-eye-slash toggle-password"></i> </div> </div> <div class="strength-meter"> <div class="strength-bar"></div> </div> <p class="strength-text"></p> <ul class="requirements-list"> <li data-requirement="length">8文字以上</li> <li data-requirement="lowercase">小文字の英字を1つ以上含む</li> <li data-requirement="uppercase">大文字の英字を1つ以上含む</li> <li data-requirement="number">数字を1つ以上含む</li> <li data-requirement="special">記号 (!, @, #, $, % など) を1つ以上含む</li> </ul> <div class="form-group"> <label for="password-cf">パスワード(確認用)</label> <div class="input-wrapper"> <input type="password" id="password-cf" name="password:cf" placeholder="もう一度パスワードを入力" required> </div> <p class="match-text"></p> </div> </form> </main> <script> document.addEventListener('DOMContentLoaded', () => { const passwordInput = document.getElementById('password'); const passwordCfInput = document.getElementById('password-cf'); const strengthBar = document.querySelector('.strength-bar'); const strengthText = document.querySelector('.strength-text'); const requirementsList = document.querySelector('.requirements-list'); const matchText = document.querySelector('.match-text'); const togglePassword = document.querySelector('.toggle-password'); const requirements = [ { regex: /.{8,}/, element: requirementsList.querySelector('[data-requirement="length"]') }, { regex: /[a-z]/, element: requirementsList.querySelector('[data-requirement="lowercase"]') }, { regex: /[A-Z]/, element: requirementsList.querySelector('[data-requirement="uppercase"]') }, { regex: /[0-9]/, element: requirementsList.querySelector('[data-requirement="number"]') }, { regex: /[^A-Za-z0-9]/, element: requirementsList.querySelector('[data-requirement="special"]') } ]; passwordInput.addEventListener('input', () => { const password = passwordInput.value; // --- 1. UIチェックリストの更新(この部分はUI表示のためだけ) --- requirements.forEach(req => { if (req.regex.test(password)) { req.element.classList.add('valid'); } else { req.element.classList.remove('valid'); } }); // --- 2. 強度判定ロジック --- if (password.length === 0) { strengthBar.style.width = '0%'; strengthText.textContent = ''; return; // 何も入力されていない場合はここで処理終了 } // まず、長さが足りなければ無条件で「弱い」 if (password.length < 8) { strengthBar.style.width = '25%'; strengthBar.style.backgroundColor = 'var(--color-weak)'; strengthText.textContent = '弱い'; strengthText.style.color = 'var(--color-weak)'; return; } // 長さが足りている場合、文字の種類の数で判定 let varietyCount = 0; if (/[a-z]/.test(password)) varietyCount++; if (/[A-Z]/.test(password)) varietyCount++; if (/[0-9]/.test(password)) varietyCount++; if (/[^A-Za-z0-9]/.test(password)) varietyCount++; switch (varietyCount) { case 1: // 長くても文字の種類が1つだけなら「弱い」 strengthBar.style.width = '25%'; strengthBar.style.backgroundColor = 'var(--color-weak)'; strengthText.textContent = '弱い'; strengthText.style.color = 'var(--color-weak)'; break; case 2: strengthBar.style.width = '50%'; strengthBar.style.backgroundColor = 'var(--color-medium)'; strengthText.textContent = '普通'; strengthText.style.color = 'var(--color-medium)'; break; case 3: case 4: strengthBar.style.width = '100%'; strengthBar.style.backgroundColor = 'var(--color-strong)'; strengthText.textContent = '安全'; strengthText.style.color = 'var(--color-strong)'; break; } checkPasswordMatch(); }); passwordCfInput.addEventListener('input', checkPasswordMatch); function checkPasswordMatch() { if (passwordCfInput.value.length === 0) { matchText.textContent = ''; return; } if (passwordInput.value === passwordCfInput.value) { matchText.textContent = '◎ パスワードが一致しました'; matchText.style.color = 'var(--color-strong)'; } else { matchText.textContent = '× パスワードが一致しません'; matchText.style.color = 'var(--color-weak)'; } } togglePassword.addEventListener('click', () => { const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password'; passwordInput.setAttribute('type', type); togglePassword.classList.toggle('fa-eye'); togglePassword.classList.toggle('fa-eye-slash'); }); }); </script> </body> </html>
SPIRALのデフォルトのデザインから少し離れていますが、必要な部分を切り取ってご利用ください。
入力文字強度の詳細
弱い (Weak) と判定される例
パスワードが8文字未満の場合、または8文字以上でも使われている文字の種類が1種類のみの場合に「弱い」と判定されます。
短いパスワード
例:p@ss123
(7文字のため、文字の種類に関わらず「弱い」と判定されます)
1種類の文字だけで構成された長いパスワード
例:passwordlong
(8文字以上ですが、使われている文字が小文字の1種類だけのため「弱い」と判定されます)
例:AAAAAAAAAA
(8文字以上ですが、使われている文字が大文字の1種類だけのため「弱い」と判定されます)
パスワードが8文字以上で、かつ使われている文字の種類が2種類の場合に「普通」と判定されます。
例: password12345
(小文字 + 数字 の2種類)
例: Passwordtest
(大文字 + 小文字 の2種類)
例: password-test
(小文字 + 記号 の2種類)
パスワードが8文字以上で、かつ使われている文字の種類が3種類以上の場合に「安全」と判定されます。
3種類利用の例 (大文字 + 小文字 + 数字)
例:Password12345
4種類すべて利用の例 (最も安全)
例:Str0ng-Pa55!word
注意事項
このコンポーネントを利用する上で、特に重要な点は以下の通りです。
1. フロントエンドでの検証について
このツールが行っているのは、あくまでユーザーの利便性を高めるためのフロントエンド(ブラウザ側)でのチェックです。入力されたパスワードがそのままサーバーに送信されるのを防ぐものではありません。
2. 強度の判定基準のカスタマイズ
パスワードの強度を決めるルール(文字数や必須の文字種)は、JavaScript内の配列で定義されています。サイトのセキュリティポリシーに応じて、この基準は自由に変更・強化することが可能です。
// この部分の正規表現を変更することで、ルールをカスタマイズできます const requirements = [ { regex: /.{8,}/, element: requirementsList.querySelector('[data-requirement="length"]') }, { regex: /[a-z]/, element: requirementsList.querySelector('[data-requirement="lowercase"]') }, { regex: /[A-Z]/, element: requirementsList.querySelector('[data-requirement="uppercase"]') }, { regex: /[0-9]/, element: requirementsList.querySelector('[data-requirement="number"]') }, { regex: /[^A-Za-z0-9]/, element: requirementsList.querySelector('[data-requirement="special"]') } ];
3. 外部ライブラリへの依存
チェックリストやパスワード表示/非表示のアイコンは、外部のWebサービスである「Font Awesome」から読み込んでいます。
そのため、オフライン環境や、セキュリティポリシーで外部CDNへのアクセスが制限されている環境では、アイコンが表示されない場合があります。
おわりに
今回は、パスワードの強度を視覚的にチェックし、ユーザーの入力を補助するUIコンポーネントを紹介しました。
複雑なパスワード要件をユーザーに分かりやすく伝え、より安全なパスワードの設定を促すことで、サイト全体のセキュリティ向上とUX改善に直接的に貢献します。
提供したコードは単一ファイルで完結しているため、様々なプロジェクトへ容易に導入できるのが特徴です。
ここで紹介したコードは、あくまで一つのサンプルです。デザインや強度の判定ロジックを、ご自身のサービスの要件に合わせて自由にカスタマイズしてみてください。
【お知らせ】本実装の構築代行・カスタマイズを承ります
記事でご紹介した内容や、貴社の要件に合わせた柔軟なカスタマイズ開発を承っております。
SPIRALの専門チームが要件定義から実装まで一貫してサポートいたしますので、まずはお見積もりをご依頼ください。