Rediscover the HTML select element
Accessibility & Inclusion 进阶 9m

重新探索 HTML select 元素

Rediscover the HTML select element

2026年6月10日

在 Apple 官方观看视频

一句话判断

✅ 前端开发者终于可以把那些臃肿的第三方 Select JS 库扔进垃圾桶,用纯 CSS 搞定带图标的下拉菜单,且完全不牺牲屏幕阅读器的体验。

这场 Session 讲了什么

这场 Session 最值得关注的一件事是:Safari 27 联合 Chrome 135 彻底重做了 HTML <select> 元素的样式化能力,推出了 Customizable Select(可定制选择框)。过去十几年,只要设计师敢把下拉菜单画成带图标、带网格布局或者非系统默认样式的,前端就得捏着鼻子引入 Headless UI 或 Select2 这种几十 KB 的 JS 库,用一堆 <div> 模拟行为,还得手动补全 ARIA 标签和键盘导航。

现在规则变了。你只需要给原生 <select> 加上 appearance: base-select,就能用 CSS 随意揉捏按钮和下拉面板。更狠的是,<option> 里终于能塞进 SVG 和图片了,配合 <selectedcontent> 元素,选中项的富文本内容能直接镜像到触发按钮上。对于那些死磕设计还原度又不想被 Lighthouse 无障碍评分教做人的团队来说,这绝对是今年 Web 端最解气的更新。

值得深挖的点

appearance: base-select 背后的妥协与克制

Apple 和 Google 这次没有发明新标签,而是选择给古老的 <select> 动刀,这个设计选择非常务实。如果用新标签(比如 <dropdown>),旧浏览器直接不渲染,Progressive Enhancement(渐进增强)就成了空话。保留 <select> 意味着在不支持的浏览器里,它依然会降级为系统原生弹窗,键盘上下键选择和 VoiceOver 朗读完全不受影响。

但克制也带来了限制。appearance: base-select 只是解除了浏览器的默认样式锁定,暴露了 ::picker(select)(下拉面板)和 ::picker-icon(箭头图标)等伪元素。你没法像写普通 <div> 那样给下拉菜单加复杂的交互动画,也没法在里面嵌套输入框做搜索过滤。如果你需要带搜索功能的 Combo Box,这套原生方案依然不够看,老老实实用 JS 库。它解决的是 90% 纯展示型下拉菜单的痛点,而不是去替代复杂的自动完成组件。

富文本 <option><selectedcontent> 的魔法

以前 <option> 里只能放纯文本,想加个图标只能靠 Unicode 字符或者背景图 hack。这次 Safari 允许在 <option> 里直接写 <svg><img>,并且支持用 CSS Grid 把下拉列表排成多列网格。这在摄影师作品集、颜色选择器这种场景下简直是杀手级功能。

最巧妙的设计是 <selectedcontent> 元素。因为原生 <select> 的触发按钮默认只渲染纯文本,当你在 <option> 里放了图标,选中后按钮上却只显示文字,体验非常割裂。把 <selectedcontent> 放在 <select> 内部的第一个 <button> 子元素里,浏览器就会自动把当前选中 <option> 的 DOM 结构克隆到按钮上。这省去了大量监听 change 事件然后手动操作 DOM 的脏活。不过要注意,给 <img>alt="" 是必须的,否则 VoiceOver 会把图片描述和 <option> 文本朗读两遍。

代码片段

1. 基础样式重置与自定义箭头

场景:把系统默认的灰色下拉框改成符合设计系统的圆角按钮,并替换下拉箭头。

/* 开启自定义模式,解除浏览器默认样式 */
select {
    appearance: base-select;
    background-color: var(--bg-primary);
    border: 1px solid var(--border-color);
    padding: 0.6em 1em;
    border-radius: 8px;
}

/* 替换默认的向下箭头 */
select::picker-icon {
    content: url('icons/chevron-down.svg');
    width: 16px;
}

/* 菜单展开时改变按钮和箭头状态 */
select:open {
    background-color: var(--bg-active);
}
select:open::picker-icon {
    content: url('icons/chevron-up.svg');
}

坑:appearance: base-select 必须同时加在 select::picker(select) 上,否则下拉面板还是会保留系统默认的白底黑边样式。

2. 富文本选项与选中内容镜像

场景:在选项中加入 SVG 图标,并在选中后让图标显示在触发按钮上。

<select>
    <!-- 自定义触发按钮,包含 selectedcontent -->
    <button>
        <selectedcontent></selectedcontent>
    </button>
    
    <!-- 选项内直接放置富文本 -->
    <option value="portrait">
        <svg>...</svg>
        <span>人像摄影</span>
    </option>
</select>

坑:<button> 必须是 <select> 的第一个子元素。如果 <option> 里有图片,记得写 alt="",防止屏幕阅读器重复朗读。

最佳实践

老项目迁移时,别急着全局替换。先挑那些因为样式问题被设计师抱怨最多、但又没加搜索功能的简单 <select> 进行改造。把 div 模拟的假下拉菜单换回原生 <select>,能直接砍掉几百 KB 的 JS 依赖。

新项目直接拥抱 <selectedcontent> 和 Grid 布局下拉面板。但在写 CSS 时,务必在 Safari Technology Preview 和 Chrome Canary 里交叉测试 ::picker(select) 的层叠上下文(Stacking Context),目前早期版本在处理带 box-shadow 的下拉面板遮挡问题时偶尔会有 bug。

永远记住,这套方案的底线是 Accessibility(无障碍)。不要为了炫酷的动画去拦截键盘事件,把默认的上下键导航和回车选中逻辑留给浏览器,你只负责画皮。

还有什么值得关注

  • Grid 布局下拉菜单::picker(select) 支持 display: grid,可以直接把长列表变成多列网格,做分类选择器时极其好用。
  • ::checkmark 伪元素:选中项前面的默认打勾图标现在可以通过 CSS content 属性随意替换成自定义 SVG。
  • 跨浏览器一致性:Safari 27 和 Chrome 135 同步首发,这意味着 WebKit 和 Blink 在表单控件自定义上达成了罕见的共识,不用写两套前缀代码。
Safari CSS HTML Accessibility WebKit