用法

Align
2023-09-19
17 min

用法(Usage)

Learn the basics of working with MUI System and its utilities.

了解MS及其工具的基本用法。

为什么使用MS?(Why use MUI System?)

MUI System's sx prop lets you avoid writing unnecessary styled-component code, and instead define styles directly within the component itself. This is especially useful for one-off components with custom designs.

MUI 系统的 sx 属性可让您避免编写不必要的styled-component代码,而是直接在组件本身内定义样式。这对于具有定制设计的一次性组件特别有用

The following code samples illustrate the difference between styled-components and sx:

下面这段代码能体现二者的区别:

  1. Using the styled-components API:
const StatWrapper = styled('div')(
  ({ theme }) => `
  background-color: ${theme.palette.background.paper};
  box-shadow: ${theme.shadows[1]};
  border-radius: ${theme.shape.borderRadius}px;
  padding: ${theme.spacing(2)};
  min-width: 300px;
`,
);

const StatHeader = styled('div')(
  ({ theme }) => `
  color: ${theme.palette.text.secondary};
`,
);

const StyledTrend = styled(TrendingUpIcon)(
  ({ theme }) => `
  color: ${theme.palette.success.dark};
  font-size: 16px;
  vertical-alignment: sub;
`,
);

const StatValue = styled('div')(
  ({ theme }) => `
  color: ${theme.palette.text.primary};
  font-size: 34px;
  font-weight: ${theme.typography.fontWeightMedium};
`,
);

const StatDiff = styled('div')(
  ({ theme }) => `
  color: ${theme.palette.success.dark};
  display: inline;
  font-weight: ${theme.typography.fontWeightMedium};
  margin-left: ${theme.spacing(0.5)};
  margin-right: ${theme.spacing(0.5)};
`,
);

const StatPrevious = styled('div')(
  ({ theme }) => `
  color: ${theme.palette.text.secondary};
  display: inline;
  font-size: 12px;
`,
);

return (
  <StatWrapper>
    <StatHeader>Sessions</StatHeader>
    <StatValue>98.3 K</StatValue>
    <StyledTrend />
    <StatDiff>18.77%</StatDiff>
    <StatPrevious>vs last week</StatPrevious>
  </StatWrapper>
);

  1. Using MUI System:
<Box
  sx={{
    bgcolor: 'background.paper',
    boxShadow: 1,
    borderRadius: 1,
    p: 2,
    minWidth: 300,
  }}
>
  <Box sx={{ color: 'text.secondary' }}>Sessions</Box>
  <Box sx={{ color: 'text.primary', fontSize: 34, fontWeight: 'medium' }}>
    98.3 K
  </Box>
  <Box
    component={TrendingUpIcon}
    sx={{ color: 'success.dark', fontSize: 16, verticalAlign: 'sub' }}
  />
  <Box
    sx={{
      color: 'success.dark',
      display: 'inline',
      fontWeight: 'medium',
      mx: 0.5,
    }}
  >
    18.77%
  </Box>
  <Box sx={{ color: 'text.secondary', display: 'inline', fontSize: 12 }}>
    vs. last week
  </Box>
</Box>

The sx prop

MUI System's core utility is the sx prop, which gives you a quick and efficient way to apply the correct design tokens directly to a React element. This prop provides a superset of CSS (i.e. it contains all CSS properties and selectors in addition to custom ones) that maps values directly from the theme, depending on the CSS property used. It also simplifies the process of defining responsive values by referring to the breakpoints defined in the theme. Visit the sx prop page for complete details.

MUI 系统的核心功能是 sx prop,它为您提供了一种快速有效的方法,将样式应用于 React 元素。该属性提供了 CSS 的超集(即,除了可以使用自定义属性之外,它还可以写所有 CSS 属性和选择器),同时其内部可以根据所使用的 CSS 属性,直接从定义的主题中映射对应的值.也可以在主题中定义响应式布局所需要的断点。

响应式示例(Responsive demo)

import * as React from 'react';
import Box from '@mui/material/Box';
import { alpha } from '@mui/material/styles';
import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';

export default function Demo() {
  return (
    <Box
      sx={{
        display: 'flex',
        flexDirection: { xs: 'column', md: 'row' },
        alignItems: 'center',
        bgcolor: 'background.paper',
        overflow: 'hidden',
        borderRadius: '12px',
        boxShadow: 1,
        fontWeight: 'bold',
      }}
    >
      <Box
        component="img"
        sx={{
          height: 233,
          width: 350,
          maxHeight: { xs: 233, md: 167 },
          maxWidth: { xs: 350, md: 250 },
        }}
        alt="The house from the offer."
        src="https://images.unsplash.com/photo-1512917774080-9991f1c4c750?auto=format&w=350&dpr=2"
      />
      <Box
        sx={{
          display: 'flex',
          flexDirection: 'column',
          alignItems: { xs: 'center', md: 'flex-start' },
          m: 3,
          minWidth: { md: 350 },
        }}
      >
        <Box component="span" sx={{ fontSize: 16, mt: 1 }}>
          123 Main St, Phoenix AZ
        </Box>
        <Box component="span" sx={{ color: 'primary.main', fontSize: 22 }}>
          $280,000 — $310,000
        </Box>
        <Box
          sx={{
            mt: 1.5,
            p: 0.5,
            backgroundColor: (theme) => alpha(theme.palette.primary.main, 0.1),
            borderRadius: '5px',
            color: 'primary.main',
            fontWeight: 'medium',
            display: 'flex',
            fontSize: 12,
            alignItems: 'center',
            '& svg': {
              fontSize: 21,
              mr: 0.5,
            },
          }}
        >
          <ErrorOutlineIcon />
          CONFIDENCE SCORE 85%
        </Box>
      </Box>
    </Box>
  );
}

什么时候使用MS(When to use MUI System)

The sx prop is best suited for applying one-off styles to custom components. This is in contrast to the styled-components API, which is ideal for building components that need to support a wide variety of contexts. These components are used in many different parts of the application and support different combinations of props.

sxprop最适用于对组件设置一些一次性样式时,这些组件往往是无需复用不需要单独封装成一个组件。这与 styled-components API 形成鲜明对比,后者非常适合构建需要支持各种上下文的组件。这些组件需要被复用,并且可能需要配置一些自定义的props。

性能权衡(Performance tradeoffs)

MUI System relies on CSS-in-JS. It works with both Emotion and styled-components.

MS依赖于CSS-in-Js。

优点(Pros)

  • The sx prop uses a superset of CSS, so the syntax will be immediately familiar to you if you know CSS already. It also offers (optional) shorthand definitions that can save you time if you put in a little work to learn them upfront. These are documented in the Style utilities section of the primary navigation to the left.

    sxprop的配置主要是css的超集,所以如果你会使用css那么基本没什么上手难度。同时在sx中编写css属性时也可以使用一些属性的简写,如果你愿意花时间学习一下某些属性的简写那么同样可以节省开发时间。前往Style utilities页面可以了解具体使用方法。

  • The System auto-purges, so that only the CSS that's used on the page is sent to the client. The initial bundle size cost is fixed—it doesn't get any larger as you add more CSS properties. You pay the cost of @emotion/react and @mui/system. The total size is ~15 kB gzipped. But if you are already using an MUI Core component library like Material UI, then it comes with no extra overhead.

缺点(Cons)

Runtime performance takes a hit

运行时的性能会受到一些影响。见下表格对比:

案例(Benchmark case)代码( Code snippet)消耗时间(Time normalized)
渲染1000个原生元素(a. Render 1,000 primitives)<div className="…">100ms
渲染1000个react组件(a. Render 1,000 components)<Div>112ms
渲染1000个styled components组件(a. Render 1,000 styled components)<StyledDiv>181ms
渲染1000个MS组件(a. Render 1,000 Box)< <Box sx={…}>296ms

Head to the benchmark folder for a reproduction of these metrics

上述案例可前往benchmark folder查看。

We believe that for most use cases it's fast enough, but there are simple workarounds when performance becomes critical. For instance, when rendering a list with many items, you can use a CSS child selector to have a single "style injection" point (using d. for the wrapper and a. for each item).

我们相信对于大多数情况来说这已经足够快了,但是当性能变得至关重要时我们也有一些简单的方法。比如当你渲染拥有许多Item的List组件时,在List组件上通过css选择器的方式来对Item组件设置样式,而不是对每个Item都使用MS预制组件并通过sx prop来设置样式。

API权衡(API tradeoff)

MUI System's unifying sx prop helps to maintain the separation of concerns between CSS utilities and component business logic.

MS的统一的sx 属性有助于保持 CSS和组件业务逻辑之间的关注点分离。

For instance, a color prop on a button impacts multiple states (hover, focus, etc.), and is distinct from the CSS color property.

例如,按钮上的颜色属性会影响多个状态(悬停、焦点等),这些都是与 CSS样式属性不同的业务逻辑部分。

Only the Box, Stack, Typography, and Grid components accept the system properties as props for this reason. These components are designed to solve CSS problems—they are CSS component utilities.

因此,只有 Box、Stack、Typography 和 Grid 组件接受系统属性作为 props。这些组件旨在解决 CSS 问题——它们是 CSS 组件实用程序

在那里使用MS(Where to use MUI System)

The sx prop can be used in four different locations:

sx属性可以被使用在四种地方:

核心组件(Core components)

All core MUI components support the sx prop.

所有的MUI核心组件都支持sx属性。

Box

Box is a lightweight component that gives access to the sx prop, and can be used as a utility component, and as a wrapper for other components. It renders a <div> element by default.

Box是一个支持sx的轻量组件,可以当作一个普通组件使用或者所谓其他组件的包裹器,该组件默认渲染一个原生div元素。

定制组件(Custom components)

In addition to MUI components, you can add the sx prop to your custom components too, by using the styled utility from @mui/material/styles.

除了MUI提供的组件,你可以使用@mui/material/styles提供的styled方法把自己的组件转化为支持sx属性的定制组件。

任何带有babel插件的元素(Any element with the babel plugin)

TODO #23220.

如何使用MS(How to use MUI System)

定义主题(Design tokens in the theme)

Visit the System properties page to learn how the different CSS (and custom) properties are mapped to the theme keys.

前往系统属性页面学习主题中属性和css属性的映射关系,这样你就可以在sx中使用主题中定义的样式。

简写(Shorthands)

There are many shorthands available for various CSS properties. These are documented on their respective Style utilities pages. Here is an example of a few:

以下示例提供了一些在sx中一些css属性的简写:

<Box
  sx={{
    boxShadow: 1, // theme.shadows[1]
    color: 'primary.main', // theme.palette.primary.main
    m: 1, // margin: theme.spacing(1)
    p: {
      xs: 1, // [theme.breakpoints.up('xs')]: { padding: theme.spacing(1) }
    },
    zIndex: 'tooltip', // theme.zIndex.tooltip
  }}
>

These shorthands are optional—they're great for saving time, but not necessary to use

简写能节省时间,当然也是可选的。

css超集(Superset of CSS)

The sx prop supports CSS syntax including child and pseudo-selectors, media queries, raw CSS values, and more. Here are a few examples of how you can implement these CSS features:

sx属性支持的语法包括子选择器和伪选择器、媒体查询、原始 CSS 值等。以下是如何实现这些 CSS 功能的一些示例:

  • 使用伪类选择器(Using pseudo-selectors):
<Box
  sx={{
    // some styles
    ":hover": {
      boxShadow: 6,
    },
  }}
>

  • 使用媒体查询(Using media queries):
<Box
  sx={{
    // some styles
    '@media print': {
      width: 300,
    },
  }}
>

  • 嵌套选择(Using nested selector):
<Box
  sx={{
    // some styles
    '& .ChildSelector': {
      bgcolor: 'primary.main',
    },
  }}
>

响应式属性(Responsive values)

The sx prop simplifies the process of defining and implementing responsive breakpoints. You can define a set of breakpoints in two different ways: as an object, or as an array.

sx 属性简化了定义和实现响应式断点的过程。您可以通过两种不同的方式定义一组断点:作为对象或作为数组。

对象的形式(Breakpoints as an object):

The first option for breakpoints is to define them as an object, using the breakpoint values as keys. Note that each property for a given breakpoint also applies to all larger breakpoints in the set. For example, width: { lg: 100 } is equivalent to theme.breakpoints.up('lg').

通过对象定义响应式断电的方式是将断点值作为对象的key。

注意

对象中定义断点的属性值在页面大于该断点时也会生效,例如设置width: {lg:500},当页面尺寸大于lg时width也是500(意思就是大于等于),等同于在主题中定义的断点theme.breakpoints.up('lg')

下面的示例展示了如何用对象定义一组断点:

<Box
  sx={{
    width: {
      xs: 100, // theme.breakpoints.up('xs')
      sm: 200, // theme.breakpoints.up('sm')
      md: 300, // theme.breakpoints.up('md')
      lg: 400, // theme.breakpoints.up('lg')
      xl: 500, // theme.breakpoints.up('xl')
    },
  }}
>
  This box has a responsive width.
</Box>

数组方式定义断点(Breakpoints as an array):

The second option is to define your breakpoints as an array, from smallest to largest. Here's what that looks like:

通过数组定义对象遵循从小到大的顺序,看起来就像下面这样:

<Box sx={{ width: [100, 200, 300] }}>This box has a responsive width.</Box>

This option should only be considered when the theme has a limited number of breakpoints, e.g. 3. We recommend using the object API instead if you need to define more than a few breakpoints.

这种写法只有主题限制了断点数量的时候(例如3个断点)才会考虑使用,一般情况下我们任然推荐使用对象的方式定义断点。

You can skip breakpoints with the null value:

通过设置断点值为null可以跳过不想设置的断点:

<Box sx={{ width: [null, null, 300] }}>This box has a responsive width.</Box>

自定义断点(Custom breakpoints)

You can also specify your own custom breakpoints, and use them as keys when defining the breakpoints object. Here is an example of how to do that:

也可以自定义自己的断点,自定义的断点支持在对象中使用。下面是一个示例:

import * as React from 'react';
import Box from '@mui/material/Box';
import { createTheme, ThemeProvider } from '@mui/material/styles';

const theme = createTheme({
  breakpoints: {
    values: {
      mobile: 0,
      tablet: 640,
      laptop: 1024,
      desktop: 1280,
    },
  },
});

export default function CustomBreakpoints() {
  return (
    <ThemeProvider theme={theme}>
      <Box
        sx={{
          width: {
            mobile: 100,
            laptop: 300,
          },
        }}
      >
        This box has a responsive width
      </Box>
    </ThemeProvider>
  );
}

If you are using TypeScript, you will also need to use module augmentation for the theme to accept the above values.

如果你在使用typescript,可以使用module augmentation来申明自定义内容的类型,以此来获得ts的语法支持。

如下示例我们自定义了三个断点:

declare module '@mui/material/styles' {
  interface BreakpointOverrides {
    xs: false; // removes the `xs` breakpoint
    sm: false;
    md: false;
    lg: false;
    xl: false;
    tablet: true; // adds the `tablet` breakpoint
    laptop: true;
    desktop: true;
  }
}

主题getter(Theme getter)

If you wish to use the theme for a CSS property that is not supported natively by the system, then you can use a function as the value, in which you can access the theme object. The following demo shows how this works:

如果你想把某个主题样式应用在本身不支持该主题样式的css属性上,可以通过传递函数的方式来实现:

<Box
  sx={{
    p: 1,
    border: 1,
    borderColor: (theme: Theme) => theme.palette.primary.main,// success 通过getter的方式设置成功
    //borderColor: primary.main, // fail palette下的属性无法映射到边框色上
    //color: primary.main // success 在sx中,palette下的属性可以映射到color上
  }}
>
  Border color with theme value.
</Box>

怎么理解这句话,在主题中预定义的样式在sx中使用时与css样式是有固定的映射关系的,例如color或者backgrondColor可以通过primary.main的方式映射成功,但是像上述代码中为borderColor映射primary.main就会失败,这时就可以通过getter的方式实现给边框设置上primary.main的颜色。