C07 表单控件与原生控件
C07 表单控件与原生控件
摘要:原生控件由浏览器绘制,直接改颜色与尺寸往往无效。可控的做法分三步:用
appearance: none移除外观、用accent-color着色仍保留原生行为的部分、用自定义元素加::before重建复选框与单选。焦点可见性由:focus-visible与:user-valid驱动,禁止直接删除 outline。本文给出输入框、复选框、单选、开关与文件上传五类控件的完整样式与四项取舍。
关键词:appearance,accent-color,focus-visible,user-valid,自定义控件
所属:frontend/css / C-高级 | 上一篇:C06-滚动吸附与滚动行为 | 下一篇:C08-图片表格与嵌入内容 | 返回:C00-总结
1 引言
表单是转换率最直接相关的一组控件,也是样式最不容易统一的一组:input 能改内边距,checkbox 改颜色无效,select 的下拉箭头由浏览器绘制,file 的按钮结构不可见。
本文给出三类处理路径与五类控件的完整写法。范围见表 1-1。
| 项 | 本文覆盖 | 本文不覆盖 |
|---|---|---|
| 重置 | appearance: none、尺寸与字体继承 |
浏览器默认样式表差异 |
| 着色 | accent-color、caret-color、::selection |
自定义下拉列表(需 JS) |
| 状态 | :focus-visible、:user-valid、:disabled |
完整校验(JS 科目 D02) |
| 重建 | 复选框、单选、开关、文件选择 | 富文本与日期选择器 |
表 1-1 本文覆盖范围
2 预备知识
| 项 | 要求 | 核对方式 |
|---|---|---|
| 环境 | 本地服务器可用 | 浏览器能打开 localhost |
| 文件 | css-practice/forms.html |
编码 UTF-8 |
| 浏览器 | Chrome 130+ | 支持 :user-valid |
| 前置 | B04、C04 | 伪类与焦点已掌握 |
表 2-1 环境与前置要求
3 原理与实现
3.1 三条处理路径
按「能否着色 → 是否重建」选择路径,如图 3-1 所示。
flowchart TD
A["需要统一样式的控件"] --> B{"原生行为是否可保留"}
B -->|是,仅换色| C["accent-color 一行解决"]
B -->|否,需改结构| D{"是否需要单选/复选语义"}
D -->|是| E["appearance:none + 伪元素重建"]
D -->|否| F["普通元素 + ARIA(需 JS)"]
C --> G["保留键盘与读屏支持"]
E --> G
F --> H["必须自行补齐键盘与 ARIA"]
图 3-1 三条路径按是否保留原生语义划分
图上可见:前两条路径保留键盘操作与无障碍语义,第三条用
div模拟控件会把这部分成本转移给脚本,只在确实需要时才走。
3.2 完整实现
<!-- 运行环境:Chrome 130+;css-practice/forms.html -->
<form class="form">
<label class="field">
<span>邮箱</span>
<input type="email" required placeholder="name@example.com" />
<small>用于接收通知</small>
</label>
<label class="check">
<input type="checkbox" checked />
<span>接收邮件通知</span>
</label>
<fieldset class="choice">
<legend>配送方式</legend>
<label class="radio"><input type="radio" name="ship" checked /><span>标准</span></label>
<label class="radio"><input type="radio" name="ship" /><span>加急</span></label>
</fieldset>
<label class="switch">
<input type="checkbox" role="switch" />
<span>启用暗色模式</span>
</label>
<label class="file">
<input type="file" accept="image/*" />
<span class="file__btn">选择图片</span>
</label>
</form>
/* 运行环境:Chrome 130+;css-practice/forms.css */
:root { --brand: #2563eb; --border: #cbd5e1; --danger: #b91c1c; }
/* 1 基础:控件不继承字体,必须显式声明 */
.form input,
.form select,
.form textarea,
.form button {
font: inherit;
color: inherit;
accent-color: var(--brand); /* 复选框、单选、range 的着色 */
caret-color: var(--brand);
}
.form ::selection { background: #bfdbfe; }
.field input {
inline-size: 100%;
padding: 0.625rem 0.75rem;
border: 1px solid var(--border);
border-radius: 0.5rem;
}
/* 2 焦点可见:仅键盘导航时显示轮廓 */
.field input:focus-visible {
outline: 2px solid var(--brand);
outline-offset: 2px;
border-color: var(--brand);
}
/* 3 用户交互后再提示错误,避免一进页面就报红 */
.field input:user-invalid {
border-color: var(--danger);
}
.field input:user-invalid + small { color: var(--danger); }
/* 4 重建复选框:隐藏原生框,用伪元素绘制 */
.check, .radio, .switch { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; }
.check input, .radio input, .switch input {
appearance: none;
margin: 0;
flex: 0 0 auto;
inline-size: 1.125rem;
block-size: 1.125rem;
border: 2px solid var(--border);
background: #fff;
display: grid;
place-content: center;
}
.radio input { border-radius: 50%; }
.check input::before,
.radio input::before,
.switch input::before {
content: "";
inline-size: 0.75rem;
block-size: 0.75rem;
transform: scale(0);
transition: transform 120ms ease;
background: var(--brand);
clip-path: polygon(14% 44%, 0 58%, 40% 100%, 100% 22%, 86% 8%, 40% 70%);
}
.radio input::before { border-radius: 50%; clip-path: none; }
.check input:checked::before,
.radio input:checked::before { transform: scale(1); }
.check input:checked { border-color: var(--brand); }
/* 5 开关:同一个复选框换个尺寸与圆点 */
.switch input {
inline-size: 2.75rem;
block-size: 1.5rem;
border: none;
border-radius: 999px;
background: #cbd5e1;
justify-content: start;
padding-inline: 0.125rem;
}
.switch input::before {
inline-size: 1.25rem;
block-size: 1.25rem;
background: #fff;
border-radius: 50%;
clip-path: none;
transform: translateX(0);
}
.switch input:checked { background: var(--brand); }
.switch input:checked::before { transform: translateX(1.25rem); }
/* 6 文件上传:隐藏原生控件,用兄弟元素做按钮 */
.file input { position: absolute; opacity: 0; inline-size: 1px; block-size: 1px; }
.file__btn {
display: inline-block;
padding: 0.5rem 0.875rem;
border: 1px dashed var(--border);
border-radius: 0.5rem;
}
.file input:focus-visible + .file__btn {
outline: 2px solid var(--brand);
outline-offset: 2px;
}
:disabled { opacity: 0.55; cursor: not-allowed; }
控件的三条处理路径见表 3-1。
| 路径 | 适用控件 | 保留原生语义 | 成本 |
|---|---|---|---|
accent-color |
复选框、单选、进度、range | 是 | 一行声明 |
appearance: none |
复选框、单选、开关、文件 | 是 | 需伪元素重建 |
| 自定义元素 + ARIA | 组合框、评分、标签输入 | 否 | 需补齐键盘 |
表 3-1 三条路径的适用范围与成本
状态伪类的差异见表 3-2。
| 伪类 | 触发条件 | 用途 |
|---|---|---|
:focus |
获得焦点(含鼠标点击) | 不用于描边,避免点击后残留 |
:focus-visible |
浏览器判定需要提示时(多为键盘) | 焦点轮廓的标准写法 |
:valid/:invalid |
校验状态,页面加载即判定 | 仅用于无需交互的场景 |
:user-valid/:user-invalid |
用户交互后才判定 | 表单错误提示的标准写法 |
:disabled |
控件被禁用 | 降透明度并禁用指针 |
:placeholder-shown |
显示占位文本时 | 浮动标签动画 |
表 3-2 六类状态伪类的触发时机差异
4 验证与讨论
- 用 Tab 键在表单内移动,确认只有键盘导航时显示蓝色轮廓,鼠标点击输入框不显示。
- 在邮箱框输入
abc,确认提交或失焦后才变红,初次加载不报红。 - 点击复选框与开关,确认对勾与圆点有过渡动画且状态正确。
- 用键盘聚焦隐藏的 file 控件,确认外圈按钮出现焦点轮廓。
| 检查项 | 预期结果 | 说明 |
|---|---|---|
| 字体继承 | 控件字号与页面一致 | font: inherit |
| 焦点轮廓 | 键盘可见、鼠标点击不残留 | 表 3-2 |
| 延迟报错 | 未交互时不报红 | :user-invalid |
| 状态可见 | 勾选与开关状态有视觉差异 | 3.2 节伪元素代码 |
| 键盘可达 | 隐藏的 file 仍可 Tab 到 | 透明而非 display:none |
表 4-1 五项验收
讨论与局限。 appearance: none 之后控件仍由同一个 input 承担语义,读屏与表单提交不受影响;若改用 div 模拟,则需自行实现键盘与 aria-checked。另,:user-invalid 在部分移动端浏览器支持较晚,需配合脚本兜底,见 JS 科目 D02。
5 常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 控件字号比页面小 | 表单控件不继承字体 | 显式写 font: inherit |
| 改复选框颜色无效 | 未用 accent-color 或 appearance |
二选一,按表 3-1 选路径 |
| 点击后轮廓一直存在 | 用了 :focus |
改 :focus-visible |
| 一进页面全部报红 | 用了 :invalid |
改 :user-invalid |
| 隐藏 file 后无法键盘访问 | 用了 display: none |
用透明与 1 像素尺寸隐藏 |
| 下拉箭头样式改不掉 | select 外观由系统绘制 |
保留原生或改用自定义列表(需 JS) |
表 5-1 表单控件的六类问题
6 结论
| 序号 | 结论 | 依据 |
|---|---|---|
| 1 | 先判断能否保留原生语义,再选路径 | 图 3-1 |
| 2 | 控件必须显式声明 font: inherit |
3.2 节 |
| 3 | 焦点轮廓用 :focus-visible |
表 3-2 |
| 4 | 错误提示用 :user-invalid,不用 :invalid |
表 3-2 |
表 6-1 结论汇总
- 上一篇:C06-滚动吸附与滚动行为
- 下一篇:C08-图片表格与嵌入内容
- 返回:C00-总结 | 科目 README
参考文献
[1] MDN Web Docs · 样式化表单控件,https://developer.mozilla.org/zh-CN/docs/Learn/Forms/Styling_web_forms(访问于 2026-10-31)
[2] MDN Web Docs · accent-color,https://developer.mozilla.org/zh-CN/docs/Web/CSS/accent-color(访问于 2026-10-31)

评论 0
还没有评论,快来抢沙发吧~