因ie及部分旧版safari将input的type属性设为只读,直接赋值input.type="text"不生效且无报错;推荐用两个input元素(type="password"和type="text")切换显隐,同步value、焦点、光标及aria属性,确保兼容性与可访问性。

为什么 type="password" 不能直接用 JavaScript 改成 type="text"?
因为 IE 和部分旧版浏览器(如 Safari 15.6 之前)会拒绝修改 input 元素的 type 属性,执行后不报错但也不生效,密码依然隐藏。这不是 bug,是规范限制——type 在某些浏览器中是只读的。
所以不能写 input.type = "text" 然后指望它跨浏览器工作。
推荐方案:用两个 input 元素切换显示
创建一个 type="password" 和一个 type="text" 的 input,初始只显示 password 版本,通过 CSS 控制 visibility 或 display 切换,同时保持 value 同步。
- 两个
input必须有相同name、id(或仅保留一个真实id)、autocomplete、required等属性,否则表单提交或无障碍访问会出问题 - 用
aria-hidden="true"隐藏备用 input,避免屏幕阅读器重复读取 - 监听
input事件同步值,不要只靠change,否则实时反馈会延迟 - 示例结构:
<div class="password-field"> <input type="password" id="pwd" name="password" autocomplete="current-password"><input type="text" id="pwd-text" aria-hidden="true" tabindex="-1"><button type="button" aria-label="显示密码">?️</button> </div>
JavaScript 切换逻辑要处理哪些细节?
核心是控制显示状态、焦点、光标位置和辅助功能语义。漏掉任意一项都可能影响体验。
- 切换时必须手动调用
focus()到当前可见的 input,否则键盘操作会中断 - 用
setSelectionRange()恢复光标位置,否则光标总跳到开头(尤其在中间编辑时) - 按钮的
aria-pressed要同步更新,让屏幕阅读器知道当前是“已显示”还是“已隐藏” - 不要用
display: none隐藏备用 input,会导致 Safari 中自动填充失效;改用visibility: hidden; position: absolute; left: -9999px; - value 同步建议用
input+compositionend双事件监听,避免中文输入法中途失焦导致同步遗漏
更轻量的替代方案:CSS appearance + ::-webkit-textfield-decoration?
目前没有稳定跨浏览器的纯 CSS 方案。Chrome 支持 appearance: textfield 强制还原样式,但无法控制密码圆点渲染;Firefox 完全不支持覆盖密码字段视觉表现。所谓“CSS 隐藏圆点”的 hack(比如用 background 覆盖)会破坏文字对齐、缩放适配和高对比度模式。
所以,双 input 切换仍是现阶段最可控、可访问、可维护的做法。复杂点在于 DOM 结构略多,但换来的是确定性——只要同步逻辑写对,iOS、Android WebView、JAWS、NVDA 全部能正常工作。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











