必须用 form 包裹输入项,因为浏览器原生行为(回车提交、Tab 焦点顺序、屏幕阅读器识别、fieldset[disabled] 批量禁用)均依赖该语义化标签;纯 div 布局会导致键盘用户无法正常导航、WCAG 审查失败,且丧失可访问性基础保障。

直接用 form + 语义化标签 + 基础 CSS 就能跑通绝大多数简单表单,不需要框架、不写 JS 也能保证可访问性和基础交互。
为什么必须用 form 包裹所有输入项
不是“看起来像表单”就行,而是浏览器原生行为依赖这个标签:回车提交、Tab 键顺序聚焦、屏幕阅读器自动识别控件组、禁用整个区域只需 fieldset[disabled]。纯 div 布局会让键盘用户卡在第一个输入框出不去,WCAG 审查直接报错。
-
form可以没有action和method,空标签也有效 - 每个
input必须有对应label,推荐包裹式写法:<label>用户名<input name="username"></label> - 避免
onsubmit="return false"这类内联拦截,JS 中用event.preventDefault()更可控
用 flex 快速对齐 label 和 input
不用 float、不用 grid、不设固定宽度,三行 CSS 解决对齐问题:
form {
display: flex;
flex-direction: column;
gap: 8px;
}
label {
display: flex;
flex-direction: column;
gap: 4px;
}
input, select, textarea {
padding: 6px 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
- 每组
label+ 控件自成一个flex列,天然垂直堆叠 -
gap控制间距,比margin更稳定(不会塌陷) - 移动端默认单列,无需媒体查询;要双列时只加
@media (min-width: 768px) { form { flex-direction: row; flex-wrap: wrap; } }
input[type="number"] 输不了小数点?检查这三个属性
Chrome 和 Safari 默认拒绝小数点和负号,不是 bug,是规范行为——step 和 min 缺一不可。
立即学习“前端免费学习笔记(深入)”;
- 支持小数:必须写
step="0.1"或step="any"(后者 iOS 兼容稍差) - 支持负数:必须显式设
min="-100"(哪怕只是占位) - 别指望 type 校验:用户仍可粘贴
"abc",JS 需监听input事件过滤 - 移动端更可靠:加
inputmode="decimal"强制唤起带小数点的键盘
验证提示怎么放才不跳动
动态插入 span.error 最容易导致表单高度突然变化,尤其 iOS 键盘弹起后视口重算,按钮可能被顶出屏幕。
- 提示统一放在
input下方,用margin-top: 4px预留固定空隙 - 隐藏时用
visibility: hidden,不是display: none—— 否则空隙消失,布局抖动 - 不要把提示塞进
label里,语义错误,屏幕阅读器读不出错误信息 - 所有提示元素加
role="alert",让辅助技术实时感知变化
真正难的不是写出来,而是记住:所有原生控件外层都得套一层 div 并设 min-width: 0,否则 flex/grid 容器默认的 min-width: auto 会锁死宽度,iOS 上 width: 100% 直接失效。



















