GODRICH
#cssアニメーション#ボタン#ローディング#トランジション#スクロール#ダッシュボード#実用ui#デザイントレンド

パスワード強度チェック UI 9選 — 強度の値が計算される仕組み

9つのうち1つは文字種の値がいくつ混ざっているかで強度の値が決まり、1つはよくある値のリストと同じ状態になると強度の値が減り、もう1つは確認入力の値と元の値が食い違い始める位置の値をリアルタイムで見つけます。パスワード強度チェック、9つの作り方です。

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

以下の9項目はどれもサーバーと通信せず、それぞれの強度・ビット・差分の値は今入力欄に入っている値だけからブラウザの中で計算されます。9つの項目には合計10個の実際のinputリスナーが配線されており、8項目はそれぞれ1個ずつ、確認欄を扱う08だけは2つのフィールドに1個ずつで、貼り付け・削除・1文字の入力のどれが起きても同じ値が再計算されます。どの入力欄もtype="text"のまま保たれ、点で隠す処理はネイティブのパスワード欄やJavaScriptによるマスキングではなく、CSSのプロパティ-webkit-text-security: discによるものです。読み込み時に流れるプレビューは固定された文字列の配列を順番になぞるだけで、これら9つのファイルのどこにもMath.randomは使われておらず、prefers-reduced-motion: reduceの判定はこの自動再生ループだけを止め、実際のキー入力の挙動には触れません。

9つの方式の構造 — どの値がいつ変わるか

決まった境界値で段が切り替わる2方式

01の4つの文字数境界と06の6つの時間単位境界は同じ仕組みで動きます — 内部では連続した数値がキー入力のたびに変わり続けているのに、表示される段や単位はその数値が短いリストの中の1点を越えた瞬間にしか更新されません。境界と境界の間でどれだけ文字を打っても、下の値自体は動いていてもラベルは動かないままです。

複数の下位値から強度の値を組み立てる4方式

02・03・07・09はどれも1つの測定値だけを読むのではなく、複数の小さな値から出力値を組み立てます — 一致した文字種パターンの数、文字数と文字集合の大きさをかけた計算、4条件の真偽の比率、あるいは長さの比率と文字種の比率を半分ずつ混ぜた値です。この4つのどれも入力の生の文字数だけを見ているわけではありません。

値を減らしたり別の値と照らし合わせたりする3方式

04と05はどちらも文字数を基にした同じ基礎点から出発し、そこから値を引きます — 04はよくある値のリストと一致した場合に一定の値を、05は同じ文字の連続や順序だった数字の区間の長さに応じた値を引きます。08は採点そのものをせず、代わりに2つの入力値を先頭から1文字ずつ比べ、どこで一致しなくなるかを探します。

方式ごとのコード

見出しの上にあるデモは、その下のコードフェンスと同じファイルから来ています — 合わせて読めば、計算の仕組みをライブラリの裏に隠さない、なかなか揃ったパスワード強度チェッカーの実例集になります。フェンスはその項目自身のindex.htmlから5〜25行の連続した区間を切り出したもので、識別子や波かっこは書かれたまま変えていません。

01文字数境界塗り — 入力値の文字数がいくつかの境界値を超えるたびに強度の値が次の段階に上がる方式

入力された値の文字数がいくつかの決められた境界値を超えるたびに強度の値が次の段階に上がります。会員登録フォームの基本パスワード入力や、最小文字数の基準を案内するアカウント設定はこの境界越えだけを見ていて、途中の細かい文字数は問いません。

文字数境界塗り — 入力値の文字数がいくつかの境界値を超えるたびに強度の値が次の段階に上がる方式
新しいタブで開く

01 · 文字数境界塗り — 入力値の文字数がいくつかの境界値を超えるたびに強度の値が次の段階に上がる方式 — 計測 累積面積 3.317% · 動いたフレーム 15/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

THRESHOLDS = [4,8,12,16]stageOf(len)STAGE_CLASS

数値が語ること

計測した24フレームのうち23コマの遷移で01が動くのは15回で、累積面積は3.317%、平均強度は103.7ですが、塗りが4つの境界を越えた瞬間にしか動かないため動きは少なめです。

  // 計算レイヤー: 入力値の文字数がこれらの境界値を超えるたびに、強度の値(0-4)が1段階ずつ上がります。
  var THRESHOLDS = [4, 8, 12, 16];
  var STAGE_CLASS = ['pw--s0', 'pw--s1', 'pw--s2', 'pw--s3', 'pw--s4'];

  function stageOf(len) {
    var s = 0;
    for (var i = 0; i < THRESHOLDS.length; i++) { if (len >= THRESHOLDS[i]) s = i + 1; }
    return s;
  }

  function paint(value) {
    var len = value.length;
    var stage = stageOf(len);
    var ratio = stage / THRESHOLDS.length;
    fill.style.transform = 'scaleX(' + ratio + ')';
    STAGE_CLASS.forEach(function (c) { root.classList.remove(c); });
    root.classList.add(STAGE_CLASS[stage]);
    label.textContent = '境界 ' + stage + '/4';
    lenEl.textContent = String(len);
  }

02文字種数塗り — 入力値に混ざった異なる文字種の値の数によって強度の値が決まる方式

入力値の中に異なる文字種の値がいくつ混ざっているかによって強度の値が決まります。大文字小文字・数字・記号の組み合わせを求めるアカウントセキュリティ設定や、社内システムのパスワード変更フォームは、この数をそのまま4つのバッジの点灯数として使います。

文字種数塗り — 入力値に混ざった異なる文字種の値の数によって強度の値が決まる方式
新しいタブで開く

02 · 文字種数塗り — 入力値に混ざった異なる文字種の値の数によって強度の値が決まる方式 — 計測 累積面積 9.395% · 動いたフレーム 22/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

CLASSES 정규식 4종countClasses(value).cc__badge--on

数値が語ること

計測した24フレームのうち23コマの遷移で02が動くのは22回で、累積面積は9.395%、平均強度は119.4と9項目中最大になりますが、これはシーケンスのほぼ毎ステップで4つのバッジと塗りバーが同時に塗り直されるためです。

  // 計算レイヤー: 入力値が4つの文字種パターンに対して検査され、真になった数が集計されます。
  var CLASSES = [/[a-z]/, /[A-Z]/, /[0-9]/, /[^A-Za-z0-9]/];

  function countClasses(value) {
    var n = 0;
    for (var i = 0; i < CLASSES.length; i++) {
      var hit = CLASSES[i].test(value);
      badges[i].classList.toggle('cc__badge--on', hit);
      if (hit) n++;
    }
    return n;
  }

  function paint(value) {
    var n = countClasses(value);
    fill.style.transform = 'scaleX(' + (n / CLASSES.length) + ')';
    label.textContent = '文字種 ' + n + '/4';
  }

03エントロピービット値表示 — 文字集合の大きさの値と文字数の値をかけた計算から強度の値が出る方式

文字集合の大きさの値と文字数の値をかけた計算から出るビット値が大きいほど強度の値が高く付けられます。セキュリティ水準を数値で確かめさせる開発者向けアカウント設定や、APIキー発行画面のシークレット値の強度表示は、あいまいなラベルの代わりにこのビット値をそのまま出します。

エントロピービット値表示 — 文字集合の大きさの値と文字数の値をかけた計算から強度の値が出る方式
新しいタブで開く

03 · エントロピービット値表示 — 文字集合の大きさの値と文字数の値をかけた計算から強度の値が出る方式 — 計測 累積面積 4.297% · 動いたフレーム 22/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

charsetSize(value)bitsOf(value)MAX_BITS = 100

数値が語ること

計測した24フレームのうち23コマの遷移で03が動くのは22回で、累積面積は4.297%、平均強度は183.8ですが、ビットの値が文字数と文字集合の大きさの両方で連続的に増えるため、数段階の跳躍ではなくほぼ毎フレームで塗りが伸び続けます。

  // 計算レイヤー: 混ざった文字種から文字集合の大きさの値が決まり、それを文字数の値でかけたあと、
  // 底が2の対数を取ることでビット値に変換します(エントロピー = 文字数 × log2(文字集合の大きさ))。
  function charsetSize(value) {
    var size = 0;
    if (/[a-z]/.test(value)) size += 26;
    if (/[A-Z]/.test(value)) size += 26;
    if (/[0-9]/.test(value)) size += 10;
    if (/[^A-Za-z0-9]/.test(value)) size += 32;
    return size;
  }

  function bitsOf(value) {
    var size = charsetSize(value);
    if (!value.length || size === 0) return { bits: 0, size: size };
    return { bits: value.length * (Math.log(size) / Math.log(2)), size: size };
  }

  function paint(value) {
    var r = bitsOf(value);
    var bits = Math.round(r.bits);
    bitsEl.textContent = String(bits);
    fill.style.transform = 'scaleX(' + Math.min(1, r.bits / MAX_BITS) + ')';
    setEl.textContent = String(r.size);
    lenEl.textContent = String(value.length);
  }

04よくある値減点 — 入力値があらかじめ決めたよくある値のリストと同じ状態になると強度の値が減る方式

入力値があらかじめ決めておいたよくある値のリストと同じ状態になると強度の値から一定の値だけ引かれます。使い回しの簡単なパスワードを防ぐ登録フォームや、よく漏えいする値をはじくアカウント設定は、この完全一致による減点だけを仕組みにしています。

よくある値減点 — 入力値があらかじめ決めたよくある値のリストと同じ状態になると強度の値が減る方式
新しいタブで開く

04 · よくある値減点 — 入力値があらかじめ決めたよくある値のリストと同じ状態になると強度の値が減る方式 — 計測 累積面積 3.392% · 動いたフレーム 21/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

COMMON 배열 10종PENALTY = 40.cl--hit

数値が語ること

計測した24フレームのうち23コマの遷移で04が動くのは21回で、累積面積は3.392%、平均強度は105.5ですが、シーケンスの値がよくある値リストと完全に一致する2コマだけ塗りが大きく下がります。

  // 計算レイヤー: 架空のよくある値リスト(10個の一般的なパターンで、実際の漏えい値リストではありません) — 実在するサービス名は0件です。
  var COMMON = ['password', '123456', 'qwerty', '111111', 'abc123',
                'letmein', 'iloveyou', 'admin', 'welcome', 'monkey'];
  var PENALTY = 40;

  function scoreOf(value) {
    var base = Math.min(100, value.length * 8);
    var hit = value.length > 0 && COMMON.indexOf(value.toLowerCase()) !== -1;
    var score = hit ? Math.max(0, base - PENALTY) : base;
    return { score: score, hit: hit };
  }

  function paint(value) {
    var r = scoreOf(value);
    fill.style.transform = 'scaleX(' + (r.score / 100) + ')';
    root.classList.toggle('cl--hit', r.hit);
    scoreEl.textContent = String(r.score);
    warn.style.opacity = r.hit ? '1' : '0';
    warn.style.transform = r.hit ? 'scale(1)' : 'scale(.7)';
  }

05反復・順次値減点 — 同じ文字が連続したり数字の値が順番に続く区間の分だけ強度の値が減る方式

同じ文字が連続したり数字の値が順番に続く区間が見つかると、その長さの値の分だけ強度の値が減ります。1234・aaaaのような値をはじくアカウントセキュリティ設定や、パターン化した値を検知する登録フォームは、この区間の長さに応じた減点に頼っています。

反復・順次値減点 — 同じ文字が連続したり数字の値が順番に続く区間の分だけ強度の値が減る方式
新しいタブで開く

05 · 反復・順次値減点 — 同じ文字が連続したり数字の値が順番に続く区間の分だけ強度の値が減る方式 — 計測 累積面積 3.086% · 動いたフレーム 22/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

flagPositions(value)PER_CHAR_PENALTY = 8.rs__chip--on

数値が語ること

計測した24フレームのうち23コマの遷移で05が動くのは22回で、累積面積は3.086%、平均強度は135.5ですが、シーケンスがパターン化した値と混在した値を交互に繰り返すため、チップの点灯と消灯がほとんどのフレームで切り替わります。

  function flagPositions(value) {
    var n = value.length;
    var flag = new Array(n).fill(false);
    var i = 0;
    while (i < n) {
      var j = i;
      while (j + 1 < n && value.charCodeAt(j + 1) === value.charCodeAt(j)) j++;
      if (j - i + 1 >= 3) for (var k = i; k <= j; k++) flag[k] = true;
      i = j + 1;
    }
    i = 0;
    while (i < n - 1) {
      var dir = value.charCodeAt(i + 1) - value.charCodeAt(i);
      if (dir === 1 || dir === -1) {
        var j2 = i + 1;
        while (j2 + 1 < n && value.charCodeAt(j2 + 1) - value.charCodeAt(j2) === dir) j2++;
        if (j2 - i + 1 >= 3) for (var k2 = i; k2 <= j2; k2++) flag[k2] = true;
        i = j2;
      } else {
        i++;
      }
    }
    return flag;
  }

06推定時間値単位切替 — 計算されたビットの値が境界値を過ぎるたびにかかる時間を表す値の単位が変わる方式

計算されたビットの値がいくつかの決められた境界値を過ぎるたびに、かかる時間を表す値の単位が変わって現れます。セキュリティ意識を助けるアカウント設定画面や、開発者向けのシークレット値発行ツールは、この単位が変わった推定値を見出しの値として使います。

推定時間値単位切替 — 計算されたビットの値が境界値を過ぎるたびにかかる時間を表す値の単位が変わる方式
新しいタブで開く

06 · 推定時間値単位切替 — 計算されたビットの値が境界値を過ぎるたびにかかる時間を表す値の単位が変わる方式 — 計測 累積面積 7.119% · 動いたフレーム 14/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

GUESSES_PER_SEC = 1e6guessesOf(value)UNITS 단위 배열

数値が語ること

計測した24フレームのうち23コマの遷移で06が動くのは14回で、累積面積は7.119%、平均強度は179.7ですが、単位のラベルは計算されたビットの値が6つの境界のどれかを越えたときにしか変わらないため、変化するフレームは一部にとどまります。

  // 計算レイヤー: 文字集合の大きさの値を文字数の値でべき乗すると組み合わせ数が求まり、それを仮定した1秒あたりの
  // 推測回数で割って秒数の値を出し、それを単位の段階に変換します(秒→分→時間→日→年→世紀)。
  function guessesOf(value) {
    var size = charsetSize(value);
    if (!value.length || size === 0) return 0;
    return Math.pow(size, value.length);
  }

  var UNITS = [
    { at: 1, name: '秒' },
    { at: 60, name: '分', div: 60 },
    { at: 3600, name: '時間', div: 3600 },
    { at: 86400, name: '日', div: 86400 },
    { at: 31536000, name: '年', div: 31536000 },
    { at: 31536000 * 100, name: '世紀', div: 31536000 * 100 }
  ];

07条件充足比率リアルタイム反映 — 複数の条件の値が真になる数の値の比率が強度の値に変わる方式

複数の条件の値がそれぞれ真になるかリアルタイムで検査され、真になった条件の値の数が全体の条件数の値に対する比率として強度の値に反映されます。要求条件を項目ごとに案内する登録フォームや、社内ポリシーの条件を並べるアカウント設定は、この比率を4つのチェックマークと一緒に見せます。

条件充足比率リアルタイム反映 — 複数の条件の値が真になる数の値の比率が強度の値に変わる方式
新しいタブで開く

07 · 条件充足比率リアルタイム反映 — 複数の条件の値が真になる数の値の比率が強度の値に変わる方式 — 計測 累積面積 4.904% · 動いたフレーム 20/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

CHECKS 기준 4종.cx__item--onSVG path 체크 아이콘

数値が語ること

計測した24フレームのうち23コマの遷移で07が動くのは20回で、累積面積は4.904%、平均強度は136.7ですが、シーケンスが条件を満たす文字を1つ足したり引いたりするたびにバーと4つのチェックマークが同時に塗り直されます。

  // 計算レイヤー: 4つの条件がそれぞれ評価され、真になった数が集計されたあと、その比率(数/4)がバーの塗りに
  // 反映されます — 各バッジは個別の条件の真偽によって点灯し、数によってではありません。
  var CHECKS = {
    len: function (v) { return v.length >= 8; },
    upper: function (v) { return /[A-Z]/.test(v); },
    digit: function (v) { return /[0-9]/.test(v); },
    special: function (v) { return /[^A-Za-z0-9]/.test(v); }
  };

  function paint(value) {
    var met = 0;
    items.forEach(function (li) {
      var key = li.getAttribute('data-key');
      var ok = CHECKS[key](value);
      li.classList.toggle('cx__item--on', ok);
      if (ok) met++;
    });
    fill.style.transform = 'scaleX(' + (met / items.length) + ')';
  }

08確認値リアルタイム照合 — 確認入力の値と元の値が食い違い始める位置の値をリアルタイムで見つける方式

確認入力の値と元の値を先頭から1文字ずつ比べ、値が食い違い始める位置の値をリアルタイムで見つけます。パスワード確認欄がある登録フォームや、再設定画面の値の一致確認は、一致か不一致かの単純な判定ではなく、この食い違う位置の値に頼っています。

確認値リアルタイム照合 — 確認入力の値と元の値が食い違い始める位置の値をリアルタイムで見つける方式
新しいタブで開く

08 · 確認値リアルタイム照合 — 確認入力の値と元の値が食い違い始める位置の値をリアルタイムで見つける方式 — 計測 累積面積 1.86% · 動いたフレーム 7/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

matchLenOf(a, b).md__chip--bad.md--full

数値が語ること

計測した24フレームのうち23コマの遷移で08が動くのは7回と9項目中最少で、累積面積は1.86%、平均強度は125.0ですが、これは固定されたパスワードの値が変わらないまま確認欄の値だけがシーケンスに沿って1文字ずつ進むためです。

  function paint() {
    var a = pw.value, b = confirm.value;
    var matchLen = matchLenOf(a, b);
    var full = b.length > 0 && a.length === b.length && matchLen === a.length;

    chipsBox.innerHTML = '';
    for (var i = 0; i < b.length; i++) {
      var chip = document.createElement('span');
      chip.className = 'md__chip ' + (i < matchLen ? 'md__chip--ok' : 'md__chip--bad');
      chipsBox.appendChild(chip);
    }

    if (b.length === 0) statusEl.textContent = '入力待ち';
    else if (full) statusEl.textContent = b.length + '文字完全一致';
    else if (matchLen === b.length) statusEl.textContent = matchLen + '文字まで一致・入力継続';
    else statusEl.textContent = matchLen + '文字まで一致・' + (matchLen + 1) + '番目で不一致';

    root.classList.toggle('md--full', full);
  }

09連続色値変化 — 強度の値が段階で切り替わらず連続した値として変わり、色の値もなめらかにつながる方式

強度の値がいくつかの決まった段階でぱっと切り替わらず連続した値として変わり、それに対応する色の値も一緒になめらかに変わります。きめ細かい視覚フィードバックを与えるアカウント設定画面や、デザイン性を打ち出した登録フォームは、段の代わりにこの連続した値を使います。

連続色値変化 — 強度の値が段階で切り替わらず連続した値として変わり、色の値もなめらかにつながる方式
新しいタブで開く

09 · 連続色値変化 — 強度の値が段階で切り替わらず連続した値として変わり、色の値もなめらかにつながる方式 — 計測 累積面積 3.354% · 動いたフレーム 22/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

STOPS 색 정지점 3개colorAt(t)scoreT(value)

数値が語ること

計測した24フレームのうち23コマの遷移で09が動くのは22回で、累積面積は3.354%、平均強度は90.9と9項目中最小ですが、塗りの幅と補間された色の値がほぼ毎フレームで変わる一方、バー自体は段の上で細く低コントラストな形のままです。

  // 計算レイヤー: 文字数の比率と文字種の比率を半分ずつ混ぜた連続値(0-1)を作り、その値を3つの色のポイント
  // (赤→黄→ミント)の間でRGB線形補間します — 入力のたびに再計算されます。
  var STOPS = [
    { t: 0,    rgb: [194, 54, 26] },
    { t: 0.5,  rgb: [255, 210, 63] },
    { t: 1,    rgb: [76, 212, 166] }
  ];

  function lerp(a, b, f) { return a + (b - a) * f; }

  function colorAt(t) {
    t = Math.max(0, Math.min(1, t));
    var lo = STOPS[0], hi = STOPS[STOPS.length - 1];
    for (var i = 0; i < STOPS.length - 1; i++) {
      if (t >= STOPS[i].t && t <= STOPS[i + 1].t) { lo = STOPS[i]; hi = STOPS[i + 1]; break; }
    }
    var span = hi.t - lo.t || 1;
    var f = (t - lo.t) / span;
    var r = Math.round(lerp(lo.rgb[0], hi.rgb[0], f));
    var g = Math.round(lerp(lo.rgb[1], hi.rgb[1], f));
    var b = Math.round(lerp(lo.rgb[2], hi.rgb[2], f));
    return 'rgb(' + r + ',' + g + ',' + b + ')';
  }

値を動かすと方式がどう変わるか — 境界・減点・単位の定数

01の境界位置はどの文字数がどの段に届くかを決め、段の数自体は決めない

4つの境界値を4/8/12/16から6/10/14/18に動かしても段の数は変わらず、5段のままです。変わるのは各段に届くために必要な文字数で、以前は2段目だった8文字の値が今は1段目にしか届かなくなります。

04の減点幅は落ちる深さを決め、引っかかるかどうかは決めない

04の減点の値を40から70に上げても、よくある値リストとの完全一致という判定条件自体は変わりません。変わるのは一致したときにどれだけ点が落ちるかで、以前は多少の点が残った値も、今はほぼ0まで落ちるようになります。

06の1秒あたり推測回数は表示される単位を決め、組み合わせ数そのものは決めない

06の仮定する推測回数の値を1e6から1e9に上げても、同じ入力から出る組み合わせ数自体は変わりません。変わるのはその組み合わせ数をより大きな値で割った結果で、表示される推定時間の単位が年ではなく秒や日といった小さな単位で読めるようになります。

この3つの定数は、この記事の9方式が既存の他の記事とつながる位置でもあります。ログイン・会員登録カードUIパターン(206)は、送信ボタンが押せる状態の値をすべての欄が単に埋まっているかどうかから計算していて、ここの9つのような段階付きの強度の値からは計算していません。フォームバリデーションのフィードバック(225)は、1つの欄のメッセージ表示の値をその欄1つだけの合否判定から計算していて、02・03・07・09のように複数の下位値を混ぜ合わせることはしません。フォームバリデーションUI(254)は、ページ全体のまとめ値をすべての欄の状態を一度に集計して計算していて、08が追いかけるような1キー入力ごとのライブな位置の値とは別物です。この記事の裏にあるzipには9つすべてのindex.htmlとstyle.scssが一緒に入っていて、上で読んだのと同じ値のまま84k56vcxというパスワードで開けます。

こんな時に壊れる — 惜しいコピペ・非常に長い値・非ラテン文字

よくある値を1文字だけ変えて貼り付けた場合

04の減点はよくある値リストとの完全一致(大文字小文字は区別しない)にしか反応しないため、passwordの代わりにPassword1を貼り付けると判定は完全にすり抜け、実際には1文字の置き換えと1桁の追加しか違わないのに、よくある値がまったく関わっていないかのようなスコアになります。

非常に長い値を入力した場合

03のビット値と06の組み合わせ数はどちらも文字数が増えるほど際限なく大きくなりますが、バーの塗りにはそれぞれ上限があります — 03はMAX_BITSという100ビットの天井で、06は底が10の対数でLOG_MAXという12の天井で塗りを止めるため、同じ文字集合の60文字の値と30文字の値でも、下の数値はまったく釣り合っていないのに見た目は同じ満タンのバーになります。これはパスワード強度 判定の仕組みを設計するときに見落としやすい落とし穴です。

非ラテン文字が含まれる値の場合

02・03・06・07・09はどれも同じ/[^A-Za-z0-9]/という正規表現で文字を分類するため、日本語・韓国語やアクセント付きの文字は!や#と同じ1つの記号バケツにまとめられます。03の文字集合の大きさの計算はそのバケツ全体に対して一律32を足すだけなので、実際にどれだけ多様な記号や文字種が含まれていても、非ラテン文字を含む値の本当の文字集合の大きさを過小に見積もります。

3つの変形とアクセシビリティ

項目 定数 値 何が変わるか
01 文字数境界塗り THRESHOLDS [4,8,12,16] → [6,10,14,18] 段の数は同じ5段のまま、各段に届くのに必要な文字数だけが延びる
04 よくある値減点 PENALTY 40 → 70 一致の判定条件は同じまま、一致した値のスコアがより深く落ちる
06 推定時間値単位切替 GUESSES_PER_SEC 1e6 → 1e9 組み合わせ数は同じまま、表示される時間の単位がより小さく読める

9つの項目のどこにもaria-live領域やrole属性は追加されておらず、唯一のARIAは07の4つと08の1つの装飾的なチェックマークアイコンに付いたaria-hidden="true"で、これらをスクリーンリーダーの読み上げから完全に外しています。各項目のprefers-reduced-motion: reduceブロックは、そのパスワード強度メーターの塗り・チップ・バッジ自身が持つCSSのtransitionだけを止めるもので、実際のキー入力が起きた瞬間に何が起きるかには触れません — paint()はそのまま動き続け、inputのたびに値を即座に更新します。

FAQ

パスワード強度チェッカーはサーバーが必要ですか?

必要ありません — 上で見た文字数境界からビット値まで、すべての計算は入力欄に今入っている値だけを使ってブラウザの中だけで行われ、どこにも送信されません。

エントロピービット値の方式と推定時間値の方式は同じ計算を共有していますか?

すでに共有しています — 06の組み合わせ数は、03がビット値に変換しているのと同じ「文字集合の大きさを文字数でべき乗した値」で、それを仮定した推測回数で割って時間の単位に変換しているだけです。

この9つはパスワード強度テストの過程で入力した値をどこかに保存したり送信したりしますか?

しません — どの入力欄もタブが開いている間だけメモリ上にとどまり、ストレージへの書き込みもネットワークへの送信も一切なく、各文字を隠すCSSのマスキングも実際に保持されている値自体には触れません。

出典: MDN — input event · MDN — RegExp · MDN — transition · MDN — prefers-reduced-motion · MDN — aria-live · MDN — color-mix

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

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