1. 从“框内提示”说起placeholder 到底是什么很多刚接触前端的朋友第一次写登录界面都会遇到这个问题左边一个账号输入框右边一个密码输入框界面倒是做出来了但总觉得少了点什么。打开别人做的页面一看人家的输入框里自带“请输入账号”“请输入密码”这样的灰色文字而且鼠标一点进去文字就自动消失换成自己敲的内容了。这个效果怎么做你可能已经在网上搜过答案十有八九会看到一个词placeholder。说得直白一点placeholder 就是 HTML 里 input 标签自带的一个属性它的作用就是给用户一个提示文字显示在输入框内部。这个提示在不影响输入内容的前提下告诉用户“这里应该填什么”用户体验比单纯在旁边放一个 label 要自然得多。我在带新人的时候经常说placeholder 是你接触的第一个“能感知用户体验”的 HTML 属性。它不涉及复杂的 JavaScript 逻辑也没有 CSS 的难点就是一行代码的事。但越是简单的东西越能看出一个前端对细节的把握。这篇文章我就以“登录界面里‘请输入账号’怎么写进框里”这个问题为切入点把 placeholder 从入门到进阶、从实现到坑位全部拆开讲清楚。如果你是刚学 HTML 的新手可以直接从第 2 节开始跟着步骤把登录界面搭出来。如果你已经会写基础页面了可以重点看第 4 节和第 5 节那里整理了很多实际开发中才会遇到的兼容性问题和小技巧。2. 基础实现用 placeholder 属性写出“框内提示字”2.1 一行代码就能搞定的事情先不讲大道理直接上代码。!DOCTYPE html html langzh-cn head meta charsetUTF-8 title登录界面/title /head body form input typetext placeholder请输入账号 input typepassword placeholder请输入密码 button typesubmit登录/button /form /body /html你把这段代码保存成 .html 文件用浏览器打开就能看到两个输入框里分别显示了“请输入账号”和“请输入密码”这行灰色的文字。点击输入框输入自己的账号时提示文字就消失了。关键就是那个 placeholder 属性英文直译就是“占位符”的意思。它放在 input 标签内部等号后面用引号括起来的文字就是最终显示在输入框里的提示内容。我见过有人把 placeholder 和 value 搞混这里必须强调一下value 是输入框的默认值它会被当作表单数据提交到后端placeholder 只是视觉提示不会参与表单提交。如果你把“请输入账号”写在 value 里用户必须手动删掉这行字才能输入那就闹笑话了。2.2 适配不同类型的输入框账号、密码、手机号placeholder 不仅能用在 typetext 上任何常见的 input 类型都支持它。比如密码框、邮箱框、手机号框甚至 textarea 文本域也都支持。input typetext placeholder请输入用户名/邮箱/手机号 input typepassword placeholder请输入密码6-20位 input typeemail placeholderexampleemail.com textarea placeholder请输入个人简介/textarea这里有一个细节值得注意账号输入框的 placeholder内容最好直接告诉用户“可以输入什么格式”而不是笼统地说“请输入账号”。很多真实项目的登录框一个框要同时兼容用户名、邮箱、手机号三种登录方式所以提示语会写成“请输入用户名/邮箱/手机号”。这相当于在用户还没输入之前就提前告诉他规则减少后面做校验时的报错率。密码框的提示同理。如果项目设定了密码必须是 6 到 20 位、必须包含数字和字母那就直接在 placeholder 里写清楚。实测下来这个做法能显著降低用户提交错误数据的概率后端同事也会感谢你。2.3 用 CSS 修改 placeholder 的样式颜色、字号、位置默认情况下placeholder 文字是灰色的。不同浏览器对它的默认样式处理并不完全一致Chrome 里偏浅灰Firefox 里稍微深一点老版本 IE 则直接不支持样式修改。要想让提示文字看起来更舒服、和整体页面风格统一就得用 CSS 单独控制它。placeholder 不是常规的文本内容它属于“伪元素/伪类”的范畴所以不能用普通的 color、font-size 直接改。需要针对不同浏览器写不同的选择器input::placeholder { color: #999; font-size: 14px; } input::-webkit-input-placeholder { color: #999; font-size: 14px; } input:-moz-placeholder { color: #999; font-size: 14px; } input::-moz-placeholder { color: #999; font-size: 14px; } input:-ms-input-placeholder { color: #999; font-size: 14px; }在标准语法中直接用 ::placeholder 就可以。但 Webkit 内核的浏览器Chrome、Safari在部分版本里需要加 -webkit- 前缀Firefox 需要 -moz- 前缀IE10-11 则要用 :-ms-input-placeholder 这个伪类写法。不过说实话现在已经是现代浏览器的时代了新版 Chrome、Edge、Firefox、Safari 对标准 ::placeholder 的支持都很完善。我建议你在项目里只写标准写法然后针对你在意的浏览器加一两条前缀规则就够了。非要把五条全写上维护起来反而麻烦。另外placeholder 也是可以设置文字对齐方式的。text-align: center 可以让提示文字居中显示这个在手机端登录页很常见。还有 font-style: italic 之类的花样看设计稿需求。3. 进阶玩法placeholder 的兼容性问题和 JavaScript 模拟方案3.1 为什么还有人不支持 placeholder聊聊 IE 的旧账如果你是在校学生或者 2015 年之后才开始接触前端你大概率没受过 IE 的折磨。但如果你维护过老系统或者公司对浏览器兼容性有严格要求就一定知道 placeholder 有一个著名的痛点IE10 以下的版本不支持。IE9 及更早版本完全无视 placeholder 属性输入框里空空如也这在小部分用户那里会直接导致他不知道该填什么。针对这种情况早期前端圈子的标准方案是用 JavaScript 模拟一个“假的 placeholder”。大致思路是给 input 绑定 focus 和 blur 事件在输入框没有内容、且失去焦点时用 JS 判断当前值是否为空如果为空就给 input 的 value 赋值为提示文字同时加上一个特殊 class 让提示文字的颜色保持灰色。当用户聚焦时如果发现当前值是提示文字就清空它。3.2 手写一个兼容 IE 的 placeholder 模拟我给大家写一个简化的版本逻辑上可以这么理解input typetext idusername placeholder请输入账号var input document.getElementById(username); var placeholderText input.getAttribute(placeholder); function setPlaceholder() { if (!input.value) { input.value placeholderText; input.classList.add(placeholder-color); } } function clearPlaceholder() { if (input.value placeholderText) { input.value ; input.classList.remove(placeholder-color); } } if (!(placeholder in document.createElement(input))) { setPlaceholder(); input.addEventListener(focus, clearPlaceholder); input.addEventListener(blur, setPlaceholder); }说实话这个方案放在今天有点过时了。现在还在用 IE9 以下版本的用户已经非常稀少如果你不是做政务系统、银行系统这类必须兼容古董浏览器的项目我不建议你花时间搞这套。真正值得注意的是另一种情况如果你在移动端开发某些老的 WebView 内核或国产浏览器的“省流量模式”下placeholder 偶尔会不显示。遇到这种问题先用特性检测判断浏览器是否支持 placeholder再决定要不要降级方案这才是标准的处理思路。3.3 用 JS 实现“点击输入框时自动清空”的效果还有一个小众需求默认情况下placeholder 是在用户输入第一个字符时消失的。但有同学希望“鼠标一聚焦就清空提示”这个行为差异虽然微妙但在某些对输入过程有特殊要求的页面上确实有需求。这时候手动用 JS 控制比较稳妥。input.addEventListener(focus, function () { if (this.value this.getAttribute(placeholder)) { this.value ; } });需要注意的是这只是单向的“聚焦清空”。如果你还需要“失焦后若为空则还原提示”那就要把第 3.2 节的 blur 逻辑也整合进来。单独写 focus 很容易造成“用户输入了内容失焦后又消失”的假象所以我在项目里通常把这两个事件绑定成一组形成一个完整的循环。3.4 placeholder 文字能不能换行这是一个非常实用、但很多人不知道的冷门知识点。默认情况下placeholder 文字是一行显示超出输入框宽度会被截断。但如果你确实需要两行提示比如做成“请输入账号\n即手机号或邮箱”这种效果原生 HTML 是做不到的因为 placeholder 属性里的文字会被浏览器当作纯文本处理你就算在值里写了换行符也没用。唯一可行的方案是换一种 UI 表现方式。把提示文字从 input 内部挪出来用绝对定位盖在输入框上面或者放到 input 下面作为辅助说明文字。我在实际项目中遇到过类似的设计稿最终都选择在输入框下方加一行小字说明而不是强行让 placeholder 换行。如果非要保留“在框内”的视觉可以用 label 元素定位到 input 上方聚焦时让 label 上移变小这就是现在很流行的“浮动标签”效果。4. 完整实战用 HTMLCSSJS 写一个现代化的登录界面4.1 页面结构与基础样式设计只写一个带 placeholder 的 input那只是一个 demo。为了让登录界面真正好看、能用我们最好把结构、样式、交互整套都搭出来。下面这个例子是简化版但布局思路可以平移到你自己的项目里。!DOCTYPE html html langzh-cn head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title登录页面实战/title style /* 全局重置 */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Microsoft YaHei, PingFang SC, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; } .login-card { width: 400px; background: #fff; border-radius: 8px; padding: 40px 32px 32px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); } .login-title { text-align: center; font-size: 22px; font-weight: 600; color: #333; margin-bottom: 8px; } .login-subtitle { text-align: center; font-size: 13px; color: #999; margin-bottom: 28px; } .form-item { margin-bottom: 20px; } .form-input { width: 100%; height: 44px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 0 12px; font-size: 14px; outline: none; transition: border-color 0.2s; } .form-input:focus { border-color: #409eff; } .form-input::placeholder { color: #c0c4cc; font-size: 14px; } .login-btn { width: 100%; height: 44px; background: #409eff; border: none; border-radius: 4px; color: #fff; font-size: 16px; cursor: pointer; transition: background 0.2s; } .login-btn:hover { background: #66b1ff; } /style /head body div classlogin-card h2 classlogin-title欢迎登录/h2 p classlogin-subtitle请使用账号密码登录/p div classform-item input classform-input typetext placeholder请输入账号/邮箱/手机号 /div div classform-item input classform-input typepassword placeholder请输入密码6-20位 /div button classlogin-btn登 录/button /div /body /html这个页面用到的核心点其实还是 placeholder但组合了布局、配色、焦点状态等前端基础能力。你可以看到我只写了标准语法 ::placeholder足够覆盖现代浏览器。页面整体风格是典型的居中卡片式登录页在管理后台项目中非常常见。4.2 添加“小眼睛”密码显示与隐藏的实现登录界面的舒适度很大程度上取决于细节功能是否齐全。“小眼睛”切换密码明文显示就是其中最典型的一个。这个功能需要配合 JavaScript 操作 input 的 type 属性。思路是默认 typepassword点击眼睛图标时把 type 改成 text密码就变成明文再点一次改回 password就恢复成密文。在切换过程中placeholder 的显示逻辑由浏览器自动处理不受影响。一个简化版的示例代码div classform-item styleposition: relative; input classform-input typepassword idpwdInput placeholder请输入密码6-20位 span idtogglePwd styleposition: absolute; right: 12px; top: 12px; cursor: pointer;/span /divvar pwdInput document.getElementById(pwdInput); var togglePwd document.getElementById(togglePwd); togglePwd.addEventListener(click, function () { if (pwdInput.type password) { pwdInput.type text; } else { pwdInput.type password; } });如果你不想用 emoji 图标也可以用 CSS 画一个或者引入字体图标库原理相同。4.3 空值校验什么时候该弹提示什么时候该用 placeholder有个新手容易犯的错误登录时把 placeholder 的文字当成 value 拿去校验了。上面已经提醒过value 和 placeholder 是两码事但真实场景里还有一个更隐蔽的问题——表单校验的时机。我见过很多页面的写法是点击登录按钮时判断输入框的 value 是否为空如果为空就 alert 一下“请输入账号”或者“请输入密码”。这种做法本身没错但如果输入框还带有 placeholder用户看到的就是输入框里明明有一行提示文字我却弹了个“请输入账号”。这种体验挺分裂的。个人建议把 placeholder 当作“引导提示”来用把校验提示放到按钮点击后的反馈里。就算输入框已经有 placeholder点击登录时仍然要校验 value 是否为空并且最好在输入框下方用红色小字提示而不是用 alert 弹窗。弹窗太打扰人了现代前端已经不太流行这个了。5. 避坑手册placeholder 相关的 7 个常见问题5.1 placeholder 不显示先把这些可能性排除排查 placeholder 不显示的问题我一般按下面的顺序来可能原因检查方式解决办法input 有 value 值查看 HTML 代码删除 value 属性样式覆盖了透明度检查 CSS 中对 input 或 ::placeholder 的设置调整颜色和不透明度浏览器不支持用特性检测判断降级为 JS 模拟方案placeholder 拼写错误查看浏览器开发者工具修正属性名先说 value 的情况。有些框架或自动填充脚本会给 input 注入 value导致 placeholder 显示不出来或者显示一下马上被替换。排查时先看元素面板确认 value 是不是空的。再说透明度。我踩过一个坑全局样式里写了 input { opacity: 0.5; }导致 placeholder 文字也跟着变淡了几乎看不见。虽然这是很简单的原因但排查起来确实耽误时间建议先查样式。5.2 placeholder 文字颜色太浅看不清怎么办不同浏览器的默认 placeholder 颜色不太一样Chrome 默认是 #757575 附近的灰色有些浏览器会偏浅。如果 UI 设计师对颜色有严格要求直接按第 2.3 节的方法覆盖样式即可。如果是移动端页面还有一个常见的对比度问题输入框背景是浅色placeholder 也是浅色看起来就很费劲。用工具检查对比度有点大材小用最直接的判断标准是你自己在手机上亮度调到 50% 以上还能看清一般就没问题。看不清就调深一档。5.3 中文和英文 placeholder 的字间距问题中文提示语和英文提示语在视觉上有明显差异。中文不需要额外处理字体默认就是等宽的英文或者数字开头的内容在部分字体下会出现首字母间距过大的情况。一旦发现 placeholder 排列不整齐可以在 CSS 里给它单独设置 letter-spacing。5.4 移动端 placeholder 与输入法弹起的联动在手机端浏览器中点击输入框时系统会弹出软键盘。这时候 placeholder 的消失时机由浏览器决定我们无法直接控制。但有两个体验细节可以优化给 input 设置 inputmode 或 type 为合适的值比如账号框用 typetext inputmodeemail手机号框用 typetel软键盘就会变成更合适的布局。不要给输入框设置过大的 height 和 padding否则软键盘弹出时页面跳动会很厉害。5.5 表单自动填充会不会影响 placeholder这是一个经常被问到的点浏览器保存过账号密码后再次打开登录页输入框被自动填充了内容placeholder 被遮住。这不是 bug是浏览器的正常行为。处理方式也比较简单给 form 设置 autocompleteoff或者给具体输入框设置 autocompleteoff通常能避免自动填充干扰 placeholder 的显示。不过要说明一点autocompleteoff 在部分浏览器尤其是 Chrome上的执行并不可靠它更倾向放行用户主动选择的自动填充。如果真的不能让浏览器自动填充登录信息那要配合后端设置而不是只在前端写一个属性就完事。5.6 placeholder 能不能支持 HTML 标签不能。placeholder 属性的值在任何浏览器里都只支持纯文本你写b提示/b它也会原样显示成文字。所以别想着在 placeholder 里加链接、加图片这条路走不通。如果产品需求要求在输入框内展示带图标的提示比如一把锁、一个人像这其实是“前缀图标”需求你应该用 CSS 背景图或者伪元素来实现让图标绝对定位在输入框左边而不是试图把图片放进 placeholder 里。5.7 老项目里 placeholder 和 label 该如何分工最后说一个设计思路的问题有了 placeholder还需要 label 吗我多年的经验是两者最好同时存在。placeholder 负责在输入框内提供引导label 负责在输入框外部标明这个字段叫什么。对于只有一个输入框的极简登录页placeholder 确实可以取代 label但在一张复杂的表单页里如果只有 placeholder 而没有 label用户一旦开始输入就会忘记这一栏到底在填什么。从无障碍角度考虑label 还承担着屏幕阅读器朗读字段名的职责。所以做正式项目时我的习惯是写视觉上隐藏的 label用 CSS 把它放到看不见的位置再配合 placeholder 做视觉引导。这样既不破坏页面美观也照顾到了可访问性。6. 锦上添花让 placeholder 动起来浮动标签效果6.1 什么是浮动标签相比普通 placeholder 有什么优势普通 placeholder 的弱点是用户一开始输入提示文字就消失了。如果他输入到一半被打断再回来可能忘了这一栏是要填什么的。浮动标签Floating Label就是为了解决这个问题页面加载时标签文字显示在输入框内聚焦或输入后它平滑“浮”到输入框的左上角变成一个微型标题。这种交互最早出现在移动端 App 的登录和注册页面后来被很多 Web 项目采用了。它的实现基础还是 placeholder 延伸出来的思路只是用 CSS 定位和过渡动画把它做得更精致。6.2 纯 CSS 实现浮动标签的思路用纯 CSS 实现浮动标签核心是利用 :focus 伪类和 :not(:placeholder-shown) 伪类。:placeholder-shown 这个伪类是重点——它表示“当前 placeholder 正在显示的状态”。如果输入框里有内容占位符被顶掉了就不再匹配这个伪类。于是我们就能用它的反向状态来判断输入框里是否有内容。下面这个例子让大家感受一下实现的简洁程度div classfloat-wrap input typetext classfloat-input placeholder请输入账号 label classfloat-label账号/label /div.float-wrap { position: relative; margin: 30px 0; } .float-input { width: 300px; height: 50px; border: 1px solid #ccc; border-radius: 4px; padding: 14px 12px 0; font-size: 16px; outline: none; } .float-label { position: absolute; left: 12px; top: 14px; font-size: 16px; color: #999; pointer-events: none; transition: all 0.2s ease; } .float-input:focus .float-label, .float-input:not(:placeholder-shown) .float-label { top: 4px; font-size: 12px; color: #409eff; }这里的巧妙之处在于input 本身仍然有一个透明的 placeholder或者用空格撑住位置我们用它来驱动 label 的状态切换。:focus 表示聚焦:not(:placeholder-shown) 表示框内有内容两种状态一旦触发label 就缩小上移。6.3 这个方案要注意的两个细节第一个细节是IE 不支持 :placeholder-shown。如果你必须兼容 IE那就只能回到 JavaScript 监听 focus/blur/input 事件的老路。现在大部分后台管理系统已经放弃 IE11 之前的老古董了我个人建议直接用标准方案。第二个细节是label 的定位要和 input 的 padding 配合好。input 的高度如果是 50pxpadding-top 至少要到 14px否则 label 上移后会被 input 的边框遮挡。这个需要反复调建议你在浏览器里直接打开开发者工具边调整边看比对着数值猜要快得多。7. 写在最后的一些经验回头来看placeholder 只是一个看似不起眼的 HTML 属性但它牵扯出的小问题其实不少浏览器兼容性、样式定制、与 label 的分工、表单校验的时机、移动端的软键盘配合……每一个单独拿出来都不难放在一个登录页里就会互相影响。我个人在实际操作中最深的一点体会是做前端不要太依赖 placeholder 来承担过多的职责。它是加分的视觉引导不是唯一的提示手段。一个信息完整的登录表单应该同时具备 label标明字段、placeholder引导填写格式、错误提示校验反馈三者各司其职才不会在复杂的交互环节里“露怯”。另外如果你是我前面提到的刚入门前端的同学我建议你亲手把第 4 节的完整代码抄一遍再照着第 6 节改一版浮动标签的效果。别用复制粘贴一个字一个字敲。这样敲完之后你再看其他网站上的输入框脑子里自然就会浮现出背后的实现逻辑。这个内容后续还可以继续扩展的方向很多比如关联上 Vue 或 React 组件里如何封装登录表单、对接后端接口时如何处理登录态、如何用 Token 保持会话。但这些都是后话了。先把眼前这个“请输入账号写进框里”的小目标稳稳拿下你就算正式迈过了前端页面开发的一道小门槛。
