required 属性仅对语义化表单控件生效:input(text、email等可输入类型)、textarea、select(需空option)、checkbox(单个必选);hidden、button、自定义组件等无效,且依赖form包裹、原生submit触发,移动端和空格场景需额外处理。

required 属性是处理 HTML 表单必填选项最直接的方式,但它不是“加了就一定生效”的开关——它有明确的触发条件、支持范围和行为边界。用错地方或忽略前提,表单照样静默提交。
哪些元素能用 required,哪些不能?
它只对语义化表单控件有效,且行为因类型而异:
-
<input>:仅对type="text"、type="email"、type="password"、type="number"、type="date"、type="file"等“可输入值”的类型起作用;type="hidden"、type="button"、type="submit"加了也无效 -
<textarea>:完全支持,空字符串""触发校验失败 -
<select>:必须配合一个空值<option value=""></option>,且该选项不能带selected或disabled,否则用户未操作时就卡在校验失败状态 -
<input type="checkbox">:表示“该复选框必须勾选”,不是“这一组至少一个”;如需组内必选,得用type="radio"+ 同名name+ 其中一个加required - 自定义组件(如
div[contenteditable]、Web Component 封装的输入框):原生required不识别,必须手动透传或用 JS 校验
为什么加了 required 却没拦住提交?
常见失效场景不是属性写错了,而是破坏了浏览器校验链:
- 表单没被
<form>包裹——required依赖 form 上下文,单独写 input 没用 - 提交按钮是
<button type="button">或用了onclick="submitForm()",没走原生 submit 流程;必须用<button type="submit">或回车触发 - JS 中调用了
e.preventDefault()但没补form.checkValidity(),等于主动关掉了校验 - 移动端 WebView(如旧版微信内置浏览器)直接忽略
required,checkValidity()返回true却不校验,需降级检测value === "" -
<select>的默认项写成<option value="" selected>请选择</option>,用户根本没动,浏览器认为“已选空值”,立刻报错
如何让 required 提示更友好?
原生提示不可定制文案,但可通过组合手段控制反馈时机和视觉表现:
- 避免页面一加载所有必填框就标红:用
input:invalid:not(:placeholder-shown)替代单纯:invalid,确保用户至少输入过再标错 - 失焦即提示(而非等提交):监听
blur事件,调用input.reportValidity(),它会触发气泡并返回布尔值 - 替换默认提示文案:在
invalid事件里调input.setCustomValidity("请输入手机号"),但成功时务必清空——input.setCustomValidity(""),否则错误状态残留 - 空格问题:
" "(单个空格)被视作有效输入,required不拦;如需严格校验,得配合pattern="\S+"或 JS 去空格后判空
服务端校验为什么不能省?
required 是纯前端体验优化,删掉属性、禁用 JS、用 curl 直接 POST,数据照进后端。所以:
立即学习“前端免费学习笔记(深入)”;
- 后端必须重新检查字段是否存在、是否为
null、是否为空字符串""、是否仅为空白符"s+" - 前后端对“空”的定义要一致:比如手机号字段,
"000"、"12345678901"(长度对但非法)、" "都应视为缺失,不能只判== null - 关键业务逻辑(如“邮箱或手机号至少填一个”)无法用
required实现,必须靠 JS + 后端双重判断
required 的真正复杂点不在写法,而在它的“被动性”——它只响应 submit、只认空字符串、只作用于特定元素、完全不感知业务语义。一旦你试图用它解决条件校验、实时反馈或跨端兼容问题,就得立刻切到 JS 层补位。



















