返回
UI · №18 · SPECIMEN
复选框Checkbox
复选框多选框勾选框不定态全选
LIVE SPECIMEN真的能玩,点点看
单个 Checkbox
多选分组
全选 + 不定态
试试看
验证方式:
- 点击区域:label 文字可点击(不只是小方框)
- 键盘:Tab 聚焦到 Checkbox,Space 切换选中 / 未选
- 不定态:在「全选任务」区域勾选部分任务,父级 Checkbox 显示横线(不定态)
- 焦点环:Tab 浏览时所有 Checkbox 有可见焦点环(朱砂色 outline)
先看结论
用户从列表中选择多个选项(或单个可选项)的控件。可以多选(和 Radio 的"单选"相反)、随表单提交(和 Switch 的"立即生效"相对)、有三种视觉状态(未选 / 已选 / 不定态)。
- 适合
- 表单中的多选列表、单个可选项(接受协议)、全选场景(父级 Checkbox 用不定态表示"部分已选")。用户期望「勾选后随表单提交」,不是「拨一下立即生效」。
- 不适合
- 不要用 Checkbox 做立即生效的开关(用 Switch);不要用 Checkbox 做单选(用 Radio);不要在单个 Checkbox 上用不定态(那是全选场景专用);不要忘记关联 label(点击文字应该能勾选)。
直接发给 agent
Create a checkbox group for [options].
Requirements:
- Use <input type="checkbox"> with unique id + <label for="..."> for each option
- Style:
* Unchecked: 16x16px square, 2px border Ink-2 (#6B675F), border-radius 2px
* Checked: background Cinnabar (#C13E23), white checkmark icon (inline SVG)
* Indeterminate: background Cinnabar, white minus icon (inline SVG)
* Disabled: opacity 0.5, cursor not-allowed
* Focus: 2px Cinnabar outline, offset 2px
- Click area: label text is clickable (not just the box)
- If "select all" is needed:
* Parent checkbox shows indeterminate state when some (not all) children are checked
* Clicking parent when indeterminate → check all
* Clicking parent when all checked → uncheck all
- Keyboard: Tab to focus, Space to toggle
- Screen reader: announces "checkbox, [label], checked/unchecked/mixed"
技术标注5 项
- 语义标签
- <input type="checkbox"> + <label>,label 的 for 属性关联 input id
- 键盘
- Tab 可达;Space 切换选中 / 未选;Enter 不触发(那是提交表单)
- 不定态
- 只能通过 JS 设置 indeterminate=true,HTML 属性无法直接写
- 分组
- 多个 Checkbox 用 <fieldset> + <legend> 包裹,提供分组语义
- 可访问性
- aria-checked(true/false/mixed);禁用时 disabled + aria-disabled=true
详细说明
复选框
它是什么
Checkbox 是用户从列表中选择多个选项(或单个可选项)的控件。
核心特征:
- 可以多选(和 Radio 的“单选”相反)
- 随表单提交(和 Switch 的“立即生效”相对)
- 有三种视觉状态:未选 / 已选 / 不定态(后者只用于全选场景)
什么时候用 Checkbox? 见 №03「选择控件(怎么选)」词条的完整辨析。这个词条只讲 Checkbox 自己怎么做。
三种核心状态
| 状态 | 视觉 | 什么时候用 |
|---|---|---|
| 未选中 | 空心方框 | 用户未勾选此项 |
| 已选中 | 实心方框 + 白色对勾 | 用户已勾选此项 |
| 不定态 | 实心方框 + 白色横线 | 只用于全选场景:父级 Checkbox 表示“部分子项已选” |
不定态(Indeterminate)的唯一用途:
场景:邮件列表的「全选」Checkbox
邮件列表共 10 封:
[ ] 全选 ← 父级 Checkbox,当前未选
[ ] 邮件 1
[ ] 邮件 2
...
用户勾选了 3 封:
[−] 全选 ← 不定态(部分已选)
[✓] 邮件 1
[✓] 邮件 2
[✓] 邮件 3
[ ] 邮件 4
...
用户点击「全选」Checkbox:
[✓] 全选 ← 从不定态变为全选
[✓] 邮件 1
[✓] 邮件 2
...全部勾上
不要在单个 Checkbox 上用不定态——那是「全选 / 部分选」场景专用的父级状态。
技术标注
| 考虑点 | 决策 |
|---|---|
| HTML 结构 | <input type="checkbox" id="..."> + <label for="...">,label 关联让文字可点 |
| 尺寸 | Checkbox 本体 16x16px;label 文字 14-16px;整行最小点击区域 44px 高 |
| 对比度 | 边框 Ink-2 (#6B675F) 对比度 4.5+;选中态背景 Cinnabar (#C13E23) 对比度 5.28 |
| 不定态设置 | 只能通过 JS:checkbox.indeterminate = true,HTML 无此属性 |
| 分组 | 多个 Checkbox 用 <fieldset> + <legend> 包裹,提供语义分组 |
| 键盘 | Tab 聚焦;Space 切换选中 / 未选;Enter 不触发(那是提交表单) |
| 可访问性 | aria-checked="true/false/mixed";禁用时 disabled + aria-disabled="true" |
什么时候用这个词
做设计决策时
场景 1:单个可选项(接受协议)
表单底部有「我已阅读并同意服务条款」
用 Checkbox(不是 Switch):
理由 1:这是表单的一部分,随提交一起发送
理由 2:用户期望「勾选后点提交」,不是「拨一下立即生效」
理由 3:视觉上 Checkbox 和表单其他输入框更协调
<label>
<input type="checkbox" id="terms" required>
我已阅读并同意<a href="/terms">服务条款</a>
</label>
场景 2:多选列表(兴趣标签)
注册时选择兴趣:
[ ] 前端开发
[ ] 后端开发
[ ] 设计
[ ] 产品
用户可以选 0 个、1 个或多个 → Checkbox
(如果是"只能选一个",那就该用 Radio)
<fieldset>
<legend>选择你感兴趣的领域</legend>
<label><input type="checkbox" name="interests" value="frontend"> 前端开发</label>
<label><input type="checkbox" name="interests" value="backend"> 后端开发</label>
<label><input type="checkbox" name="interests" value="design"> 设计</label>
<label><input type="checkbox" name="interests" value="product"> 产品</label>
</fieldset>
场景 3:全选 + 不定态
邮件列表批量操作:
[−] 全选(当前选了 3 封) ← 父级 Checkbox,不定态
[✓] 邮件 1
[✓] 邮件 2
[✓] 邮件 3
[ ] 邮件 4
[ ] 邮件 5
交互逻辑:
- 用户勾选任意子项 → 父级变不定态(如果不是全选)
- 用户点不定态的父级 → 全选所有子项
- 用户点全选态的父级 → 取消所有子项
JS 示例:
parentCheckbox.indeterminate = (checkedCount > 0 && checkedCount < totalCount);
parentCheckbox.checked = (checkedCount === totalCount);
给 agent 发指令时
设计一个任务管理应用的「任务列表」批量选择功能。
需求:
1. 列表顶部有「全选」Checkbox
2. 每个任务左侧有独立 Checkbox
3. 用户可以勾选多个任务后批量删除
交互要求:
- 勾选部分任务时,「全选」Checkbox 显示不定态(实心 + 横线)
- 点击不定态的「全选」→ 全部勾上
- 点击全选态的「全选」→ 全部取消
- 所有 Checkbox 支持键盘操作(Tab + Space)
样式要求(遵循 TellYourAgent 设计系统):
- Checkbox 尺寸 16x16px,圆角 2px
- 未选:2px 边框 Ink-2 (#6B675F)
- 已选 / 不定态:背景 Cinnabar (#C13E23),白色图标(对勾 / 横线)
- 禁用:opacity 0.5
- Focus:2px Cinnabar outline,offset 2px
- label 文字可点击(点击区域 = Checkbox + label 文字)
输出:HTML + CSS + JS(全选逻辑)+ 可访问性标注
常见错误
错误 1:label 和 input 没有关联
<!-- 错误 -->
<input type="checkbox" id="terms">
<label>我同意服务条款</label>
问题:点击文字不会勾选 Checkbox,用户只能点那个小方框(移动端很难点)
<!-- 正确 -->
<input type="checkbox" id="terms">
<label for="terms">我同意服务条款</label>
或者:
<label>
<input type="checkbox">
我同意服务条款
</label>
错误 2:在非全选场景用不定态
单个 Checkbox 显示不定态(横线)
用户困惑:这是选中还是没选中?
正确做法:不定态只用于「全选 Checkbox 表示部分子项已选」,
单个 Checkbox 只有选中 / 未选两种状态。
错误 3:Checkbox 太小
Checkbox 只有 12x12px,label 文字紧贴着
问题:移动端用户点不中(手指触达区域推荐 ≥44px)
正确做法:
- Checkbox 本体 16x16px
- 整行(Checkbox + label)最小高度 44px
- label 文字和 Checkbox 之间留 8-12px 间距
错误 4:只用颜色标记选中态
选中时只是边框变红,没有对勾图标
问题:色弱用户看不出选中 / 未选的区别
正确做法:选中态用「颜色 + 图标」双通道
- 背景变 Cinnabar
- 显示白色对勾
错误 5:禁用时没有视觉反馈
<input type="checkbox" disabled>
CSS 里没写 :disabled 样式,看起来和正常 Checkbox 一样
用户困惑:为什么点了没反应?
正确做法:
input[type="checkbox"]:disabled {
opacity: 0.5;
cursor: not-allowed;
}
相关词条
- №03「选择控件(怎么选)」 — Switch vs Checkbox vs Radio 完整辨析(什么时候用哪个)
- №03「表单结构与校验」 — Checkbox 作为表单字段的校验规则(必选 / 至少选 N 个)
- №03「按钮怎么选」 — Checkbox 分组通常配合操作按钮(「删除选中项」用 Danger)
- №04「表单验证提示」 — Checkbox 未勾选时的错误提示怎么显示
完整可复制的 Prompt
设计一个任务管理应用的「任务列表」,包含批量选择功能。
需求:
1. 列表顶部有「全选」Checkbox
2. 每个任务项左侧有独立 Checkbox
3. 列表底部有「删除选中项」按钮(Danger 变体)
HTML 结构:
- 用 <fieldset> + <legend> 包裹整个 Checkbox 分组
- 每个 Checkbox 用 <input type="checkbox"> + <label for="...">
- label 必须关联 input(点文字能勾选)
样式要求(遵循 TellYourAgent 设计系统):
- Checkbox 尺寸:16x16px,border-radius 2px
- 未选:2px 边框 Ink-2 (#6B675F),透明背景
- 已选:背景 Cinnabar (#C13E23),白色对勾(inline SVG)
- 不定态:背景 Cinnabar,白色横线(inline SVG)
- 禁用:opacity 0.5,cursor not-allowed
- Hover:边框变深(未选时)或背景变深(已选时)
- Focus:2px Cinnabar outline,offset 2px
- label 文字:14px,颜色 Ink (#1C1B18),与 Checkbox 间距 12px
- 整行最小高度:44px(移动端触达标准)
交互逻辑(JS):
1. 勾选任意子项:
- 如果全部勾选 → 父级 checked=true, indeterminate=false
- 如果部分勾选 → 父级 indeterminate=true
- 如果全部未勾选 → 父级 checked=false, indeterminate=false
2. 点击父级「全选」:
- 当前未选 → 全部勾上
- 当前不定态 → 全部勾上
- 当前全选 → 全部取消
3. 「删除选中项」按钮:
- 没有选中项时 disabled
- 有选中项时显示数量(「删除 3 项」)
可访问性:
- 每个 Checkbox 的 label 清晰描述选项内容
- 禁用时 aria-disabled="true"
- 父级 Checkbox 不定态时 aria-checked="mixed"
- 键盘操作:Tab 遍历,Space 切换选中 / 未选
响应式:
- 移动端(<768px):label 文字可以换行,保持 44px 最小点击高度
- 桌面端(≥768px):Checkbox 和 label 单行显示
输出:
- HTML(语义化结构)
- CSS(所有状态 + 响应式)
- JS(全选逻辑 + 按钮禁用逻辑)
- 可访问性标注(aria-* 属性说明)
为什么这个决策很重要
Checkbox 看起来很简单,但细节决定体验:
- label 不关联 input → 移动端用户点不中,弃填
- 不定态乱用 → 用户困惑「这是选中还是没选中」
- 只用颜色标记 → 色弱用户分不出选中 / 未选
- Checkbox 太小 → 触达区域不足,点击失败率高
一句话:Checkbox 的可用性,90% 取决于「label 能不能点」和「视觉反馈够不够清晰」。