Icons 图标
我们提供了一些建议和指导,能够帮助您在 Material-UI 中使用图标。
Material-UI 通过以下三种方式来支持图标的使用:
- 您可以将标准的 Material Design 图标 导出为 React 组件 (SVG icons)。
- 或者可以将自定义的 SVG 图标通过 SvgIcon 组件来包装成一个 React 组件。
- 或者可以将自定义的 font 图标通过 Icon 组件来包装成一个 React 组件。
Material Icons
Google 已经创建了 1300 多个官方的 Material icons,每个图标都有5种不同的“主题”(见下文)。 对于每个 SVG 图标,我们从 @material-ui/icons
包中导出相应的 React 组件。 您可以 搜索完整的图标列表。
安装
请在您的项目目录中用以下方式安装依赖包:
// 使用 npm 安装
npm install @material-ui/icons@next
// 使用 yarn 安装
yarn add @material-ui/icons@next
这些组件使用 Material-UI 的 SvgIcon
组件来渲染每个图标的 SVG 路径,因此对 @materialui/core
具有对等依赖性。
如果你的项目中还没有使用 Material-UI,那么你可以用以下方法添加它:
// 用 npm 安装
npm install @material-ui/core@next
// 用 yarn 安装
yarn add @material-ui/core@next
使用
有两种导入图标的方法:
方法 1:
import AccessAlarmIcon from '@material-ui/icons/AccessAlarm'; import ThreeDRotation from '@material-ui/icons/ThreeDRotation';
方法 2:
import { AccessAlarm, ThreeDRotation } from '@material-ui/icons';
对于捆绑包的大小来说,最安全的是方案 1,但有些开发者更喜欢方案 2。 在使用第二个方法之前,请确保您遵循 最小化捆绑包大小指南。
每个 Material icon 都有一个“主题”:Filled(默认), Outlined, Rounded, Two-tone, 和 Sharp。 要导入非默认主题的图标组件,请在图标名称后附加主题名称。 例如,@material-ui/icons/Delete
图标可以:
- 导出为 Filled 主题(默认值):
@material-ui/icons/Delete
, - 导出为 Outlined 主题:
@material-ui/icons/DeleteOutlined
, - 导出为 Rounded 主题:
@material-ui/icons/DeleteRounded
, - 导出为 Twotone 主题:
@material-ui/icons/DeleteTwoTone
, - 导出为 Sharp 主题:
@material-ui/icons/DeleteSharp
,
友情提示:Material Design 在命名图标的时候遵循了 “snake_case” 变量命名法(例如,
delete_forever
和add_a_photo
),而@material-ui/icons
则使用 “PascalCase” 来命名导出的相应图标(例如,DeleteForever
以及AddAPhoto
)。 并且此命名规则有三个特例:3d_rotation
导出为ThreeDRotation
,4k
导出为FourK
,以及360
导出为ThreeSixty
。
Filled
Outlined
Rounded
Two Tone
Sharp
Edge-cases
测试
出于测试目的,每个从 @material-ui/icons
暴露的图标都有一个 data-testid
属性,这其中包含了图标的名称。 就像这样:
import DeleteIcon from '@material-ui/icons/Delete';
一旦挂载后,它就具有以下属性:
<svg data-testid="DeleteIcon"></svg>
SvgIcon(Svg 图标)
如果你需要使用自定义的 SVG 图标(而它在 Material Icons 中不存在),那么你可以使用 SvgIcon
封装。 此组件是原生 <svg>
元素的拓展版:
- 它具备一些内置的无障碍设计。
- SVG 元素应该在 24x24px 的视口中进行缩放,这样所渲染的图标就可以按原样使用,或者作为其他使用图标的 Material-UI 组件的子元素。 (使用
viewBox
属性,您可以随意自定义)。 - 默认情况下,此组件会继承当前的颜色。 当然,通过
color
这个属性,你可以让图标使用主题里的颜色。
function HomeIcon(props) {
return (
<SvgIcon {...props}>
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
</SvgIcon>
);
}
Color 颜色
<HomeIcon />
<HomeIcon color="primary" />
<HomeIcon color="secondary" />
<HomeIcon color="action" />
<HomeIcon color="disabled" />
<HomeIcon style={{ color: green[500] }} />
<HomeIcon fontSize="small" />
<HomeIcon />
<HomeIcon fontSize="large" />
<HomeIcon style={{ fontSize: 40 }} />
组件属性
即使图标以 .svg
的格式保存,你依然可以使用 SvgIcon
来包装它。 通过 svgr 提供的加载器,您可以导入 SVG 文件,并以 React 组件形式使用。 譬如,使用 webpack :
// webpack.config.js
{
test: /\.svg$/,
use: ['@svgr/webpack'],
}
// ---
import StarIcon from './star.svg';
<SvgIcon component={StarIcon} viewBox="0 0 600 476.6" />
通过 “url-loader” 或 “file-loader” 加载也是可行的。 这是 Create React App 使用的方法。
// webpack.config.js
{
test: /\.svg$/,
use: ['@svgr/webpack', 'url-loader'],
}
// ---
import { ReactComponent as StarIcon } from './star.svg';
<SvgIcon component={StarIcon} viewBox="0 0 600 476.6" />
createSvgIcon
createSvgIcon
工具集是用于创建 Material icons 的。 它可以用来包装一个带有 SvgIcon 组件的 SVG 路径。
const HomeIcon = createSvgIcon(
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />,
'Home',
);
<HomeIcon />
<HomeIcon color="primary" />
Font Awesome
如果你发现在使用来自 @fortawesome/react-fontawesome
的 FontAwesomeIcon 时存在布局问题,你可以尝试将 Font Awesome SVG 数据直接传递给 SvgIcon。
如下是一个同时将 Font Awesome<
和 Icon
一起的示例:
<IconButton aria-label="Example">
<FontAwesomeIcon icon={faEllipsisV} />
</IconButton>
<IconButton aria-label="Example">
<FontAwesomeSvgIcon icon={faEllipsisV} />
</IconButton>
<Button variant="contained" startIcon={<FontAwesomeIcon icon={faInfo} />}>
Example
</Button>
<Button variant="contained" startIcon={<FontAwesomeSvgIcon icon={faInfo} />}>
Example
</Button>
FontAwesomeIcon 的 fullWidth
属性也可以用来应用近似正确的尺寸,但这样的效果并不完美。
其他图标库
MDI
materialdesignicons.com 提供了 2000 多个图标。 对于你想要使用的图标,可以复制它们所提供的 SVG path
,并将其作为 SvgIcon
组件的子组件,或者也可以使用 createSvgIcon()
来应用它。
友情提示:mdi-material-ui 已经将每个 SVG 图标用 SvgIcon
组件包装起来,你可以高枕无忧了。
Icon (Font icons)
对于支持连字的任何图标字体,Icon
组件能够将其显示为一个图标。 先决条件,你必须要在项目中包含 Material icon font。 若想要使用图标,您只需把图标名(字体连字)和 Icon
组件包装到一起,例如:
import Icon from '@material-ui/core/Icon';
<Icon>star</Icon>
默认情况下,一个图标会继承使用当前的文本颜色。 您也可以选择使用以下任何一个主题颜色属性来设置图标的颜色:primary
,secondary
,action
,error
以及 disabled
。
Font Material 图标
Icon
默认情况下将为 Material Icons 字体(填充变体)设置正确的基类名称。 所以你需要加载字体即可,例如使用 Google Web Fonts:
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<Icon>add_circle</Icon>
<Icon color="primary">add_circle</Icon>
<Icon style={{ color: green[500] }}>add_circle</Icon>
<Icon fontSize="small">add_circle</Icon>
<Icon style={{ fontSize: 30 }}>add_circle</Icon>
自定义字体
对于其他字体,你可以使用 baseClassName
属性来自定义基线类名。 例如,你可以使用 Material Design 显示 two-tone 图标:
import Icon from '@material-ui/core/Icon';
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Material+Icons+Two+Tone"
// 引入 MD 的 two tones 变体 ^^^^^^^^
/>
<Icon baseClassName="material-icons-two-tone">add_circle</Icon>
全局类名
为了每个组件的使用都去修改 baseClassName
属性是很繁琐的。 你可以在全局范围内使用主题来改变默认属性。
const theme = createMuiTheme({
components: {
MuiIcon: {
defaultProps: {
// 替换 `material-icons` 的默认值。
baseClassName: 'material-icons-two-tone',
},
},
},
});
然后,你就可以直接使用 two-tone 图标了:
<Icon>add_circle</Icon>
Font Awesome
Font Awesome 可以和 Icon
组件一起使用,如下所示:
<Icon baseClassName="fas" className="fa-plus-circle" />
<Icon baseClassName="fas" className="fa-plus-circle" color="primary" />
<Icon
baseClassName="fas"
className="fa-plus-circle"
style={{ color: green[500] }}
/>
<Icon baseClassName="fas" className="fa-plus-circle" fontSize="small" />
<Icon
baseClassName="fas"
className="fa-plus-circle"
style={{ fontSize: 30 }}
/>
需要注意的是,Font Awesome icons 的设计并不像 Material Design icons 那样(你可以对比之前的两个 demo)。 fa icons 经过裁剪,以利用所有可用空间。 你可以通过全局覆盖的方式来适配它:
const theme = createMuiTheme({
components: {
MuiIcon: {
styleOverrides: {
root: {
// 匹配 24px = 3 * 2 + 1.125 * 16
boxSizing: 'content-box',
padding: 3,
fontSize: '1.125rem',
},
},
},
},
});
<ThemeProvider theme={theme}>
<Chip icon={<MdPhone />} label="Call me" />
<Chip icon={<Icon className="fas fa-phone-alt" />} label="Call me" />
</ThemeProvider>
Font vs SVG。 使用哪个更好呢?
这两种方法都能很好地工作,但是其中有一些微妙的差异,特别是在性能和渲染质量方面。 在条件允许的情况下,首选使用 SVG 的方式,因为它允许代码分割,能支持更多的图标,并且渲染得更快更好。
更多详情,请查阅 为什么 GitHub 将 font icons 迁移到 SVG icons。
无障碍设计
图标可以传达各种有意义的信息,所以确保它们的无障碍设计是很重要的。 您可能会注意到这两个用例:
- 装饰性图标 仅用于增强视觉或强调品牌。 即使将它们从页面中移除,用户仍然可以理解并能够使用整个界面。
- 语义图标 是用来传达其中意义的,而不只是单纯地起装饰作用。 这包含了没有文字辅助说明的图标,这些图标一般被用作在交互式控件中 — 按钮、表单元素、切换按钮等。
装饰性图标
如果你的图标只是作为纯粹的装饰,那么你已经大功告成啦! 而添加 aria-hidden=true
属性可以让你的图标变成正确的且可访问的(隐形的)。
语义图标
语义化的 SVG icons
你应该在 titleAccess
属性中增加一个有意义的值。 role="img"
属性和 <title>
元素将会被添加,以便你的图标可以正确适配无障碍设计。
对于可聚焦的交互式元素,例如当与图标按钮一起使用时,你可以使用 aria-label
属性:
import IconButton from '@material-ui/core/IconButton';
import SvgIcon from '@material-ui/core/SvgIcon';
// ...
<IconButton aria-label="delete">
<SvgIcon>
<path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z" />
</SvgIcon>
</IconButton>;
语义化的 font icons
你需要提供一个只有辅助技术才能看到的文本替代方案:
import Icon from '@material-ui/core/Icon';
import { visuallyHidden } from '@material-ui/system';
import { makeStyles } from '@material-ui/core/styles';
const classes = makeStyles({ visuallyHidden })();
// ...
<Icon>add_circle</Icon>
<span className={classes.visuallyHidden}>创建一个用户</span>