Angular Material MatButton 完全指南:变体、外观、图标定位与无障碍实践
【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components
Angular Material 的按钮组件(MatButton)以原生<button>与<a>元素为基础,叠加 Material Design 视觉样式与无障碍能力,是组件库中使用频率最高的交互控件之一。本文基于本仓库中 button.md 的官方文档,结合 按钮源码实现 与 官方示例,系统讲解按钮的四种变体、五种外观(appearance)、图标投影规则、交互式禁用、进度指示器及无障碍最佳实践,帮助你写出语义正确、可访问、可复用的 Angular Material 按钮。
按钮的本质:增强原生元素,而非替换
Angular Material 按钮始终使用原生<button>与<a>元素,仅通过指令(directive)叠加 Material Design 样式。之所以坚持这一设计,是为了给用户提供最直接、最无障碍的使用体验,具体遵循以下选择原则:
- 执行动作(如保存、提交、删除)时,使用
<button>元素; - 跳转导航(如跳转到另一个视图或 URL)时,使用
<a>元素。
这一点在组件声明中体现得很直接:MatButton的选择器同时覆盖了按钮与锚点两种形态,见 button.ts:
selector: ` button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] `,值得注意的是,组件还保留了mat-button、mat-raised-button、mat-flat-button、mat-stroked-button等旧版选择器以向后兼容。在构造函数中,组件会通过_inferAppearance从这些静态属性推断外观(见 button.ts):mat-raised-button推断为elevated、mat-stroked-button推断为outlined、mat-flat-button推断为filled、mat-button推断为text。这意味着旧项目迁移到新版后,原有标记无需改动即可获得正确外观。
四种按钮变体(Variants)
Angular Material 提供四种按钮变体,每种都以属性(attribute)形式应用在元素上:
| 属性 | 说明 |
|---|---|
matButton | 矩形按钮,可包含文本与图标,是最通用的按钮形态 |
matIconButton | 更小的圆形按钮,用于容纳单个图标,不包含文本 |
matFab | 悬浮操作按钮(Floating Action Button),带高度与圆角,用于容纳图标;可通过extended属性扩展为矩形以容纳文字标签 |
matMiniFab | matFab的缩小版 |
从源码看,各变体有独立的组件类与样式文件:MatFabButton、MatMiniFabButton定义于 fab.ts,MatIconButton定义于 icon-button.ts,并统一由 MatButtonModule 导出。FAB 类组件在宿主元素上设置了mdc-fab相关类,并通过_isFab = true标记让涟漪(ripple)使用 FAB 专属样式。
快速上手示例
以下模板来自官方示例 button-overview-example.html,展示了三种基础形态:
<button matButton>Basic</button> <button matButton disabled>Disabled</button> <a matButton href="https://www.google.com/" target="_blank">Link</a> <button matFab aria-label="Example icon button with a delete icon"> <mat-icon>delete</mat-icon> </button> <button matMiniFab aria-label="Example icon button with a menu icon"> <mat-icon>menu</mat-icon> </button>五种外观(Appearance)
matButton支持通过属性值设置多种外观,例如matButton="outlined"。下表列出了全部外观及其适用场景:
| 外观 | 说明 |
|---|---|
text | 默认外观。文本按钮用于最低优先级的操作,尤其是在需要呈现多个选项时 |
filled | 高强调按钮,用于流程中的最终或解锁性操作,例如保存、确认 |
tonal | 中强调按钮,常用于流程中的最终或解锁性操作,但视觉强调度低于filled |
outlined | 中强调按钮,常用于需要引起注意但并非主操作的动作 |
elevated | 中强调按钮,常用于按钮需要与有图案的背景产生视觉分隔的场景 |
外观到 CSS 类的映射维护在APPEARANCE_CLASSES中(见 button.ts):
const APPEARANCE_CLASSES: Map<MatButtonAppearance, readonly string[]> = new Map([ ['text', ['mat-mdc-button']], ['filled', ['mdc-button--unelevated', 'mat-mdc-unelevated-button']], ['elevated', ['mdc-button--raised', 'mat-mdc-raised-button']], ['outlined', ['mdc-button--outlined', 'mat-mdc-outlined-button']], ['tonal', ['mat-tonal-button']], ]);设置外观时,组件会先移除旧外观对应的类,再添加新外观的类(见 setAppearance)。同时,appearance输入允许空字符串,这样matButton单独使用时无需写出="text",默认回落到text。
五种外观的完整模板
<button matButton>Basic text button</button> <button matButton="elevated">Elevated button</button> <button matButton="outlined">Outlined button</button> <button matButton="filled">Filled button</button> <button matButton="tonal">Tonal button</button>扩展 FAB 按钮(Extended FAB)
传统悬浮操作按钮(FAB)是圆形的,只能容纳一个图标。添加extended属性后,FAB 会扩展为带圆角的矩形,在图标之外还能容纳文字标签:
<button matFab extended> <mat-icon>home</mat-icon> Home </button>需要注意的是,只有全尺寸 FAB 支持extended属性,mini FAB 不支持。源码中extended是一个布尔转换输入(见 fab.ts),并通过宿主绑定添加mdc-fab--extended与mat-mdc-extended-fab类:
@Input({transform: booleanAttribute}) extended: boolean = false; host: { '[class.mdc-fab--extended]': 'extended', '[class.mat-mdc-extended-fab]': 'extended', }扩展 FAB 同样支持链接形态,可配合routerLink使用:
<a matFab extended routerLink="."> <mat-icon>favorite</mat-icon> Link </a>图标定位(Icon Positioning)
按钮可以在文本旁容纳图标。默认情况下,图标(mat-icon、.material-icons,或带matButtonIcon属性的元素)会被投影到按钮标签之前:
<button matButton> <mat-icon>favorite</mat-icon> Like </button>要把图标放到标签之后,只需在图标元素上加iconPositionEnd属性:
<button matButton> Send <mat-icon iconPositionEnd>send</mat-icon> </button>也可以同时使用两个位置:
<button matButton> <mat-icon>arrow_back</mat-icon> Navigate <mat-icon iconPositionEnd>arrow_forward</mat-icon> </button>如果你使用的是自定义图标元素(既不是mat-icon也不是.material-icons),需要添加matButtonIcon属性,按钮才能将其投影到正确的插槽:
<button matButton> <my-custom-icon matButtonIcon>custom</my-custom-icon> Action </button>这一行为在模板 button.html 中通过三段<ng-content>实现:前段投影不含iconPositionEnd的图标,中段是标签容器mdc-button__label,后段投影带iconPositionEnd的图标。模板还支持 Material Symbols(.material-symbols-outlined、.material-symbols-rounded、.material-symbols-sharp)系列的图标类。
交互式禁用按钮(Interactive Disabled Buttons)
原生禁用的<button>元素无法获得焦点,也不会派发任何事件。这在某些场景下会带来问题——例如应用无法告知用户按钮为何被禁用。disabledInteractive输入可以将按钮样式化为禁用状态,同时仍允许其获得焦点并派发事件,并会为辅助技术设置aria-disabled="true"。
<button matButton="elevated" disabled disabledInteractive matTooltip="This is a tooltip!"> Disabled button allowing interactivity </button>上面的示例来自 button-disabled-interactive-example.html,它借助 tooltip 向用户解释禁用原因——这正是原生禁用按钮无法做到的。对比之下,普通disabled按钮无法触发 tooltip。
重要警示:使用disabledInteractive可能导致原本会被阻止的操作不再被阻止,例如表单中的提交按钮。启用该输入时,应在组件中自行防护这类情况。
从源码看(见 button-base.ts),该行为通过多个宿主属性协同实现:
_getDisabledAttribute():仅在disabledInteractive || !disabled时为null,否则返回true,即交互式禁用不会写入原生disabled属性;_getAriaDisabled():对按钮元素,仅当disabled && disabledInteractive时返回true,从而为辅助技术标记禁用;_getTabIndex():锚点元素在disabled && !disabledInteractive时返回-1,交互式禁用时保持可聚焦。
同时,button-base.ts 中为锚点注册了点击拦截:当锚点被禁用时,阻止默认行为并停止事件冒泡。
全局配置 MAT_BUTTON_CONFIG
交互式禁用行为可以通过MAT_BUTTON_CONFIG注入令牌全局配置。该令牌在 button-base.ts 中定义:
export interface MatButtonConfig { /** Whether disabled buttons should be interactive. */ disabledInteractive?: boolean; /** Default palette color to apply to buttons. */ color?: ThemePalette; /** Default appearance for plain buttons (not icon buttons or FABs). */ defaultAppearance?: MatButtonAppearance; }在应用启动时全局提供:
import {MAT_BUTTON_CONFIG} from '@angular/material/button'; providers: [ { provide: MAT_BUTTON_CONFIG, useValue: { disabledInteractive: true, defaultAppearance: 'tonal', }, }, ]构造函数会读取该配置并作为默认值(见 button-base.ts),单个按钮上的显式输入始终可以覆盖全局默认。此外,MatButton的appearancesetter 也会回退到this._config?.defaultAppearance(见 button.ts),因此defaultAppearance可用于统一全站按钮外观。
带进度指示器的按钮(Buttons with Progress Indicators)
按钮可以投影一个带progressIndicator属性的元素。当showProgress输入为true时,该元素会覆盖显示在按钮内容之上,同时按钮原有内容变为不可见。
<button matButton="outlined" [showProgress]="showProgress()" (click)="toggleShowProgress()"> Click to toggle progress <mat-progress-spinner progressIndicator mode="indeterminate" diameter="20" aria-label="Loading" tabindex="" /> </button>上面的代码来自官方示例 button-progress-indicator-example.html。同一示例还展示了自定义进度指示器的写法——不依赖MatProgressSpinner,用带role="progressbar"的普通元素即可:
<button matButton="outlined" [showProgress]="showProgress()" (click)="toggleShowProgress()"> Click to toggle progress <div progressIndicator role="progressbar" aria-valuemin="0" aria-valuemax="100"> Loading... </div> </button>模板实现上(见 button.html),当showProgress()为真时渲染mat-mdc-button-progress-indicator-container容器并投影[progressIndicator]元素;宿主上同时添加mat-mdc-button-progress-indicator-shown类(见 button-base.ts)来驱动内容隐藏样式。
无障碍要求
投影的进度指示器元素不得可交互。使用MatProgressSpinner作为指示器时,应设置tabindex="",将其从 Tab 键顺序中移除(如上例所示)。
无障碍(Accessibility)
Angular Material 默认使用原生<button>与<a>元素来保证无障碍体验:
- 在当前页面执行动作的交互,使用
<button>; - 导航到另一个 URL的交互,使用
<a>。
MatButton同样适用按钮与锚点的所有标准无障碍最佳实践。
大写文本(Capitalization)
按钮文本本身使用全大写会导致屏幕阅读器逐字符朗读,也会引发本地化问题。因此官方不建议修改按钮文本的默认大小写。
禁用锚点(Disabling anchors)
MatAnchor在原生<a>元素能力之外还支持禁用锚点。禁用时,组件会设置aria-disabled="true"和tabindex="-1",并在点击时拦截默认跳转(见 button-base.ts)。由于禁用锚点的辅助技术支持情况可能因读屏软件而异,官方建议始终在应用中测试禁用锚点的行为。
纯图标按钮(Buttons with icons)
仅包含图标的按钮或链接(如matFab、matMiniFab、matIconButton)应通过aria-label或aria-labelledby提供有意义的标签,例如官方示例中的aria-label="Example icon button with a delete icon"。此外,为保证充分可访问,图标的最小触控目标应为 48x48 像素,尤其在移动设备与小屏上要确保易于点击——模板末尾的mat-mdc-button-touch-target元素(见 button.html)正是用于扩展触控区域。
切换按钮(Toggle buttons)
需要带状态的切换按钮(toggle button)时,请参阅MatButtonToggle组件的文档(仓库内对应实现位于 src/material/button-toggle),MatButton本身不提供状态保持能力。
小结与延伸阅读
总结本指南的关键要点:
- 语义优先:动作用
<button>,导航用<a>,组件只增强样式与交互,不替换原生语义; - 四种变体:
matButton、matIconButton、matFab、matMiniFab,按内容形态选用; - 五种外观:
text、filled、tonal、outlined、elevated,按强调等级与场景选用,旧版mat-*-button属性可自动推断外观; - 图标灵活布局:默认前置,
iconPositionEnd后置,自定义图标用matButtonIcon标记; - 禁用态精细化:
disabledInteractive配合MAT_BUTTON_CONFIG实现可聚焦、可解释的禁用态; - 进度反馈:
progressIndicator+showProgress让按钮承载加载状态; - 无障碍是默认项:遵循大写、禁用锚点、图标标签、48px 触控目标等实践。
如需进一步深入,可以阅读本仓库中的相关源码与测试:按钮核心实现见 button.ts、button-base.ts、fab.ts 与 icon-button.ts,样式体系见 _m3-button.scss、_m2-button.scss 与 _button-theme.scss,完整行为测试见 button.spec.ts,可直接运行的示例见 button-overview。
【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考