如何在 HTML 中创建按钮
按钮就是 <button> 元素。标签之间的内容是用户看到的文字,type="button" 表示它运行你的脚本,而不是提交表单。在预览中点击它:
一个能用的按钮只需要这些:文字、type,以及监听 click 的代码。浏览器会让它可以通过键盘聚焦,并且按 Enter 或空格键就能激活,所以键盘用户无需额外处理就能使用。带点击处理函数的 <div> 则什么都没有。
你也可能见过直接写在标签里的 onclick="..."。它能用,但 addEventListener 让脚本和标记分离,还能让多个监听器共用一个按钮。
三种按钮类型
type 属性决定按钮被按下时做什么。
type | 作用 | 用途 |
|---|---|---|
submit | 提交它所属的表单。这是默认值。 | 表单的主要操作 |
button | 本身什么都不做,由你的 JavaScript 决定 | 开关、对话框、计数器,以及任何由脚本控制的功能 |
reset | 把表单的每个字段恢复为初始值 | 很少用;用户容易误点 |
先输入一些内容,再逐个试试这些按钮。表单提交时预览不会离开页面,而是显示表单将要发送的数据。
Reset 恢复的是 HTML 中写好的值(Ada),而不是清空字段。如果你把 Uppercase 按钮上的 type="button" 删掉,它就变成了提交按钮:先把名字转成大写,然后提交表单。
HTML 提交按钮:发送 name 和 value
提交按钮可以带有自己的 name 和 value。只有当这个按钮是触发提交的那个按钮时,它们才会随表单发送,所以两个按钮可以共用一个表单,并告诉服务器选择的是哪个操作:
点击 Publish,表单会发送 title=My first post 和 action=publish。清空标题后再点任意一个按钮:required 会阻止提交,浏览器会显示它自己的提示。在文本框里按 Enter 也会提交,浏览器会把它当作按下了第一个提交按钮,所以发送的是 action=draft。
提交按钮还支持一些只对这个按钮生效、覆盖表单设置的属性:formaction(不同的 URL)、formmethod、formtarget,以及跳过验证的 formnovalidate。对于在必填字段还空着时也应该能用的“保存草稿”按钮,通常会选择 formnovalidate。
放在表单外面的按钮也可以通过 form 属性提交它,属性值是表单的 id:<button type="submit" form="signup">Sign up</button>。
禁用按钮
disabled 属性会关闭按钮。禁用的按钮不响应点击,按 Tab 时会被跳过,也不会随表单发送。浏览器还会把它显示成灰色。一种常见做法是在满足某个条件之前,一直让提交按钮保持禁用:
在 JavaScript 中,button.disabled 是一个布尔属性:把它设为 true 或 false。在 HTML 中,起作用的是这个属性是否存在,所以 disabled="false" 仍然会禁用按钮。
禁用的按钮不会说明自己为什么被禁用,用 Tab 键浏览的键盘用户和屏幕阅读器用户也永远不会停在它上面。如果原因并不明显,就在按钮旁边用文字说明,或者让按钮保持可用,在点击时显示错误提示。
用 CSS 设置按钮样式
浏览器会用自己的字体、边框和背景来绘制按钮。设置几个属性就能把这些全部替换掉。记得保留可见的焦点样式:键盘用户要靠它知道自己在哪里。
每条规则的作用:
font: inherit让按钮使用页面的字体。没有它,按钮会使用浏览器自带的较小的表单字体(Chrome 和 Firefox 中为 13.33px)。cursor: pointer显示手形光标。按钮默认显示的是普通箭头。:hover、:active和:focus-visible分别设置鼠标悬停、按下和键盘聚焦时的样式。:focus-visible只在键盘聚焦时显示焦点环,鼠标点击后不会显示,所以你不必为了避免它而去掉outline。:disabled选中带有disabled属性的按钮。
在预览中按 Tab 键,可以看到琥珀色的焦点环在前两个按钮之间移动,禁用的那个会被跳过。(在 Mac 上,Safari 和 Firefox 只有在系统设置中开启键盘导航后,才会用 Tab 键聚焦到按钮;在 Safari 中,不开启也可以用 Option+Tab。)完整的状态列表请参阅 CSS hover。
带图标的按钮
因为 <button> 可以包含 HTML,所以图标可以放在里面,和文字并排。只有图标的按钮没有可供屏幕阅读器播报的文字,所以要给它加上 aria-label:
SVG 上的 aria-hidden="true" 把它排除在无障碍树之外,所以第一个按钮会被播报为“Add item,按钮”,第二个为“Delete,按钮”。
button 与 input type="submit"
<input type="submit"> 是编写提交按钮的旧方式。两者提交表单的方式完全相同,区别在于它们能包含什么内容。
<input type="submit" value="Send"> <!-- label comes from value, text only -->
<button type="submit">Send</button> <!-- label is the content, HTML allowed -->
<button> | <input type="submit"> | |
|---|---|---|
| 按钮文字 | 标签之间的内容 | value 属性 |
| 能否包含图标或标记 | 能 | 不能 |
| 结束标签 | 必须有 | 没有(空元素) |
| 默认类型 | submit | 始终是 submit |
请使用 <button>。保留 <input type="submit"> 的唯一理由,是已有的 CSS 或 JavaScript 会选中它。另外还有 <input type="button"> 和 <input type="reset">,对应另外两种类型,原理相同。
按钮还是链接?
按钮在当前页面上执行操作:提交、打开、切换、删除。链接则跳转到另一个 URL。如果点击后地址栏会改变,它就应该是 <a href>,设计需要的话可以设置成按钮的样式。这种做法,以及为什么链接里套按钮是不合法的,请参阅 HTML 按钮链接。
无障碍
- 使用真正的
<button>。它可以聚焦,支持 Enter 和空格键,并会被播报为按钮。在<div>上重新实现这些需要role、tabindex和按键处理函数,而且通常还是不完整。 - 每个按钮都需要一个名称:它的文字,或者只有图标时的
aria-label。 - 保留可见的焦点样式。只写
outline: none而不提供替代样式,会让键盘用户迷失方向。 - 让点击区域足够大。WCAG 2.2 要求至少 24 × 24 个 CSS 像素;像上面样式示例那样的内边距,能让高度达到大约 40 像素。
- 对于开关按钮,加上
aria-pressed="true"或"false",并在状态改变时更新它。
常见错误
- 表单里的按钮没有写
type。 它会提交表单。所有不用于提交的按钮都要写上type="button"。 - 把按钮包在链接里,例如
<a href="/x"><button>Go</button></a>。这是不合法的 HTML,在不同浏览器中的表现也不一样。只用一个元素:设置成按钮样式的链接。 - 把
<div onclick>当作按钮。 用键盘无法访问它。 - 去掉焦点轮廓,却没有添加
:focus-visible样式。 - 写
disabled="false",以为按钮是可用的。应该删掉这个属性。 - 忘了写
font: inherit,然后奇怪为什么按钮的字体和页面其他部分不一样。
常见问题
如何在 HTML 中创建按钮?
写 <button type="button">Click me</button>。标签之间的文字就是按钮上显示的文字。在 JavaScript 中添加 click 监听器让它执行操作,或者把它放进 <form> 并设置 type="submit" 来提交表单。
HTML 按钮的默认类型是什么?
submit。在表单里,没有 type 属性的 <button> 被点击时会提交这个表单,这就是表单里的普通按钮可能会刷新页面的原因。凡是用来运行 JavaScript 的按钮,都要写上 type="button"。
button 和 input type=submit 有什么区别?
两者都能提交表单。<button> 的标签之间可以包含 HTML(图标、粗体文字),而 <input type="submit"> 的文字来自 value 属性,只能是纯文本。现在的代码大多使用 <button>。
如何在 HTML 中禁用按钮?
加上 disabled 属性:<button disabled>Save</button>。禁用的按钮无法点击,也无法获得焦点,它的 name 和 value 也不会随表单发送。删掉这个属性(在 JavaScript 中写 btn.disabled = false)就能重新启用它。
如何让 HTML 按钮跳转到另一个页面?
使用设置成按钮样式的链接:<a href="/pricing" class="btn">See pricing</a>。<button> 用于当前页面上的操作。把按钮包在 <a> 里是不合法的 HTML。
为什么我的按钮会刷新页面?
它在 <form> 里面又没有 type,所以它是一个提交按钮,浏览器会发送表单并加载响应。给它加上 type="button",或者如果你用 JavaScript 处理表单,就在 submit 监听器里调用 event.preventDefault()。