如何做一个链接到页面的按钮
写一个普通的链接 <a href>,再用 CSS 把它设置成按钮的样子。它像任何链接一样跳转到页面,而且保留了链接的所有功能:在新标签页中打开、复制链接地址,以及悬停时预览 URL。
把链接变成按钮的几条规则:
display: inline-block让内边距能把盒子撑开,同时让它保持在文字行内。text-decoration: none去掉下划线。color和background替换掉蓝色的链接颜色。:focus-visible为键盘用户提供清晰的焦点环。
同一个类也适用于 <button>,所以表单的提交按钮和链接到其他页面的链接可以看起来一模一样,同时各司其职。
按钮还是链接:该用哪个元素
关键在于点击后会发生什么,而不是它看起来像什么。
| 点击后 | 使用 | 示例 |
|---|---|---|
| 跳转到另一个 URL | <a href> | 注册、阅读更多、查看价格、下载 |
| 改变当前页面上的某些内容 | <button type="button"> | 打开菜单、播放、加入购物车、显示密码 |
| 提交表单 | <button type="submit"> | 登录、搜索、保存 |
屏幕阅读器把链接播报为“链接”,把按钮播报为“按钮”,以此告诉用户接下来会发生什么。它们的键盘行为也不同:Enter 键对两者都有效,但空格键只能激活按钮(在链接上按空格会滚动页面)。按钮元素本身的介绍见 HTML 按钮。
为什么不要把按钮放在链接里
大多数人首先尝试的都是这种写法:
<!-- Invalid: interactive content inside <a> -->
<a href="/signup"><button>Sign up</button></a>
<!-- Invalid the other way round, too -->
<button><a href="/signup">Sign up</a></button>
HTML 标准对这两种写法都是禁止的:<a> 和 <button> 里面都不能包含交互元素。实际上,键盘会在一个控件上遇到两个 Tab 停留点,屏幕阅读器可能会播报“链接,按钮,Sign up”,而点击是否会跟随链接取决于浏览器。只选一个元素。
为什么不要用 onclick 加 location.href
另一种常见的变通办法,是做一个用 JavaScript 设置 URL 的按钮。它看起来和链接一样:
(示例里用的是 window.open,因为预览不能离开当前页面;平时的写法是 location.href = '...'。)把鼠标悬停在两者上并点击右键:只有真正的链接会显示它的 URL,并提供“在新标签页中打开链接”和“复制链接地址”。按钮也无法用 Ctrl+点击或中键点击,浏览器不会把它标记为已访问,搜索引擎也不会把它当作链接来抓取。如果目标是一个 URL,就写 <a href>。
打开 URL 的表单按钮
有一种情况下,跳转到其他页面的 <button> 是正确的:它需要同时发送数据。搜索框就是典型的例子。表单的 action 是 URL,method="get" 会把字段放进查询字符串:
点击 Search:在真实页面中,浏览器会跳转到 https://duckduckgo.com/?q=html+button+link。预览不会离开页面,而是显示这些数据。第二个按钮上的 formaction 会把同一个表单发送到另一个 URL。
禁用的链接按钮
链接没有 disabled 属性;<a disabled> 什么作用都没有。要关闭一个链接按钮,就删掉它的 href(没有 href 的 <a> 不是链接,无法点击也无法聚焦),并用 aria-disabled="true" 标记它,让样式和屏幕阅读器都知道:
在预览中按 Tab 键:焦点只会落在第一个按钮上。有些网站保留 href,改用 pointer-events: none,但这只能阻止鼠标。用 Tab 键依然能访问到这个链接,按 Enter 也依然会跳转。
新标签页和下载按钮
设置成按钮样式的链接,所有链接属性依然有效:
<a class="btn" href="/files/guide.pdf" download>Download the guide</a>
<a class="btn" href="https://github.com/" target="_blank" rel="noopener">GitHub</a>
这是使用 <a> 的又一个理由:<button> 没有 download 或 target。关于 target 的更多内容,请参阅在新标签页中打开链接。
常见错误
- 链接里套按钮,或按钮里套链接。 不合法的 HTML,行为无法预测。
- 用
<button onclick="location.href=...">做普通跳转。 无法在新标签页打开,无法复制链接,也无法被抓取。 - 在跳转用的链接上加
role="button"。 它告诉屏幕阅读器用户这里有个按钮,结果页面却跳转了。保持它是链接。 - 把链接做成按钮样式来执行操作,比如用
href="#"做“删除”或“打开菜单”。如果没有页面要加载,就用<button type="button">。 <a disabled>。 链接上根本没有这个属性。删掉href。- 忘了写
display: inline-block,导致垂直内边距与上下行文字重叠。
常见问题
在 HTML 中如何做一个链接到其他页面的按钮?
使用链接,并把它设置成按钮的样式:<a href="/signup" class="btn">Sign up</a>,再用 CSS 设置内边距、背景、圆角和 text-decoration: none。它看起来像按钮,行为上则是链接,而它本来就是链接。
可以把按钮放在 a 标签里面吗?
不可以。HTML 标准不允许在 <a> 里面放 <button> 这类交互内容。各个浏览器的处理方式不同,键盘用户会在一个控件上遇到两个 Tab 停留点,屏幕阅读器的播报也会让人困惑。只用一个元素。
button 有 href 属性吗?
没有。<button> 没有 href。要让浏览器跳转到某个 URL,使用 <a href>,或者把按钮放进带有 action 的 <form> 中(按钮上的 formaction 属性可以覆盖它)。
在按钮上用 onclick 加 location.href 不好吗?
能用,但读者会失去链接带来的一切:用中键点击或 Ctrl+点击在新标签页打开、复制链接地址、悬停时预览 URL,搜索引擎也不会把它当作链接来抓取。目标是 URL 时,请使用 <a>。
如何禁用一个看起来像按钮的链接?
链接没有 disabled 属性。删掉 href,让它不再是链接,加上 aria-disabled="true",并设置成禁用的样式。需要它重新可用时,再把 href 加回来。