Material-UI 样式系统 #
概述 #
MUI v5 使用 Emotion 作为默认的样式引擎,提供了多种灵活的样式方案。
text
样式方案
│
├── sx prop 内联样式(最常用)
├── styled API CSS-in-JS 组件
├── styleOverrides 主题覆盖
├── className 传统 CSS 类
└── global CSS 全局样式
sx Prop #
sx prop 是 MUI 最强大的样式工具,允许直接在组件上编写 CSS。
基础用法 #
jsx
import { Box } from '@mui/material';
<Box
sx={{
width: 100,
height: 100,
bgcolor: 'primary.main',
color: 'white',
p: 2,
m: 1,
}}
>
sx 样式
</Box>
主题值 #
jsx
<Box sx={{ color: 'primary.main' }}>主色调文字</Box>
<Box sx={{ color: 'secondary.light' }}>次色调浅色</Box>
<Box sx={{ bgcolor: 'error.dark' }}>错误背景</Box>
<Box sx={{ p: 2 }}>padding: 16px</Box>
<Box sx={{ m: 3 }}>margin: 24px</Box>
<Box sx={{ borderRadius: 1 }}>borderRadius: 8px</Box>
响应式值 #
jsx
<Box
sx={{
width: {
xs: '100%',
sm: '80%',
md: '60%',
lg: '50%',
},
p: {
xs: 1,
sm: 2,
md: 3,
},
fontSize: {
xs: '0.875rem',
md: '1rem',
lg: '1.25rem',
},
}}
>
响应式样式
</Box>
伪类和伪元素 #
jsx
<Box
sx={{
'&:hover': {
bgcolor: 'primary.dark',
transform: 'translateY(-2px)',
},
'&:active': {
transform: 'translateY(0)',
},
'&:focus': {
outline: '2px solid primary.main',
},
'&::before': {
content: '"→"',
mr: 1,
},
}}
>
带伪类的 Box
</Box>
嵌套选择器 #
jsx
<Box
sx={{
'& .child': {
p: 2,
bgcolor: 'grey.100',
},
'& .child:hover': {
bgcolor: 'grey.200',
},
'& .active': {
bgcolor: 'primary.light',
},
}}
>
<div className="child">子元素 1</div>
<div className="child active">子元素 2</div>
</Box>
条件样式 #
jsx
function ConditionalBox({ isActive, isDisabled }) {
return (
<Box
sx={{
bgcolor: isActive ? 'primary.main' : 'grey.200',
opacity: isDisabled ? 0.5 : 1,
cursor: isDisabled ? 'not-allowed' : 'pointer',
}}
>
条件样式
</Box>
);
}
数组语法 #
jsx
<Box
sx={[
{ bgcolor: 'primary.main' },
isActive && { bgcolor: 'secondary.main' },
isLarge && { p: 4 },
]}
>
数组样式
</Box>
函数语法 #
jsx
<Box sx={(theme) => ({
bgcolor: theme.palette.primary.main,
p: theme.spacing(2),
borderRadius: theme.shape.borderRadius,
})}>
函数样式
</Box>
styled API #
styled API 用于创建可复用的样式组件。
基础用法 #
jsx
import { styled } from '@mui/material/styles';
const StyledBox = styled('div')({
padding: 16,
backgroundColor: '#f5f5f5',
borderRadius: 8,
});
<StyledBox>样式组件</StyledBox>
使用主题 #
jsx
const StyledButton = styled('button')(({ theme }) => ({
padding: theme.spacing(1, 2),
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
borderRadius: theme.shape.borderRadius,
border: 'none',
cursor: 'pointer',
'&:hover': {
backgroundColor: theme.palette.primary.dark,
},
}));
扩展 MUI 组件 #
jsx
import { Button } from '@mui/material';
const CustomButton = styled(Button)(({ theme }) => ({
borderRadius: 20,
textTransform: 'none',
fontWeight: 600,
padding: theme.spacing(1.5, 3),
}));
动态样式 #
jsx
const DynamicBox = styled('div')(({ theme, $bgColor, $size }) => ({
backgroundColor: $bgColor || theme.palette.primary.main,
padding: $size === 'large' ? theme.spacing(4) : theme.spacing(2),
borderRadius: theme.shape.borderRadius,
}));
<DynamicBox $bgColor="secondary.main" $size="large">
动态样式
</DynamicBox>
嵌套选择器 #
jsx
const Card = styled('div')(({ theme }) => ({
padding: theme.spacing(2),
backgroundColor: theme.palette.background.paper,
borderRadius: theme.shape.borderRadius,
'& .title': {
fontSize: '1.25rem',
fontWeight: 600,
marginBottom: theme.spacing(1),
},
'& .content': {
color: theme.palette.text.secondary,
},
'&:hover': {
boxShadow: theme.shadows[4],
},
}));
组合样式 #
jsx
const baseStyles = ({ theme }) => ({
padding: theme.spacing(2),
borderRadius: theme.shape.borderRadius,
});
const primaryStyles = ({ theme }) => ({
...baseStyles({ theme }),
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
});
const PrimaryCard = styled('div')(primaryStyles);
sx vs styled #
使用 sx 的场景 #
jsx
<Box sx={{ p: 2, bgcolor: 'primary.main' }}>
快速原型开发
</Box>
<Button sx={{ mt: 2, borderRadius: 20 }}>
一次性样式
</Button>
使用 styled 的场景 #
jsx
const CustomButton = styled(Button)(({ theme }) => ({
borderRadius: 20,
textTransform: 'none',
fontWeight: 600,
}));
<CustomButton>可复用组件</CustomButton>
性能对比 #
| 特性 | sx prop | styled |
|---|---|---|
| 性能 | 略慢 | 更快 |
| 可复用性 | 低 | 高 |
| 开发速度 | 快 | 中 |
| 类型安全 | 好 | 好 |
样式覆盖 #
通过 sx prop #
jsx
<Button
sx={{
bgcolor: 'secondary.main',
'&:hover': {
bgcolor: 'secondary.dark',
},
}}
>
自定义按钮
</Button>
通过 styled #
jsx
const CustomTextField = styled(TextField)({
'& .MuiOutlinedInput-root': {
borderRadius: 12,
'& fieldset': {
borderColor: 'primary.main',
},
'&:hover fieldset': {
borderColor: 'primary.dark',
},
},
});
通过主题 #
jsx
const theme = createTheme({
components: {
MuiButton: {
styleOverrides: {
root: {
borderRadius: 20,
textTransform: 'none',
},
},
},
},
});
通过 className #
jsx
import { styled } from '@mui/material/styles';
const CustomButton = styled(Button)`
border-radius: 20px;
text-transform: none;
`;
全局样式 #
GlobalStyles 组件 #
jsx
import { GlobalStyles } from '@mui/material';
<GlobalStyles
styles={{
'*': {
boxSizing: 'border-box',
},
html: {
scrollBehavior: 'smooth',
},
body: {
margin: 0,
padding: 0,
},
'::-webkit-scrollbar': {
width: 8,
},
'::-webkit-scrollbar-track': {
background: '#f1f1f1',
},
'::-webkit-scrollbar-thumb': {
background: '#888',
borderRadius: 4,
},
}}
/>
在主题中定义 #
jsx
const theme = createTheme({
components: {
MuiCssBaseline: {
styleOverrides: {
body: {
scrollbarColor: '#6b6b6b #2b2b2b',
'&::-webkit-scrollbar, & *::-webkit-scrollbar': {
backgroundColor: '#2b2b2b',
},
'&::-webkit-scrollbar-thumb, & *::-webkit-scrollbar-thumb': {
borderRadius: 8,
backgroundColor: '#6b6b6b',
},
},
},
},
},
});
CSS 变量 #
启用 CSS 变量 #
jsx
const theme = createTheme({
cssVariables: true,
palette: {
primary: {
main: '#1976d2',
},
},
});
使用 CSS 变量 #
jsx
<Box sx={{ color: 'var(--mui-palette-primary-main)' }}>
使用 CSS 变量
</Box>
自定义 CSS 变量 #
jsx
const theme = createTheme({
cssVariables: {
cssVarPrefix: 'my-app',
},
palette: {
primary: {
main: '#1976d2',
},
},
});
实战示例:设计系统组件 #
jsx
import { styled, alpha } from '@mui/material/styles';
import { Button, Card, TextField } from '@mui/material';
const PrimaryButton = styled(Button)(({ theme }) => ({
borderRadius: 24,
padding: theme.spacing(1.5, 3),
textTransform: 'none',
fontWeight: 600,
boxShadow: 'none',
'&:hover': {
boxShadow: 'none',
backgroundColor: alpha(theme.palette.primary.main, 0.9),
},
}));
const GlassCard = styled(Card)(({ theme }) => ({
backgroundColor: alpha(theme.palette.background.paper, 0.8),
backdropFilter: 'blur(10px)',
borderRadius: 16,
border: `1px solid ${alpha(theme.palette.divider, 0.1)}`,
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.1)',
}));
const RoundedTextField = styled(TextField)(({ theme }) => ({
'& .MuiOutlinedInput-root': {
borderRadius: 12,
'& fieldset': {
borderColor: alpha(theme.palette.primary.main, 0.2),
},
'&:hover fieldset': {
borderColor: alpha(theme.palette.primary.main, 0.4),
},
'&.Mui-focused fieldset': {
borderColor: theme.palette.primary.main,
},
},
}));
function DesignSystemDemo() {
return (
<Stack spacing={2}>
<PrimaryButton variant="contained">Primary Button</PrimaryButton>
<GlassCard sx={{ p: 3 }}>
<Typography>Glass Card</Typography>
</GlassCard>
<RoundedTextField label="Rounded Input" />
</Stack>
);
}
下一步 #
继续学习 响应式设计,了解断点系统和响应式布局技巧!
最后更新:2026-03-28