:required伪类仅匹配必填控件,不自动显示红星;需通过label::after添加星号并配合aria-required保障可访问性。

为什么 :required 本身不显示红星
:required 只是匹配带 required 属性的表单控件,它不生成内容,也不改变外观——它只是个“开关”,后续样式得自己写。直接只写 input:required { color: red; } 很难精准定位到“标签旁的星号”,因为星号不是输入框的一部分。
用 ::after 在 label 上加星号最稳妥
真正可维护的做法是把星号加在 label 上,前提是 label 和 input 有明确关联(用 for 或嵌套)。这样视觉逻辑清晰,且不会干扰表单交互。
- 确保每个必填项的
label正确绑定:<label for="name">姓名</label><input id="name" required> - 用属性选择器匹配带
required的 input,再用label[for]关联其 label:input:required + label::after不可靠(顺序可能错),改用label[for]:has(+ input:required)::after——但注意:has()在旧版 Safari 中不支持 - 更兼容的写法是手动加 class:
<label class="required">姓名</label>,然后写label.required::after { content: " *"; color: #e53935; }
:required 配合 input:valid 做状态反馈更实用
光加星号只是提示“要填”,用户提交失败时才真正需要反馈。这时候结合 :required:invalid 给边框变红、加图标,比静态星号有用得多。
-
input:required:invalid:not(:placeholder-shown) { border-color: #f44336; }—— 排除 placeholder 占位时的误触发 - 避免用
:required:invalid直接加::after星号,因为初始加载时所有空必填项都匹配,会显得页面一打开就满屏报错 - 如果要用 JS 触发校验态,记得调用
input.reportValidity(),否则:valid/:invalid不更新
移动端和屏幕阅读器的隐藏星号风险
很多人用 content: "*" 加星号,但这对屏幕阅读器不可见,也容易被缩放或字体渲染影响位置。若需无障碍支持,必须额外加 aria-required="true",且星号应包裹在 span 里并设 aria-hidden="true"。
立即学习“前端免费学习笔记(深入)”;
- 推荐结构:
<label>邮箱 <span aria-hidden="true" class="required-mark">*</span></label><input required aria-required="true"> - 纯 CSS 方案无法让读屏软件把星号读作“必填”,所以
aria-required是刚需,不能省 - 别用
font-size: 0或visibility: hidden隐藏星号——这会让它既看不见也读不到,破坏可访问性


















