原生<select>支持多选必须添加布尔属性multiple,即<select multiple>;JS需用selectedOptions获取全部值,后端须按数组接收,移动端多选不可靠。

原生 <select> 标签要支持多选,只有一条硬规则:multiple 属性必须存在,且必须是布尔属性写法——<select multiple>。不加它,按住 Ctrl/Cmd 点击也只会切换当前项,不是累加。
怎么写才合法:multiple 是布尔属性,不是字符串
常见错误是写成 <select multiple="true"> 或 <select multiple="1">。虽然部分浏览器能容错,但 HTML 规范只要求存在该属性即可,推荐只写 multiple 二字。XHTML 场景下才需写成 multiple="multiple",但如今极少用 XHTML,没必要引入冗余。
-
<select multiple>✅ 推荐,简洁、语义清晰、兼容性好 -
<select multiple="">✅ 合法,空字符串值在 HTML5 中等价于存在 -
<select multiple="multiple">⚠️ 可用但不必要,易与自定义属性混淆 -
<select multiple="true">❌ 不规范,某些旧版 Safari 或严格解析器可能忽略
为什么表单提交后后端只收到一个值
根本原因有两个:前端没正确取值 + 后端没按数组接收。原生 select.value 永远只返回第一个选中项的 value 字符串,和是否 multiple 无关。
- JS 获取全部值,必须用
select.selectedOptions:Array.from(select.selectedOptions).map(opt => opt.value) - 表单提交时,
<select multiple name="tag">会发出多个同名参数(如tag=1&tag=3&tag=5),后端需按数组/列表类型接收(如 PHP 的$_POST['tag']是数组,Node.js 的req.body.tag需配置urlencoded({ extended: true })) - 如果后端框架要求显式数组名(如 Laravel、Django),建议写成
name="tag[]",更直观,也避免部分中间件解析歧义
移动端多选基本不可靠,别把它当核心交互
iOS Safari 完全忽略 multiple 属性,点开仍是单选弹窗;安卓 Chrome 表现不一,有些机型无视觉反馈、无法取消已选。这不是 bug,是浏览器厂商对移动端表单体验的主动降级。
立即学习“前端免费学习笔记(深入)”;
- 不要在 iOS 上测试“是否多选生效”,它不会触发任何多选逻辑
- 若业务强依赖多选,必须换方案:用
<input type="checkbox">组合 + CSS 模拟下拉展开,或引入tom-select、Choices.js这类库(注意它们初始化时仍需传入multiple: true) - 如果坚持用原生
<select multiple>,至少加提示文字:<div class="hint">PC 端按 Ctrl/Cmd 多选</div>,避免用户困惑
size 属性不是可选项,而是体验刚需
不设 size,多数浏览器默认只显示 2 行(含滚动条),用户看不到全部选项,还得拖动,极易漏选。这不是样式问题,是可用性断层。
-
<select multiple size="5">是合理起点,确保常见场景下至少 5 项可见 -
size和multiple无关:不加multiple时size="5"只是显示 5 行单选;加了multiple才真正启用多选能力 - CSS 覆盖
height或max-height容易破坏原生滚动行为,优先用size控制行数,再微调字体/行高
最常被忽略的其实是前后端协作细节:前端写了 multiple,但 JS 取值还用 value,后端又没按数组收——三处都对,但连起来就是“明明多选了却只存了一个”。这种链路问题,比语法错误更难排查。



















