No.156
MICRO CSSJS

Password Strength Meter

パスワードを入力すると4段のメーターが色を変えながら伸び、満たした条件にチェックが付く強度表示。表示・非表示の切り替えと、読み上げへの通知まで含めています。

DEMO

未入力

  • 8文字以上
  • 大文字と小文字
  • 数字
  • 記号

CODE

HTML
<div class="demo-stage pwm-stage">
  <div class="pwm-box">
    <label class="pwm-lbl" for="pwm-input">パスワード</label>
    <div class="pwm-row">
      <input id="pwm-input" class="pwm-input" type="password" autocomplete="new-password" aria-describedby="pwm-strength pwm-rules">
      <button type="button" class="pwm-eye" id="pwm-eye" aria-pressed="false">表示</button>
    </div>
    <div class="pwm-bar" aria-hidden="true"><i></i><i></i><i></i><i></i></div>
    <p class="pwm-strength" id="pwm-strength" aria-live="polite">未入力</p>
    <ul class="pwm-rules" id="pwm-rules">
      <li data-rule="len">8文字以上</li>
      <li data-rule="case">大文字と小文字</li>
      <li data-rule="num">数字</li>
      <li data-rule="sym">記号</li>
    </ul>
  </div>
</div>
CSS
.pwm-stage { display:flex; align-items:center; justify-content:center; padding:2rem; background:#0B0B10; min-height:300px; }
.pwm-box { width:100%; max-width:320px; }
.pwm-lbl { display:block; margin-bottom:.4rem; color:#C9C9D1; font-size:.8rem; }
.pwm-row { display:flex; gap:.5rem; }
.pwm-input { flex:1; min-width:0; padding:.7rem .8rem; font-size:16px; color:#EDEDED; background:#15151B; border:1px solid rgba(255,255,255,.14); border-radius:9px; outline:none; }
.pwm-input:focus { border-color:#E91B89; box-shadow:0 0 0 3px rgba(233,27,137,.22); }
.pwm-eye { padding:0 .8rem; min-height:44px; border:1px solid rgba(255,255,255,.14); border-radius:9px; background:#1E1E26; color:#C9C9D1; font-size:.78rem; cursor:pointer; }
.pwm-eye:focus-visible { outline:2px solid #E91B89; outline-offset:2px; }
.pwm-bar { display:grid; grid-template-columns:repeat(4,1fr); gap:5px; margin-top:.8rem; }
.pwm-bar i { height:6px; border-radius:3px; background:rgba(255,255,255,.1); overflow:hidden; position:relative; }
.pwm-bar i::after { content:''; position:absolute; inset:0; background:var(--pwm-c,#F87171); transform:scaleX(0); transform-origin:left; transition: transform .3s cubic-bezier(.22,1,.36,1), background .3s ease; }
.pwm-bar i.on::after { transform:scaleX(1); }
.pwm-strength { margin:.5rem 0 .6rem; font-size:.8rem; color:var(--pwm-c,#8A8A96); }
.pwm-rules { list-style:none; margin:0; padding:0; display:grid; grid-template-columns:1fr 1fr; gap:.3rem .8rem; }
.pwm-rules li { position:relative; padding-left:1.2rem; color:#8A8A96; font-size:.76rem; transition: color .2s ease; }
.pwm-rules li::before { content:''; position:absolute; left:0; top:.28em; width:.7rem; height:.7rem; border-radius:50%; border:1px solid currentColor; }
.pwm-rules li.ok { color:#34D399; }
.pwm-rules li.ok::before { background:currentColor; }
@media (prefers-reduced-motion: reduce) {
  .pwm-bar i::after, .pwm-rules li { transition-duration:.01ms; }
}
JS
(function(){
  var input = document.getElementById('pwm-input');
  var eye = document.getElementById('pwm-eye');
  var out = document.getElementById('pwm-strength');
  var box = input && input.closest('.pwm-box');
  if (!input || !out || !box) return;
  var bars = box.querySelectorAll('.pwm-bar i');
  var rules = box.querySelectorAll('.pwm-rules li');
  var TESTS = { len: function(v){ return v.length >= 8; }, 'case': function(v){ return /[a-z]/.test(v) && /[A-Z]/.test(v); },
                num: function(v){ return /\d/.test(v); }, sym: function(v){ return /[^A-Za-z0-9]/.test(v); } };
  var LEVELS = [['未入力', '#8A8A96'], ['弱い', '#F87171'], ['やや弱い', '#FB923C'], ['普通', '#FACC15'], ['強い', '#34D399']];
  function update(){
    var v = input.value, score = 0;
    rules.forEach(function(li){ var ok = v && TESTS[li.dataset.rule](v); li.classList.toggle('ok', !!ok); if (ok) score++; });
    if (v && score === 0) score = 1;
    var lv = LEVELS[v ? score : 0];
    box.style.setProperty('--pwm-c', lv[1]);
    bars.forEach(function(b, i){ b.classList.toggle('on', i < (v ? score : 0)); });
    out.textContent = v ? '強度: ' + lv[0] : '未入力';
  }
  input.addEventListener('input', update);
  if (eye) eye.addEventListener('click', function(){
    var show = input.type === 'password';
    input.type = show ? 'text' : 'password';
    eye.textContent = show ? '隠す' : '表示';
    eye.setAttribute('aria-pressed', show ? 'true' : 'false');
  });
  update();
})();

AI PROMPT

Claude Code Cursor v0
PROMPT
パスワードを入力すると4段のメーターが色を変えながら伸び、満たした条件にチェックが付く強度表示を作って。条件は「8文字以上」「大文字と小文字」「数字」「記号」の4つで、満たした数をスコアにする(何か入力されていれば最低1)。メーターは4つのバーを grid で並べ、各バーの ::after を transform: scaleX(0→1)(transform-origin: left)で伸ばす。色はスコアに応じて赤→橙→黄→緑へ変え、カスタムプロパティ --pwm-c に入れてバーと強度の文字色の両方に使う。強度の文字(「強度: 普通」など)は aria-live="polite" で読み上げに伝え、入力欄は aria-describedby で強度と条件の一覧に関連付ける。横に「表示/隠す」の切り替えボタンを置き、input の type を password と text で切り替え、aria-pressed で状態を示す。autocomplete="new-password"、font-size は16px以上。@media (prefers-reduced-motion: reduce) で transition を無効化する。なお、この4条件は目安であり、本番では辞書語や使い回しを考慮する推定ライブラリ(zxcvbn など)や、漏洩済みパスワードとの照合を検討すること。

Acceptance criteria: works with prefers-reduced-motion (animation disabled), zero console errors, zero layout shift

AIエージェントでの実装ガイド → Claude Code でWebアニメーションを実装する

BOOKS · PR · AMAZON

📖 なかしまぁ先生のCSSアニメーション入門 📖 マイクロインタラクション ―UI/UXデザインの神が宿る細部 📖 Fundamentals of Web Animation with GSAP

※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。

学びを止めない · AMAZONサブスク

📚 Kindle Unlimited — 技術書・デザイン書が読み放題。30日無料体験 → 🎧 Audible — 移動中に耳で学ぶオーディオブック。30日無料体験 → 📦 Amazon Prime — Prime Reading・配送特典つき。30日無料体験 → 🎵 Music Unlimited — 作業用BGMに。1億曲が聴き放題・30日無料体験 →

※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。

RELATED EFFECTS

↗ MORE
→ FLOATING LABEL → PROGRESS BAR → CHECKBOX ANIMATION

Password Strength Meter(パスワード強度メーター)とは

新規登録やパスワード変更の画面で、入力中のパスワードがどれくらい強いかをバーの長さと色で示す部品です。条件を満たしていくたびにバーが伸びるので、利用者は「あと何をすれば良いか」をその場で確かめながら入力できます。

当サイトの Floating Label は入力欄のラベルの動き、Progress Bar は処理の進み具合を示すバーです。本ページは入力内容そのものを評価して段階的に表示する別テーマで、フォームの入力支援として使えます。

注意点は、ここで使っている4つの条件が目安にすぎないことです。見た目の部品としてはそのまま使えますが、強さの判定は本番の要件に合わせて置き換えてください。色だけでなく言葉でも強さを伝えることも欠かせません。

よくある質問

この4つの条件を満たせば安全なパスワードですか?

いいえ、目安にすぎません。「Password1!」のように条件をすべて満たしても、よく使われる語の組み合わせは簡単に推測されます。本番では、辞書語や並びのパターンから強さを推定するライブラリ(zxcvbn など)の利用や、漏洩済みパスワードの一覧と照合する仕組みを検討してください。記号や大文字を強制するより、長さを確保するほうが効果的だという考え方も広く採られています。

強度の変化を読み上げに伝えるには?

強度を表示する要素に aria-live="polite" を付けると、文字が変わるたびに入力の区切りで読み上げられます。あわせて入力欄に aria-describedby で強度と条件の一覧を関連付けておくと、欄にフォーカスした時点で何が求められているかが伝わります。色だけで強さを表さず、必ず言葉でも示してください。

コードは無料で使えますか?

はい。Motion LabのコードスニペットとAIプロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。