原生 select 的展开区域高度无法用 CSS 控制,唯一跨浏览器生效的限高方案是 size 属性;需自定义组件才能实现点击展开、严格限高及键盘导航等需求。

原生 select 的展开区域高度根本不能用 CSS 控制
直接给 select 设 height、max-height 或 line-height,对弹出菜单(即“展开区域”)完全无效。浏览器把顶部选中区和下拉弹层拆成两个独立渲染单元:前者能被部分样式影响,后者由操作系统或 UA 直接绘制,CSS 无法穿透。你在 Chrome 里看到弹出菜单高得离谱、滚动条位置诡异、甚至出现双滚动条,就是这个原因。
size 属性是唯一跨浏览器生效的原生限高方案
它不靠 CSS,而是告诉浏览器“展开时默认显示几行”,从而间接决定弹出区域的初始高度和滚动行为。这是目前最轻量、无障碍友好、无需 JS 的可靠方式。
-
size="4"→ 弹出后固定显示 4 行选项,超出自动加overflow-y: auto - 必须搭配
multiple才能保留多选语义;不加时,size="1"等效于默认单选下拉(但某些旧版 Safari 会丢箭头) - 移动端(尤其是 iOS Safari)可能无视
size,强制走全屏选择器,别指望它在所有设备上一致 - 别设过大的
size值(如 >6),DOM 渲染负担加重,长列表下滚动卡顿明显
要点击展开 + 严格限高?只能自定义 div+ul
当你需要“点击才弹出”“最大高度 200px”“每项 48px 高”“支持键盘导航”这些条件时,size 就不够用了。必须放弃原生 select,用语义化结构模拟:
- 下拉层(
ul)设max-height: 200px+overflow-y: auto—— 这才是真生效的高度限制 - 父容器必须是
position: relative,下拉层用position: absolute; top: 100%定位,否则错位 - 必须监听
Escape键、外部点击、ArrowDown/Up导航,否则键盘和屏幕阅读器不可用 - 原生
select不能删,得保留在 DOM 中(opacity: 0; position: absolute;),并用 JS 同步值,否则表单提交拿不到数据
别碰 transform: scale() 来压高度
有人试过用 transform: scale(1, 0.75) 缩小整个 select,以为能“统一视觉高度”。但它只缩放选中区,弹出菜单依然按原始尺寸展开,反而导致热区偏移、点不中、Lighthouse 报可访问性警告。更麻烦的是:缩放后字体变小,你得手动调大 font-size 补偿,而不同浏览器对 transform-origin 和 margin-top 的计算又不一致——看似省事,实则埋坑。
真正难的不是“怎么写代码”,而是分清哪部分高度你能控(选中区),哪部分你永远控不了(系统弹层)。想 100% 自由,就得接受自定义组件带来的可访问性和移动端适配成本。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











