网页上那些能点的东西,看着都一样,背地里却可能藏着两种完全不同的命。一种是用<div>硬装出来的按钮,一种就是原生的<button>。好多时候图省事,随手就丢个<div role="button">上去,心想反正能点就行,用户又看不出来。可这玩意儿真没那么简单,这里面差的可不是一星半点,而是从骨子里就决定了这玩意到底好不好用,尤其是对那些不用鼠标、靠键盘或者读屏软件上网的人来说,体验简直是天差地别。
为啥用div冒充button会被喷?
以前总觉得说用语义标签就是“为了规范”,听起来跟喊口号似的。真正上手比划比划,才发现这俩玩意在浏览器眼里压根就不是一个物种。打开开发者工具,用那个检查元素的功能一看,原生<button>自带的那些属性,<div>基本全得靠手动硬编码去补,而且补得还不一定对。
在开发者工具里扒一扒它们的底裤
拿俩东西放一块对比,啥都清楚了。先整一个正宗的<button>自定义按钮</button>,再搞一个<div class="btn" role="button">自定义按钮</div>,然后用浏览器那个审查元素的家伙,点开“无障碍属性”或者“属性”那一栏,差别一下就显出来了。
| 特性对比 | 原生按钮 | 模拟按钮 |
|---|---|---|
| 角色标识 | 按钮 | 通用 |
| 标签内容 | 按钮文字 | 无 |
| 默认聚焦 | 支持 | 不支持 |
| 键盘触发 | 空格回车 | 不支持 |
原生那个直接就把自己“按钮”的身份亮出来了,里面的文字自动就成了给读屏软件听的标签,而且键盘一按Tab键,焦点框“啪”一下就套上去了,敲空格或者回车,它立马就有反应。再看那个<div>,身份就是个“通用”玩意儿,没标签,Tab键按到死也切不到它身上,敲键盘更是一点动静没有。
给div强行续命的那些骚操作
有些头铁的朋友可能会说,这有啥难的,给它补上不就完了?行,那就看看给这个<div>把功能补齐得花多少功夫。光加个role="button"还远远不够,那只是告诉读屏软件“我像个按钮”,但实际行为一点没变。得手动给它加上tabindex="0",这样Tab键才能切到它。可就算切上去了,敲空格和回车还是没反应,还得写JavaScript去监听键盘事件。而且空格键和回车键在浏览器里干的活还不一样,得分别处理,一个管滚动页面不触发的场景,一个管触发的场景,稍微不注意就写漏了。更别提还得自己实现一个禁用状态,原生按钮加个disabled属性就完事,<div>这边又得折腾一堆属性监听和样式覆盖。
| 功能点 | 原生实现 | 模拟实现 |
|---|---|---|
| 禁用状态 | 加属性即可 | 写逻辑加样式 |
| 焦点管理 | 浏览器自带 | 手动加索引 |
| 键盘交互 | 自动支持 | 脚本监听 |
| 语义暴露 | 自动识别 | 手动加角色 |
这弯道超车的代价也太大了,本来一行标签能搞定的事,非要写成几十行代码,还容易出岔子。给<div>加个role="button",就好比给自行车贴了个“法拉利”的标,蹬起来该累还是累,该没顶棚还是没顶棚。
想把button样式随心改,有什么化繁为简的办法?
很多人死抱着<div>不放,无非是嫌原生<button>自带了太多默认样式,什么边框、背景、内边距,每个浏览器长得还不一样,重置起来感觉麻烦。其实这就有点因噎废食了,重置样式根本就是一行CSS的事,比重新造轮子省心多了。
一行CSS让button变白纸
写样式的时候,直接给所有按钮来个“格式化”操作,把那些自带的花里胡哨统统抹掉。就这一句:
button {
all: unset;
}这行代码跟卸妆似的,把<button>身上所有浏览器强加的样式全都清干净,连默认的盒子模型都给你回归到最原始状态。清完以后,它就跟<div>一样白纸一张,想怎么画就怎么画。要是觉得all: unset太猛了,也可以只挑几个关键属性重置:
button {
background: none;
border: none;
padding: 0;
font: inherit;
color: inherit;
cursor: pointer;
}这么一套组合拳下来,<button>那点“臭脾气”就全被捋顺了。剩下的就是用同一个CSS类名,比如.btn,给原生按钮和模拟按钮套上同样的样式,从外观上根本看不出区别,但背后的功能却一个天上一个地下。
样式克隆,功能不掉队
写样式的时候,完全可以设计一个.btn类,把圆角、背景、阴影、悬停效果都定义好。然后:
<button class="btn">点我提交</button>
<div class="btn" role="button">点我提交</div>俩东西摆在一起,视觉上一模一样。可真正跑起来,<div>那个除了长得像,键盘用户根本够不着,屏幕阅读器也不确定这玩意儿到底是啥。所以与其在这上面纠结那点重置样式的时间,不如直接养成习惯,凡是能点的交互控件,无脑用<button>就对了。样式的事,本来就应该交给CSS去管,HTML负责把结构的底子打好。那些以为用<div>能弯道超车的,最后往往都在可访问性测试上翻车翻得焦头烂额。
