返回
UI · №15 · PLATE

Link 还是 ButtonLink vs Button

链接按钮超链接能点的用哪个

先看怎么选

页面上有个可点击的东西,你要决定用 `<a>` 还是 `<button>`。选错的代价:键盘用户 Tab 不到(少了 button)、屏幕阅读器误导(「链接」但点了不跳转)、右键「在新标签页打开」失效。

朱批看点了之后去哪——去别的地方(URL 变)用 Link;停在原地做个操作(URL 不变)用 Button。看起来像链接但行为像按钮的,是反模式。

LIVE SPECIMEN真的能玩,点点看

Link

Link / Anchor

用户点了之后会离开当前页面,或跳到页面内另一个位置。URL 栏会变(或锚点变)。语义上是「去某个地方」,不是「做某件事」。

适合
导航到其他页面、下载文件、跳到页面内锚点、打开外部链接。用户期望右键「在新标签页打开」「复制链接」能用。
不适合
不要用 Link 做操作(提交表单、打开弹窗、触发 JS 逻辑但不跳转)——那些是 Button 的事。看起来像链接(蓝色下划线)但 `href="#"` 或 `href="javascript:void(0)"` 的,是反模式。
实现细节与 Prompt
语义标签
`<a href="...">`,必须有真实 href(不是 # 或 javascript:)
键盘
Enter 触发;Tab 可达;屏幕阅读器读作「链接,去往 XX」
样式重置
浏览器默认蓝色 + 下划线;自定义时保持「可点击」信号(颜色/下划线/图标)
可访问性
href 缺失或 `#` 会让屏幕阅读器困惑;`target="_blank"` 需配 `rel="noopener"`
Create a link for [destination]. Requirements: - Use `<a href="...">` with a real URL (not # or javascript:) - Style: Cinnabar (#C13E23) with underline, or Ink with subtle underline - Hover: darken color, keep underline - If external link: add icon (inline SVG arrow-up-right) + `rel="noopener"` - If opens new tab: add `target="_blank"` + visible indicator - Keyboard: Enter triggers navigation - Screen reader: announces as "link, [text]"

Button

Button

用户点了之后停在当前页面,触发一个操作(提交表单、打开弹窗、展开/收起、触发 JS 逻辑)。URL 不变,页面可能局部更新但不是「去别的地方」。

适合
提交表单、打开/关闭弹窗、展开/收起内容、删除、保存、触发任何不跳转的 JS 逻辑。用户不期望右键「在新标签页打开」。
不适合
不要用 Button 做导航(去其他页面)——那会让键盘用户和屏幕阅读器用户困惑(「按钮」但点了跳走了)。也不要给 Button 套 href。
实现细节与 Prompt
语义标签
`<button type="button">` 或 `<button type="submit">`(表单内)
键盘
Enter 和 Space 都能触发;Tab 可达;屏幕阅读器读作「按钮,XX」
type 属性
明确写 `type="button"`(防止表单内误触发提交)或 `type="submit"`
可访问性
禁用时 `disabled` + `aria-disabled="true"`;loading 时保持可聚焦但禁用
Create a button for [action]. Requirements: - Use `<button type="button">` (or `type="submit"` if in a form) - Style: Primary/Secondary/Ghost/Danger per action importance (see Button variants term) - States: Normal, Hover, Active, Disabled, Loading - Keyboard: Enter and Space both trigger; Tab-reachable - Screen reader: announces as "button, [text]" - Never add href to a button; never wrap button in <a>

详细说明

Link 还是 Button

它是什么

页面上能点的东西只有两种语义身份:Link(链接)= 去某个地方Button(按钮)= 做某件事

选对的唯一判断标准:点了之后 URL 变不变

  • URL 会变(或锚点变)→ Link
  • URL 不变,停在原地做操作 → Button

不是「长得像哪个就用哪个」,是「行为像哪个就用哪个」。一个看起来像链接(蓝色下划线)但点了不跳转的,是反模式——骗了用户也骗了屏幕阅读器。

快速判断

用户点了之后 用哪个 例子
去其他页面、去页面内锚点、下载文件 Link 导航栏链接、面包屑、文章标题、「了解更多」
停在原地,触发操作(提交/打开/关闭/删除) Button 提交表单、打开弹窗、展开手风琴、删除、保存
看起来像链接但点了不跳转 反模式 <a href="#">展开</a><a href="javascript:void(0)">删除</a>

常见误区

  • ❌ 「能点的就用 Button」— 错,导航必须用 Link
  • ❌ 「蓝色下划线的就用 Link」— 错,看行为不看样式
  • ❌ 「Button 不能跳转」— 对,Button 只做操作不做导航

为什么要区分

用错标签的代价:

错误 后果
导航用了 Button 右键「在新标签页打开」失效;Cmd+点击失效;屏幕阅读器说「按钮」但行为是跳转,误导
操作用了 Link 屏幕阅读器说「链接,去往 XX」但点了不跳转,困惑;键盘只能 Enter 不能 Space
Link 的 href 是 #javascript: 浏览器历史记录污染;右键菜单功能全失效;屏幕阅读器读出「链接」但没真实目的地

可访问性核心差别

  • Link:屏幕阅读器读作「链接,去往 XX」,只响应 Enter
  • Button:屏幕阅读器读作「按钮,XX」,响应 Enter Space

技术标注

考虑点 Link Button
HTML 标签 <a href="真实 URL"> <button type="button">type="submit"
必需属性 href(必须是真实 URL,不是 # 或 javascript:) type(明确写,防止表单内误触发)
键盘 Enter 触发 Enter Space 都触发
右键菜单 「在新标签页打开」「复制链接」可用 无特殊右键功能
屏幕阅读器 「链接,去往 [href]」 「按钮,[文本]」
焦点样式 默认蓝色轮廓(需自定义为品牌色) 同 Link
外部链接 target="_blank" + rel="noopener" N/A

什么时候用这个词

做设计决策时

场景 1:导航栏

需求:顶部导航栏有「首页」「关于」「联系」三个可点击项

错误:用 Button 因为「看起来像按钮」
├─ 右键「在新标签页打开」失效
├─ Cmd+点击失效
└─ 屏幕阅读器困惑(「按钮」但行为是跳转)

正确:用 Link
├─ <a href="/">首页</a>
├─ <a href="/about">关于</a>
└─ <a href="/contact">联系</a>
  → 所有浏览器功能正常;键盘和屏幕阅读器符合预期

场景 2:卡片上的「了解更多」

需求:文章卡片底部有「了解更多」,点了去文章详情页

错误:<button onclick="location.href='/article/1'">了解更多</button>
├─ 右键菜单失效
├─ 屏幕阅读器说「按钮」但行为是导航
└─ JS 禁用时整个卡片失效

正确:<a href="/article/1">了解更多</a>
  → 即使 JS 禁用也能点;右键功能齐全

场景 3:「展开更多」

需求:折叠内容下方有「展开更多」,点了展开下方隐藏内容(不跳转)

错误:<a href="#" onclick="expand()">展开更多</a>
├─ href="#" 污染浏览器历史
├─ 屏幕阅读器说「链接」但点了不去任何地方
└─ 右键「在新标签页打开」会打开一个一样的页面(没意义)

正确:<button type="button" onclick="expand()">展开更多</button>
  → 语义正确;键盘 Enter/Space 都能触发;屏幕阅读器说「按钮,展开更多」

给 agent 发指令时

不要只说「加个可点击的」——说清是导航还是操作:

需求 1:文章列表每篇文章的标题可点击,去文章详情页
→ 用 Link:<a href="/article/123">文章标题</a>

需求 2:文章详情页底部有「删除文章」,点了弹确认框
→ 用 Button:<button type="button" onclick="confirmDelete()">删除文章</button>

需求 3:侧边栏有「下载 PDF」,点了下载文件
→ 用 Link(下载也是导航的一种):<a href="/report.pdf" download>下载 PDF</a>

常见错误

错误 1:Link 的 href 是 #

<a href="#" onclick="doSomething()">点我</a>

问题:
- 浏览器历史记录里多一条 `#`
- 屏幕阅读器读「链接」但没真实目的地
- 右键「复制链接」得到的是当前页面 URL + #

正确:改用 Button
<button type="button" onclick="doSomething()">点我</button>

错误 2:Button 做导航

<button onclick="location.href='/page2'">下一页</button>

问题:
- 右键「在新标签页打开」失效
- Cmd+点击失效
- 屏幕阅读器说「按钮」但行为是跳转

正确:改用 Link
<a href="/page2">下一页</a>

错误 3:Link 长得像 Button

<a href="/submit" class="btn btn-primary">提交表单</a>

问题:
- 看起来像提交按钮,但点了是跳转(用户困惑)
- 如果真的要提交表单,应该用 <button type="submit">

何时可以:
- 「提交」后真的要跳到另一个页面(比如支付跳转第三方)
- 但这种情况文案应该改成「前往支付」而不是「提交」

错误 4:Button 包在 Link 里(或反过来)

<a href="/page"><button>点我</button></a>  <!-- 非法 HTML -->

问题:
- HTML 规范不允许
- 浏览器行为不一致

正确:只用一个
- 导航:<a href="/page">点我</a>
- 操作:<button type="button">点我</button>

相关词条

  • №03「按钮怎么选」 — Button 确定后,选 Primary / Secondary / Ghost / Danger 的规则
  • №02「页面导航架构」 — 顶栏导航、侧边栏、面包屑都是 Link 的组合应用
  • №03「表单结构与校验」 — 表单的提交按钮用 <button type="submit">
  • №05「页面转场」 — Link 的点击可以触发转场动画(Button 不会)

完整可复制的 Prompt

我需要在页面上加一个可点击元素,帮我判断用 Link 还是 Button:

场景描述:[用户点了之后会发生什么?去其他地方 or 停在原地做操作]

如果是 Link:
- 用 <a href="真实 URL">文本</a>
- 样式遵循 TellYourAgent 设计系统:
  * 导航链接:Ink (#1C1B18) + 无下划线,hover 变 Cinnabar (#C13E23)
  * 正文链接:Cinnabar + 下划线,hover 变 Cinnabar-deep (#A33418)
- 如果是外部链接:加 target="_blank" + rel="noopener" + 外部图标(inline SVG)
- 焦点态:2px Cinnabar outline

如果是 Button:
- 用 <button type="button">文本</button>(表单内用 type="submit")
- 样式按操作重要性选 Primary / Secondary / Ghost / Danger(见「按钮怎么选」词条)
- 所有状态:Normal / Hover / Active / Disabled / Loading
- 焦点态:2px Cinnabar outline
- 键盘:Enter 和 Space 都能触发

如果我描述的场景是「看起来像链接但点了不跳转」:
→ 这是反模式,改成 Button 并去掉链接样式

输出:HTML + CSS(所有状态)+ 使用说明

为什么这个决策很重要

Link vs Button 是 Web 语义的基石。选对了,浏览器的所有功能(右键菜单、键盘快捷键、历史记录、书签)都正常工作;选错了,所有这些都会以微妙的方式坏掉——用户可能说不清哪里不对,但就是觉得「这个网站用起来怪怪的」。

更重要的是,屏幕阅读器用户完全依赖这个语义区分来理解「点了之后会发生什么」。Link 说「你会去某个地方」,Button 说「停在这里做个操作」——搞混了就是在对使用辅助技术的用户撒谎。

一句话:Link 和 Button 的区分,是 Web 可访问性的第一课。