Skip to content

password 密码输入

type="password" 创建一个密码输入框,用户输入的每个字符都会被替换为掩码字符(通常是圆点或星号),防止密码被旁观者看到。本节将详细讲解密码输入框的使用、密码可见性切换的实现方式,以及密码输入的安全注意事项。

前置知识

阅读本节前,建议先了解:text 文本输入

基础概念

什么是 password 输入

type="password"type="text" 的行为几乎完全相同,唯一的区别是:输入的字符会被掩码隐藏显示。它支持与 text 相同的大部分属性,如 maxlengthminlengthpatternplaceholderrequired 等。

html
<!-- text:输入内容明文显示 -->
<input type="text" name="username" placeholder="用户名">

<!-- password:输入内容以掩码显示 -->
<input type="password" name="password" placeholder="密码">

password 的核心特征

特征说明
显示方式字符显示为掩码(圆点/星号)
数据类型纯文本字符串(明文传输)
自动验证无自动格式验证
剪贴板可以复制粘贴(粘贴内容也被掩码)
浏览器自动填充密码管理器可能自动填充

语法

基本语法

html
<input
  type="password"
  name="password"
  id="password"
  placeholder="请输入密码"
  required
  minlength="8"
  maxlength="64"
  autocomplete="current-password"
  pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}"
  title="至少8位,包含大小写字母和数字"
>

password 专用属性

type="password" 支持的属性与 type="text" 基本一致。以下是密码场景中常用的属性组合:

属性建议值说明
autocompletecurrent-password当前密码(登录场景)
autocompletenew-password新密码(注册/修改密码场景)
minlength8 或更大最小密码长度
maxlength64128最大密码长度
pattern正则表达式密码复杂度要求
required-密码为必填项
placeholder提示文字如"请输入密码"

详细说明

基本使用

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>密码输入基本使用</title>
  <style>
    .form-group {
      margin-bottom: 16px;
    }

    label {
      display: block;
      font-weight: 500;
      margin-bottom: 6px;
    }

    input {
      width: 300px;
      padding: 10px 12px;
      border: 1px solid #ccc;
      border-radius: 6px;
      font-size: 14px;
      box-sizing: border-box;
    }

    input:focus {
      outline: none;
      border-color: #4a90d9;
      box-shadow: 0 0 0 3px rgba(74, 144, 217, 0.1);
    }
  </style>
</head>
<body>
  <h2>用户登录</h2>
  <form action="/api/login" method="post">
    <div class="form-group">
      <label for="username">用户名</label>
      <input type="text" id="username" name="username"
             placeholder="请输入用户名" required>
    </div>

    <div class="form-group">
      <label for="password">密码</label>
      <input type="password" id="password" name="password"
             placeholder="请输入密码" required
             autocomplete="current-password">
    </div>

    <button type="submit">登录</button>
  </form>
</body>
</html>

密码可见性切换

浏览器不会自动提供密码显示/隐藏按钮(Firefox 除外,有内置按钮)。通常需要通过 JavaScript 实现这个功能。

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>密码可见性切换</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      max-width: 400px;
      margin: 40px auto;
      padding: 20px;
    }

    .form-group {
      margin-bottom: 20px;
    }

    label {
      display: block;
      font-weight: 500;
      margin-bottom: 6px;
    }

    .password-wrapper {
      position: relative;
      width: 100%;
    }

    .password-wrapper input {
      width: 100%;
      padding: 10px 40px 10px 12px;
      border: 1px solid #ccc;
      border-radius: 6px;
      font-size: 14px;
      box-sizing: border-box;
    }

    .toggle-btn {
      position: absolute;
      right: 8px;
      top: 50%;
      transform: translateY(-50%);
      background: none;
      border: none;
      cursor: pointer;
      font-size: 14px;
      color: #666;
      padding: 4px 8px;
    }

    .toggle-btn:hover {
      color: #333;
    }
  </style>
</head>
<body>
  <h2>设置密码</h2>
  <form action="/api/register" method="post">
    <div class="form-group">
      <label for="password">密码</label>
      <div class="password-wrapper">
        <input type="password"
               id="password"
               name="password"
               placeholder="请输入密码"
               required
               minlength="8"
               autocomplete="new-password">
        <!-- 切换按钮 -->
        <button type="button" class="toggle-btn" onclick="togglePassword('password', this)">
          显示
        </button>
      </div>
    </div>

    <div class="form-group">
      <label for="confirmPassword">确认密码</label>
      <div class="password-wrapper">
        <input type="password"
               id="confirmPassword"
               name="confirm_password"
               placeholder="再次输入密码"
               required
               minlength="8"
               autocomplete="new-password">
        <button type="button" class="toggle-btn" onclick="togglePassword('confirmPassword', this)">
          显示
        </button>
      </div>
    </div>

    <button type="submit">注册</button>
  </form>

  <script>
    /**
     * 切换密码可见性
     * @param {string} inputId - 输入框的 id
     * @param {HTMLButtonElement} btn - 切换按钮元素
     */
    function togglePassword(inputId, btn) {
      const input = document.getElementById(inputId);

      if (input.type === 'password') {
        // 切换为明文显示
        input.type = 'text';
        btn.textContent = '隐藏';
      } else {
        // 切换为密码显示
        input.type = 'password';
        btn.textContent = '显示';
      }
    }
  </script>
</body>
</html>

使用 show-password 按钮图标

更现代的做法是使用图标来表示显示/隐藏状态:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>图标密码切换</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      max-width: 400px;
      margin: 40px auto;
      padding: 20px;
    }

    .password-field {
      position: relative;
      margin-bottom: 20px;
    }

    .password-field label {
      display: block;
      font-weight: 500;
      margin-bottom: 6px;
    }

    .password-field input {
      width: 100%;
      padding: 10px 44px 10px 12px;
      border: 1px solid #ccc;
      border-radius: 6px;
      font-size: 14px;
      box-sizing: border-box;
    }

    .eye-btn {
      position: absolute;
      right: 6px;
      top: 32px;
      background: none;
      border: none;
      cursor: pointer;
      padding: 6px;
      color: #666;
      font-size: 18px;
      line-height: 1;
    }

    .eye-btn:hover {
      color: #333;
    }

    /* 隐藏图标和显示图标 */
    .icon-eye { display: inline; }
    .icon-eye-slash { display: none; }

    .visible .icon-eye { display: none; }
    .visible .icon-eye-slash { display: inline; }
  </style>
</head>
<body>
  <form action="/api/login" method="post">
    <div class="password-field">
      <label for="pwd">密码</label>
      <input type="password" id="pwd" name="pwd"
             placeholder="请输入密码" autocomplete="current-password">
      <button type="button" class="eye-btn" id="toggleBtn"
              aria-label="切换密码可见性">
        <!-- 使用 SVG 图标 -->
        <svg class="icon-eye" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
          <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
          <circle cx="12" cy="12" r="3"/>
        </svg>
        <svg class="icon-eye-slash" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
          <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/>
          <line x1="1" y1="1" x2="23" y2="23"/>
        </svg>
      </button>
    </div>

    <button type="submit">登录</button>
  </form>

  <script>
    const toggleBtn = document.getElementById('toggleBtn');
    const pwdInput = document.getElementById('pwd');

    toggleBtn.addEventListener('click', function() {
      const isPassword = pwdInput.type === 'password';
      pwdInput.type = isPassword ? 'text' : 'password';

      // 切换图标的可见性
      this.classList.toggle('visible', isPassword);

      // 更新无障碍标签
      this.setAttribute('aria-label',
        isPassword ? '隐藏密码' : '显示密码'
      );
    });
  </script>
</body>
</html>

密码强度检测

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>密码强度检测</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      max-width: 400px;
      margin: 40px auto;
      padding: 20px;
    }

    .password-group {
      margin-bottom: 16px;
    }

    .password-group label {
      display: block;
      font-weight: 500;
      margin-bottom: 6px;
    }

    .password-group input {
      width: 100%;
      padding: 10px 12px;
      border: 1px solid #ccc;
      border-radius: 6px;
      box-sizing: border-box;
    }

    /* 密码强度条 */
    .strength-bar {
      display: flex;
      gap: 4px;
      margin-top: 8px;
    }

    .strength-bar .bar {
      flex: 1;
      height: 4px;
      background-color: #e0e0e0;
      border-radius: 2px;
      transition: background-color 0.3s;
    }

    .strength-text {
      font-size: 12px;
      margin-top: 4px;
      color: #666;
    }

    /* 密码规则清单 */
    .rules {
      list-style: none;
      padding: 0;
      margin-top: 8px;
      font-size: 13px;
    }

    .rules li {
      padding: 2px 0;
      color: #999;
    }

    .rules li.pass {
      color: #27ae60;
    }

    .rules li.pass::before {
      content: '✓ ';
    }

    .rules li.fail::before {
      content: '○ ';
    }
  </style>
</head>
<body>
  <form action="/api/set-password" method="post">
    <div class="password-group">
      <label for="newPwd">设置密码</label>
      <input type="password" id="newPwd" name="password"
             placeholder="至少8位" required minlength="8"
             autocomplete="new-password">

      <!-- 密码强度条 -->
      <div class="strength-bar">
        <div class="bar" id="bar1"></div>
        <div class="bar" id="bar2"></div>
        <div class="bar" id="bar3"></div>
        <div class="bar" id="bar4"></div>
      </div>
      <div class="strength-text" id="strengthText"></div>

      <!-- 密码规则 -->
      <ul class="rules" id="rules">
        <li id="rule-length" class="fail">至少8个字符</li>
        <li id="rule-upper" class="fail">包含大写字母</li>
        <li id="rule-lower" class="fail">包含小写字母</li>
        <li id="rule-number" class="fail">包含数字</li>
        <li id="rule-special" class="fail">包含特殊字符</li>
      </ul>
    </div>
  </form>

  <script>
    const pwdInput = document.getElementById('newPwd');
    const bars = [
      document.getElementById('bar1'),
      document.getElementById('bar2'),
      document.getElementById('bar3'),
      document.getElementById('bar4')
    ];
    const strengthText = document.getElementById('strengthText');

    const rules = {
      length: document.getElementById('rule-length'),
      upper: document.getElementById('rule-upper'),
      lower: document.getElementById('rule-lower'),
      number: document.getElementById('rule-number'),
      special: document.getElementById('rule-special')
    };

    const strengthColors = ['#e74c3c', '#f39c12', '#f1c40f', '#27ae60'];
    const strengthLabels = ['弱', '一般', '较强', '强'];

    pwdInput.addEventListener('input', function() {
      const pwd = this.value;

      // 检查各项规则
      const checks = {
        length: pwd.length >= 8,
        upper: /[A-Z]/.test(pwd),
        lower: /[a-z]/.test(pwd),
        number: /[0-9]/.test(pwd),
        special: /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(pwd)
      };

      // 更新规则列表样式
      for (const [key, el] of Object.entries(rules)) {
        el.className = checks[key] ? 'pass' : 'fail';
      }

      // 计算满足的规则数
      const passedCount = Object.values(checks).filter(Boolean).length;

      // 更新强度条
      bars.forEach((bar, i) => {
        if (i < passedCount) {
          bar.style.backgroundColor = strengthColors[Math.min(passedCount - 1, 3)];
        } else {
          bar.style.backgroundColor = '#e0e0e0';
        }
      });

      // 更新强度文字
      if (pwd.length === 0) {
        strengthText.textContent = '';
      } else if (passedCount <= 1) {
        strengthText.textContent = '密码强度:弱';
        strengthText.style.color = '#e74c3c';
      } else if (passedCount === 2) {
        strengthText.textContent = '密码强度:一般';
        strengthText.style.color = '#f39c12';
      } else if (passedCount === 3) {
        strengthText.textContent = '密码强度:较强';
        strengthText.style.color = '#f1c40f';
      } else {
        strengthText.textContent = '密码强度:强';
        strengthText.style.color = '#27ae60';
      }
    });
  </script>
</body>
</html>

安全注意事项

安全警告

密码输入框只是在视觉上隐藏了输入内容,它并没有对数据进行加密。以下安全要点必须了解:

1. 密码以明文传输(除非使用 HTTPS)

html
<!--
  如果页面使用 HTTP(非 HTTPS),
  密码以明文形式在网络上传输!
  攻击者可以截获网络请求获取密码。

  始终使用 HTTPS 保护包含密码的表单。
-->
<form action="https://example.com/login" method="post">
  <input type="password" name="password">
</form>

2. 密码管理器的自动填充

html
<!--
  浏览器的密码管理器可能自动填充密码。
  对于修改密码页面,使用 new-password 防止填充旧密码。
-->
<input type="password" name="password" autocomplete="new-password">

3. 不要在前端限制密码字符

html
<!--
  不推荐:限制密码只能包含字母和数字
  这降低了密码的安全性
-->
<!-- <input type="password" pattern="[a-zA-Z0-9]+"> -->

<!-- 推荐:允许特殊字符,只限制长度 -->
<input type="password" minlength="8" maxlength="128">

4. 密码不应出现在 URL 中

html
<!--
  错误!GET 请求会把密码放在 URL 中
  URL 会被浏览器历史、服务器日志等记录
-->
<!-- <form action="/login" method="get">
  <input type="password" name="password">
</form> -->

<!-- 正确:使用 POST -->
<form action="/login" method="post">
  <input type="password" name="password">
</form>

实战示例

完整的修改密码表单

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>修改密码</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      max-width: 450px;
      margin: 40px auto;
      padding: 20px;
      background-color: #f5f5f5;
    }

    .card {
      background: white;
      padding: 30px;
      border-radius: 12px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    }

    h2 {
      text-align: center;
      margin-bottom: 24px;
    }

    .form-group {
      margin-bottom: 20px;
    }

    .form-group label {
      display: block;
      font-weight: 500;
      margin-bottom: 6px;
    }

    .input-wrapper {
      position: relative;
    }

    .input-wrapper input {
      width: 100%;
      padding: 10px 40px 10px 12px;
      border: 1px solid #ddd;
      border-radius: 6px;
      box-sizing: border-box;
      font-size: 14px;
    }

    .toggle-btn {
      position: absolute;
      right: 8px;
      top: 50%;
      transform: translateY(-50%);
      background: none;
      border: none;
      cursor: pointer;
      color: #666;
      padding: 4px;
      font-size: 13px;
    }

    .btn-submit {
      width: 100%;
      padding: 12px;
      background-color: #4a90d9;
      color: white;
      border: none;
      border-radius: 6px;
      font-size: 16px;
      cursor: pointer;
      margin-top: 8px;
    }

    .btn-submit:hover {
      background-color: #3a7bc8;
    }
  </style>
</head>
<body>
  <div class="card">
    <h2>修改密码</h2>
    <form id="changePwdForm" action="/api/change-password" method="post">
      <div class="form-group">
        <label for="oldPwd">当前密码</label>
        <div class="input-wrapper">
          <input type="password"
                 id="oldPwd"
                 name="old_password"
                 placeholder="请输入当前密码"
                 required
                 autocomplete="current-password">
          <button type="button" class="toggle-btn"
                  onclick="togglePwd('oldPwd', this)">显示</button>
        </div>
      </div>

      <div class="form-group">
        <label for="newPwd">新密码</label>
        <div class="input-wrapper">
          <input type="password"
                 id="newPwd"
                 name="new_password"
                 placeholder="至少8位,包含字母和数字"
                 required
                 minlength="8"
                 autocomplete="new-password">
          <button type="button" class="toggle-btn"
                  onclick="togglePwd('newPwd', this)">显示</button>
        </div>
      </div>

      <div class="form-group">
        <label for="confirmPwd">确认新密码</label>
        <div class="input-wrapper">
          <input type="password"
                 id="confirmPwd"
                 name="confirm_password"
                 placeholder="再次输入新密码"
                 required
                 minlength="8"
                 autocomplete="new-password">
          <button type="button" class="toggle-btn"
                  onclick="togglePwd('confirmPwd', this)">显示</button>
        </div>
      </div>

      <button type="submit" class="btn-submit">修改密码</button>
    </form>
  </div>

  <script>
    function togglePwd(id, btn) {
      const input = document.getElementById(id);
      input.type = input.type === 'password' ? 'text' : 'password';
      btn.textContent = input.type === 'password' ? '显示' : '隐藏';
    }

    const form = document.getElementById('changePwdForm');
    form.addEventListener('submit', function(e) {
      e.preventDefault();

      const newPwd = document.getElementById('newPwd').value;
      const confirmPwd = document.getElementById('confirmPwd').value;

      // 检查两次密码是否一致
      if (newPwd !== confirmPwd) {
        document.getElementById('confirmPwd')
          .setCustomValidity('两次输入的密码不一致');
        this.reportValidity();
        return;
      }

      // 清除自定义验证
      document.getElementById('confirmPwd').setCustomValidity('');

      // 检查新密码不能与旧密码相同
      const oldPwd = document.getElementById('oldPwd').value;
      if (newPwd === oldPwd) {
        document.getElementById('newPwd')
          .setCustomValidity('新密码不能与当前密码相同');
        this.reportValidity();
        return;
      }

      document.getElementById('newPwd').setCustomValidity('');

      // 提交表单
      this.submit();
    });
  </script>
</body>
</html>

注意事项

  1. password 不等于加密type="password" 只是在界面上隐藏输入内容,数据仍然是明文。安全性依赖于 HTTPS 传输和服务器端加密存储。

  2. autocomplete="off" 对密码可能无效:现代浏览器可能忽略密码字段的 autocomplete="off",仍然提供密码管理器的填充功能。使用 new-password 是更好的控制方式。

  3. 不要用 JavaScript 限制密码字符集:允许用户使用任意字符作为密码(包括空格和特殊字符),这能提高密码强度。

  4. 密码可见性切换的隐私风险:在公共场所使用时,显示密码可能被旁人看到。切换按钮应明确提示用户注意周围环境。

  5. 浏览器自动填充密码:浏览器会在登录页面自动填充已保存的密码。如果不需要此功能,使用 autocomplete="new-password" 或将字段名设为非标准名称(不推荐)。

最佳实践

  1. 使用 autocomplete token:登录页使用 current-password,注册/修改密码页使用 new-password

  2. 提供密码可见性切换:帮助用户确认输入的密码是否正确,减少输入错误。

  3. 提供实时密码强度反馈:引导用户创建更强的密码。

  4. 使用 POST + HTTPS:密码表单必须使用 POST 方法,并通过 HTTPS 传输。

  5. 服务器端验证是最终防线:客户端验证只是辅助,密码的复杂度检查、是否与历史密码重复等必须在服务器端验证。

下一节

继续学习:email 邮箱输入

参考链接