パスワード強度メーター

文字数・大小文字・数字・記号の条件を判定し、4段階のバーと色で強度を可視化。表示切替や条件チェックリスト付きで会員登録に最適です。

#javascript#form#security

ライブデモ

使用例(お題: SaaS FlowDesk)

この技法を「SaaS FlowDesk」というテーマのダミーサイトで実際に使った例です。

HTML
<div class="fd-screen">
  <div class="fd-card">
    <div class="fd-brand"><span class="fd-mark">◇</span> FlowDesk</div>
    <h2 class="fd-title">アカウントを作成</h2>
    <p class="fd-sub">14日間の無料トライアルをはじめましょう</p>

    <label class="fd-flabel" for="fd-email">仕事用メールアドレス</label>
    <input id="fd-email" class="fd-input" type="email" placeholder="you@company.com" autocomplete="off">

    <label class="fd-flabel" for="pw-input">パスワード</label>
    <div class="pw-wrap">
      <input id="pw-input" class="fd-input" type="password" placeholder="8文字以上" autocomplete="off">
      <button id="pw-toggle" class="pw-toggle" type="button">表示</button>
    </div>

    <!-- 強度メーター(技法の主役) -->
    <div class="pw-meter">
      <div class="pw-bar"></div><div class="pw-bar"></div>
      <div class="pw-bar"></div><div class="pw-bar"></div>
    </div>
    <p id="pw-level" class="pw-level">パスワードを入力してください</p>

    <ul class="pw-checks">
      <li data-check="len">8文字以上</li>
      <li data-check="case">大文字と小文字</li>
      <li data-check="num">数字を含む</li>
      <li data-check="sym">記号を含む</li>
    </ul>

    <button class="fd-cta" type="button">無料ではじめる</button>
  </div>
</div>
CSS
* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
  background:
    radial-gradient(80% 60% at 85% 0%, rgba(79, 124, 255, 0.35), transparent 60%),
    #0f1b34;
  color: #e8edf7;
}

.fd-card {
  width: min(360px, 92vw);
  padding: 26px 28px 24px;
  background: #16244a;
  border: 1px solid rgba(120, 150, 220, 0.22);
  border-radius: 16px;
  box-shadow: 0 26px 60px -24px rgba(0, 0, 0, 0.8);
}
.fd-brand {
  display: flex; align-items: center; gap: 7px;
  font-size: 0.82rem; font-weight: 700; letter-spacing: 0.06em; color: #9fb6f0;
}
.fd-mark { color: #4f7cff; font-size: 1rem; }
.fd-title { margin: 12px 0 4px; font-size: 1.2rem; font-weight: 800; }
.fd-sub { margin: 0 0 18px; font-size: 0.78rem; color: #8ea0c4; }

.fd-flabel { display: block; margin: 0 0 6px; font-size: 0.74rem; font-weight: 600; color: #aebcdc; }
.fd-input {
  width: 100%;
  padding: 11px 13px;
  margin-bottom: 14px;
  font-size: 0.92rem; color: #eef2fb;
  background: #0f1b34;
  border: 1.5px solid rgba(120, 150, 220, 0.3); border-radius: 10px;
  outline: none;
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
.fd-input::placeholder { color: #5f719a; }
.fd-input:focus { border-color: #4f7cff; box-shadow: 0 0 0 3px rgba(79, 124, 255, 0.25); }

.pw-wrap { position: relative; }
.pw-wrap .fd-input { margin-bottom: 10px; padding-right: 56px; }
.pw-toggle {
  position: absolute; right: 8px; top: 9px;
  padding: 5px 9px; font-size: 0.72rem; font-weight: 600;
  color: #9fb6f0; background: rgba(79, 124, 255, 0.14);
  border: none; border-radius: 7px; cursor: pointer;
}

/* 強度バー */
.pw-meter { display: flex; gap: 6px; margin: 4px 0 8px; }
.pw-bar {
  flex: 1; height: 6px; border-radius: 99px;
  background: rgba(120, 150, 220, 0.22);
  transition: background 0.25s ease;
}
.pw-bar.on { background: var(--pw-color, #4f7cff); }
.pw-level {
  margin: 0 0 12px; font-size: 0.78rem; font-weight: 700;
  color: var(--pw-color, #8ea0c4);
}

/* 条件チェックリスト */
.pw-checks {
  list-style: none; margin: 0 0 16px; padding: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 5px 12px;
}
.pw-checks li {
  position: relative; padding-left: 20px;
  font-size: 0.74rem; color: #7e8fb6;
  transition: color 0.18s ease;
}
.pw-checks li::before {
  content: "○"; position: absolute; left: 0; top: 0;
  font-size: 0.72rem; color: #5f719a;
}
.pw-checks li.ok { color: #6ee7b7; }
.pw-checks li.ok::before { content: "✓"; color: #34d399; }

.fd-cta {
  width: 100%; padding: 12px;
  font-size: 0.92rem; font-weight: 700; letter-spacing: 0.03em;
  color: #fff;
  background: linear-gradient(135deg, #4f7cff, #2f5fe0);
  border: none; border-radius: 10px; cursor: pointer;
  box-shadow: 0 12px 24px -10px rgba(79, 124, 255, 0.8);
  transition: transform 0.15s ease;
}
.fd-cta:hover { transform: translateY(-2px); }

@media (prefers-reduced-motion: reduce) {
  .pw-bar, .pw-checks li, .fd-input, .fd-cta { transition: none; }
}
JavaScript
const input = document.getElementById("pw-input");
const toggle = document.getElementById("pw-toggle");
const levelEl = document.getElementById("pw-level");
const bars = [...document.querySelectorAll(".pw-bar")];
const checkItems = [...document.querySelectorAll(".pw-checks li")];
const cta = document.querySelector(".fd-cta");

// 強度レベルごとの色とラベル(0〜4)
const LEVELS = [
  { label: "パスワードを入力してください", color: "#8ea0c4" },
  { label: "弱い", color: "#f87171" },
  { label: "普通", color: "#fbbf24" },
  { label: "強い", color: "#34d399" },
  { label: "とても強い", color: "#22d3ee" },
];

// 各条件を判定
function evaluate(v) {
  return {
    len: v.length >= 8,
    case: /[a-z]/.test(v) && /[A-Z]/.test(v),
    num: /\d/.test(v),
    sym: /[^A-Za-z0-9]/.test(v),
  };
}

function update() {
  if (!input) return;
  const v = input.value;
  const checks = evaluate(v);

  // チェックリスト反映
  checkItems.forEach((li) => {
    const key = li.dataset.check;
    li.classList.toggle("ok", !!checks[key]);
  });

  // スコア=満たした条件数。空なら0
  const score = v.length === 0 ? 0 : Object.values(checks).filter(Boolean).length;
  const level = LEVELS[score];

  bars.forEach((bar, i) => {
    bar.classList.toggle("on", i < score);
    bar.style.setProperty("--pw-color", level.color);
  });

  levelEl.textContent = level.label;
  levelEl.style.setProperty("--pw-color", level.color);
}

if (input) input.addEventListener("input", update);

// 表示/非表示トグル
if (toggle && input) {
  toggle.addEventListener("click", () => {
    const show = input.type === "password";
    input.type = show ? "text" : "password";
    toggle.textContent = show ? "隠す" : "表示";
  });
}

// CTAは実送信せず完了表示(デモ)
if (cta) {
  cta.addEventListener("click", () => {
    const keep = cta.textContent;
    cta.textContent = "アカウントを作成しました ✓";
    setTimeout(() => (cta.textContent = keep), 1600);
  });
}

update();

コード

HTML
<div class="stage">
  <div class="pw-card">
    <h2 class="pw-title">パスワードを設定</h2>

    <div class="pw-field">
      <input id="pw-input" class="pw-input" type="password" placeholder="パスワードを入力" autocomplete="new-password">
      <button id="pw-toggle" class="pw-eye" type="button" aria-label="表示切替">表示</button>
    </div>

    <!-- 強度バー(4セグメント) -->
    <div class="pw-bars" aria-hidden="true">
      <span class="pw-bar"></span><span class="pw-bar"></span>
      <span class="pw-bar"></span><span class="pw-bar"></span>
    </div>
    <p class="pw-level" id="pw-level">パスワードを入力してください</p>

    <!-- 条件チェックリスト -->
    <ul class="pw-checks">
      <li data-check="len"><i></i>8文字以上</li>
      <li data-check="case"><i></i>大文字と小文字</li>
      <li data-check="num"><i></i>数字を含む</li>
      <li data-check="sym"><i></i>記号を含む</li>
    </ul>
  </div>
</div>
CSS
* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
  background: linear-gradient(160deg, #0f172a, #1e1b4b 60%, #312e81);
  color: #e5e7eb;
}

.stage { width: 100%; padding: 22px; display: grid; place-items: center; }

.pw-card {
  width: min(360px, 92vw);
  padding: 26px 24px;
  background: rgba(23, 27, 46, 0.92);
  border: 1px solid #2e3556;
  border-radius: 16px;
  box-shadow: 0 24px 56px -24px rgba(0, 0, 0, 0.7);
}

.pw-title { margin: 0 0 16px; font-size: 1.1rem; letter-spacing: 0.04em; }

.pw-field { position: relative; }
.pw-input {
  width: 100%;
  padding: 12px 64px 12px 14px;
  font-size: 1rem;
  color: #f1f5f9;
  background: #11152a;
  border: 1.5px solid #3a4368;
  border-radius: 10px;
  outline: none;
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
.pw-input:focus { border-color: #818cf8; box-shadow: 0 0 0 3px rgba(129, 140, 248, 0.22); }

.pw-eye {
  position: absolute;
  right: 8px; top: 50%;
  transform: translateY(-50%);
  padding: 5px 9px;
  font-size: 0.74rem;
  color: #c7d2fe;
  background: #2a3157;
  border: none;
  border-radius: 7px;
  cursor: pointer;
}
.pw-eye:hover { background: #353e6e; }

/* 強度バー */
.pw-bars { display: flex; gap: 6px; margin: 16px 0 8px; }
.pw-bar {
  flex: 1;
  height: 6px;
  border-radius: 4px;
  background: #2c3454;
  transition: background 0.3s ease;
}
/* スコアに応じた点灯色は変数で受け取る */
.pw-bar.on { background: var(--pw-color, #818cf8); }

.pw-level { margin: 0 0 14px; font-size: 0.82rem; color: var(--pw-color, #94a3b8); transition: color 0.3s ease; font-weight: 600; }

/* チェックリスト */
.pw-checks { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.pw-checks li {
  display: flex; align-items: center; gap: 9px;
  font-size: 0.8rem; color: #8b95b2;
  transition: color 0.2s ease;
}
.pw-checks i {
  width: 16px; height: 16px; flex: none;
  border-radius: 50%;
  border: 1.5px solid #4b5578;
  position: relative;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.pw-checks li.ok { color: #d1fae5; }
.pw-checks li.ok i { background: #34d399; border-color: #34d399; }
/* チェックマーク */
.pw-checks li.ok i::after {
  content: "";
  position: absolute;
  left: 4.5px; top: 1.5px;
  width: 4px; height: 8px;
  border: solid #0b3b2a;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

@media (prefers-reduced-motion: reduce) {
  .pw-bar, .pw-level, .pw-checks li, .pw-checks i { transition: none; }
}
JavaScript
const input = document.getElementById("pw-input");
const toggle = document.getElementById("pw-toggle");
const levelEl = document.getElementById("pw-level");
const bars = [...document.querySelectorAll(".pw-bar")];
const checkItems = [...document.querySelectorAll(".pw-checks li")];

// 強度レベルごとの色とラベル(0〜4)
const LEVELS = [
  { label: "パスワードを入力してください", color: "#94a3b8" },
  { label: "弱い", color: "#f87171" },
  { label: "普通", color: "#fbbf24" },
  { label: "強い", color: "#34d399" },
  { label: "とても強い", color: "#22d3ee" },
];

// 各条件を判定
function evaluate(v) {
  return {
    len: v.length >= 8,
    case: /[a-z]/.test(v) && /[A-Z]/.test(v),
    num: /\d/.test(v),
    sym: /[^A-Za-z0-9]/.test(v),
  };
}

function update() {
  if (!input) return;
  const v = input.value;
  const checks = evaluate(v);

  // チェックリスト反映
  checkItems.forEach((li) => {
    const key = li.dataset.check;
    li.classList.toggle("ok", !!checks[key]);
  });

  // スコア=満たした条件数。空なら0
  const score = v.length === 0 ? 0 : Object.values(checks).filter(Boolean).length;
  const level = LEVELS[score];

  bars.forEach((bar, i) => {
    const on = i < score;
    bar.classList.toggle("on", on);
    bar.style.setProperty("--pw-color", level.color);
  });

  levelEl.textContent = level.label;
  levelEl.style.setProperty("--pw-color", level.color);
}

if (input) input.addEventListener("input", update);

// 表示/非表示トグル
if (toggle && input) {
  toggle.addEventListener("click", () => {
    const show = input.type === "password";
    input.type = show ? "text" : "password";
    toggle.textContent = show ? "隠す" : "表示";
  });
}

update();

🤖 AIエージェント用プロンプト

このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「パスワード強度メーター」の効果を追加してください。

# 追加してほしい効果
パスワード強度メーター(フォーム & 入力)
文字数・大小文字・数字・記号の条件を判定し、4段階のバーと色で強度を可視化。表示切替や条件チェックリスト付きで会員登録に最適です。

# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<div class="stage">
  <div class="pw-card">
    <h2 class="pw-title">パスワードを設定</h2>

    <div class="pw-field">
      <input id="pw-input" class="pw-input" type="password" placeholder="パスワードを入力" autocomplete="new-password">
      <button id="pw-toggle" class="pw-eye" type="button" aria-label="表示切替">表示</button>
    </div>

    <!-- 強度バー(4セグメント) -->
    <div class="pw-bars" aria-hidden="true">
      <span class="pw-bar"></span><span class="pw-bar"></span>
      <span class="pw-bar"></span><span class="pw-bar"></span>
    </div>
    <p class="pw-level" id="pw-level">パスワードを入力してください</p>

    <!-- 条件チェックリスト -->
    <ul class="pw-checks">
      <li data-check="len"><i></i>8文字以上</li>
      <li data-check="case"><i></i>大文字と小文字</li>
      <li data-check="num"><i></i>数字を含む</li>
      <li data-check="sym"><i></i>記号を含む</li>
    </ul>
  </div>
</div>

【CSS】
* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
  background: linear-gradient(160deg, #0f172a, #1e1b4b 60%, #312e81);
  color: #e5e7eb;
}

.stage { width: 100%; padding: 22px; display: grid; place-items: center; }

.pw-card {
  width: min(360px, 92vw);
  padding: 26px 24px;
  background: rgba(23, 27, 46, 0.92);
  border: 1px solid #2e3556;
  border-radius: 16px;
  box-shadow: 0 24px 56px -24px rgba(0, 0, 0, 0.7);
}

.pw-title { margin: 0 0 16px; font-size: 1.1rem; letter-spacing: 0.04em; }

.pw-field { position: relative; }
.pw-input {
  width: 100%;
  padding: 12px 64px 12px 14px;
  font-size: 1rem;
  color: #f1f5f9;
  background: #11152a;
  border: 1.5px solid #3a4368;
  border-radius: 10px;
  outline: none;
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
.pw-input:focus { border-color: #818cf8; box-shadow: 0 0 0 3px rgba(129, 140, 248, 0.22); }

.pw-eye {
  position: absolute;
  right: 8px; top: 50%;
  transform: translateY(-50%);
  padding: 5px 9px;
  font-size: 0.74rem;
  color: #c7d2fe;
  background: #2a3157;
  border: none;
  border-radius: 7px;
  cursor: pointer;
}
.pw-eye:hover { background: #353e6e; }

/* 強度バー */
.pw-bars { display: flex; gap: 6px; margin: 16px 0 8px; }
.pw-bar {
  flex: 1;
  height: 6px;
  border-radius: 4px;
  background: #2c3454;
  transition: background 0.3s ease;
}
/* スコアに応じた点灯色は変数で受け取る */
.pw-bar.on { background: var(--pw-color, #818cf8); }

.pw-level { margin: 0 0 14px; font-size: 0.82rem; color: var(--pw-color, #94a3b8); transition: color 0.3s ease; font-weight: 600; }

/* チェックリスト */
.pw-checks { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.pw-checks li {
  display: flex; align-items: center; gap: 9px;
  font-size: 0.8rem; color: #8b95b2;
  transition: color 0.2s ease;
}
.pw-checks i {
  width: 16px; height: 16px; flex: none;
  border-radius: 50%;
  border: 1.5px solid #4b5578;
  position: relative;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.pw-checks li.ok { color: #d1fae5; }
.pw-checks li.ok i { background: #34d399; border-color: #34d399; }
/* チェックマーク */
.pw-checks li.ok i::after {
  content: "";
  position: absolute;
  left: 4.5px; top: 1.5px;
  width: 4px; height: 8px;
  border: solid #0b3b2a;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

@media (prefers-reduced-motion: reduce) {
  .pw-bar, .pw-level, .pw-checks li, .pw-checks i { transition: none; }
}

【JavaScript】
const input = document.getElementById("pw-input");
const toggle = document.getElementById("pw-toggle");
const levelEl = document.getElementById("pw-level");
const bars = [...document.querySelectorAll(".pw-bar")];
const checkItems = [...document.querySelectorAll(".pw-checks li")];

// 強度レベルごとの色とラベル(0〜4)
const LEVELS = [
  { label: "パスワードを入力してください", color: "#94a3b8" },
  { label: "弱い", color: "#f87171" },
  { label: "普通", color: "#fbbf24" },
  { label: "強い", color: "#34d399" },
  { label: "とても強い", color: "#22d3ee" },
];

// 各条件を判定
function evaluate(v) {
  return {
    len: v.length >= 8,
    case: /[a-z]/.test(v) && /[A-Z]/.test(v),
    num: /\d/.test(v),
    sym: /[^A-Za-z0-9]/.test(v),
  };
}

function update() {
  if (!input) return;
  const v = input.value;
  const checks = evaluate(v);

  // チェックリスト反映
  checkItems.forEach((li) => {
    const key = li.dataset.check;
    li.classList.toggle("ok", !!checks[key]);
  });

  // スコア=満たした条件数。空なら0
  const score = v.length === 0 ? 0 : Object.values(checks).filter(Boolean).length;
  const level = LEVELS[score];

  bars.forEach((bar, i) => {
    const on = i < score;
    bar.classList.toggle("on", on);
    bar.style.setProperty("--pw-color", level.color);
  });

  levelEl.textContent = level.label;
  levelEl.style.setProperty("--pw-color", level.color);
}

if (input) input.addEventListener("input", update);

// 表示/非表示トグル
if (toggle && input) {
  toggle.addEventListener("click", () => {
    const show = input.type === "password";
    input.type = show ? "text" : "password";
    toggle.textContent = show ? "隠す" : "表示";
  });
}

update();

# 外部ライブラリ
なし(追加ライブラリ不要)

# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。