样式对象 #
一、样式对象基础 #
1.1 基本语法 #
jsx
import styled from 'styled-components';
const Button = styled.button({
padding: '12px 24px',
fontSize: '16px',
fontWeight: '600',
backgroundColor: '#667eea',
color: '#ffffff',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
});
1.2 与模板字符串对比 #
jsx
const ButtonTemplate = styled.button`
padding: 12px 24px;
font-size: 16px;
background-color: #667eea;
color: #ffffff;
border: none;
border-radius: 8px;
cursor: pointer;
`;
const ButtonObject = styled.button({
padding: '12px 24px',
fontSize: '16px',
backgroundColor: '#667eea',
color: '#ffffff',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
});
1.3 属性命名规则 #
text
CSS 属性命名转换
CSS 短横线命名 → JavaScript 驼峰命名
background-color → backgroundColor
border-radius → borderRadius
font-size → fontSize
line-height → lineHeight
box-shadow → boxShadow
text-align → textAlign
z-index → zIndex
flex-direction → flexDirection
justify-content → justifyContent
align-items → alignItems
二、嵌套选择器 #
2.1 伪类选择器 #
jsx
const Button = styled.button({
padding: '12px 24px',
backgroundColor: '#667eea',
color: '#ffffff',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
transition: 'all 0.2s',
':hover': {
backgroundColor: '#5a6fd6',
transform: 'translateY(-2px)',
},
':active': {
transform: 'translateY(0)',
},
':focus': {
outline: 'none',
boxShadow: '0 0 0 3px rgba(102, 126, 234, 0.3)',
},
':disabled': {
backgroundColor: '#cccccc',
cursor: 'not-allowed',
transform: 'none',
},
});
2.2 伪元素选择器 #
jsx
const Tooltip = styled.span({
position: 'relative',
cursor: 'pointer',
'::before': {
content: 'attr(data-tooltip)',
position: 'absolute',
bottom: '100%',
left: '50%',
transform: 'translateX(-50%)',
padding: '8px 12px',
backgroundColor: '#333333',
color: '#ffffff',
fontSize: '12px',
borderRadius: '4px',
whiteSpace: 'nowrap',
opacity: '0',
visibility: 'hidden',
transition: 'all 0.2s',
},
':hover::before': {
opacity: '1',
visibility: 'visible',
},
});
2.3 后代选择器 #
jsx
const Card = styled.div({
padding: '24px',
backgroundColor: '#ffffff',
borderRadius: '12px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
h2: {
fontSize: '24px',
fontWeight: '700',
marginBottom: '12px',
color: '#1a1a2e',
},
p: {
fontSize: '16px',
lineHeight: '1.6',
color: '#666666',
marginBottom: '16px',
},
a: {
color: '#667eea',
textDecoration: 'none',
':hover': {
textDecoration: 'underline',
},
},
'ul, ol': {
paddingLeft: '20px',
marginBottom: '16px',
},
});
2.4 子代选择器 #
jsx
const List = styled.ul({
listStyle: 'none',
padding: '0',
margin: '0',
'> li': {
padding: '12px',
borderBottom: '1px solid #eeeeee',
':last-child': {
borderBottom: 'none',
},
},
'> li > a': {
color: '#333333',
textDecoration: 'none',
},
});
三、媒体查询 #
3.1 基本媒体查询 #
jsx
const Container = styled.div({
padding: '16px',
width: '100%',
'@media (min-width: 768px)': {
padding: '24px',
maxWidth: '720px',
margin: '0 auto',
},
'@media (min-width: 1024px)': {
padding: '32px',
maxWidth: '960px',
},
'@media (min-width: 1280px)': {
maxWidth: '1140px',
},
});
3.2 响应式网格 #
jsx
const Grid = styled.div({
display: 'grid',
gap: '16px',
gridTemplateColumns: '1fr',
'@media (min-width: 640px)': {
gridTemplateColumns: 'repeat(2, 1fr)',
},
'@media (min-width: 1024px)': {
gridTemplateColumns: 'repeat(3, 1fr)',
gap: '24px',
},
'@media (min-width: 1280px)': {
gridTemplateColumns: 'repeat(4, 1fr)',
},
});
3.3 媒体查询变量 #
jsx
const breakpoints = {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
};
const Container = styled.div({
padding: '16px',
[`@media (min-width: ${breakpoints.md})`]: {
padding: '24px',
},
[`@media (min-width: ${breakpoints.lg})`]: {
padding: '32px',
},
});
四、函数样式 #
4.1 基于 Props 的样式 #
jsx
const Button = styled.button(props => ({
padding: '12px 24px',
fontSize: '16px',
borderRadius: '8px',
cursor: 'pointer',
border: 'none',
transition: 'all 0.2s',
backgroundColor: props.$primary ? '#667eea' : '#ffffff',
color: props.$primary ? '#ffffff' : '#667eea',
...(props.$disabled && {
opacity: 0.6,
cursor: 'not-allowed',
}),
...(props.$fullWidth && {
width: '100%',
}),
}));
4.2 复杂条件样式 #
jsx
const sizes = {
small: {
padding: '8px 16px',
fontSize: '14px',
},
medium: {
padding: '12px 24px',
fontSize: '16px',
},
large: {
padding: '16px 32px',
fontSize: '18px',
},
};
const variants = {
primary: {
backgroundColor: '#667eea',
color: '#ffffff',
border: 'none',
},
secondary: {
backgroundColor: 'transparent',
color: '#667eea',
border: '2px solid #667eea',
},
danger: {
backgroundColor: '#ff4d4f',
color: '#ffffff',
border: 'none',
},
};
const Button = styled.button(props => ({
borderRadius: '8px',
cursor: 'pointer',
transition: 'all 0.2s',
...sizes[props.$size || 'medium'],
...variants[props.$variant || 'primary'],
':hover:not(:disabled)': {
opacity: 0.9,
transform: 'translateY(-1px)',
},
...(props.$disabled && {
opacity: 0.6,
cursor: 'not-allowed',
}),
}));
4.3 主题访问 #
jsx
const Card = styled.div(props => ({
padding: props.theme.spacing[6],
backgroundColor: props.theme.colors.background,
borderRadius: props.theme.borderRadius.lg,
boxShadow: props.theme.shadows.md,
h2: {
fontSize: props.theme.typography.fontSize['2xl'],
fontWeight: props.theme.typography.fontWeight.bold,
color: props.theme.colors.text,
marginBottom: props.theme.spacing[4],
},
p: {
fontSize: props.theme.typography.fontSize.base,
lineHeight: props.theme.typography.lineHeight.relaxed,
color: props.theme.colors.textSecondary,
},
}));
五、样式对象复用 #
5.1 基础样式对象 #
jsx
const baseButtonStyles = {
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
fontWeight: '600',
borderRadius: '8px',
cursor: 'pointer',
transition: 'all 0.2s',
};
const PrimaryButton = styled.button({
...baseButtonStyles,
padding: '12px 24px',
backgroundColor: '#667eea',
color: '#ffffff',
border: 'none',
});
const SecondaryButton = styled.button({
...baseButtonStyles,
padding: '12px 24px',
backgroundColor: 'transparent',
color: '#667eea',
border: '2px solid #667eea',
});
5.2 样式变体 #
jsx
const buttonVariants = {
primary: {
backgroundColor: '#667eea',
color: '#ffffff',
border: 'none',
},
secondary: {
backgroundColor: 'transparent',
color: '#667eea',
border: '2px solid #667eea',
},
danger: {
backgroundColor: '#ff4d4f',
color: '#ffffff',
border: 'none',
},
};
const buttonSizes = {
small: {
padding: '8px 16px',
fontSize: '14px',
},
medium: {
padding: '12px 24px',
fontSize: '16px',
},
large: {
padding: '16px 32px',
fontSize: '18px',
},
};
const Button = styled.button(props => ({
borderRadius: '8px',
cursor: 'pointer',
transition: 'all 0.2s',
...buttonSizes[props.$size || 'medium'],
...buttonVariants[props.$variant || 'primary'],
}));
5.3 混合样式 #
jsx
const flexCenter = {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
};
const cardBase = {
backgroundColor: '#ffffff',
borderRadius: '12px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
};
const smoothTransition = {
transition: 'all 0.3s ease',
};
const Card = styled.div({
...cardBase,
...smoothTransition,
padding: '24px',
':hover': {
transform: 'translateY(-4px)',
boxShadow: '0 8px 24px rgba(0, 0, 0, 0.15)',
},
});
const CenteredCard = styled.div({
...cardBase,
...flexCenter,
...smoothTransition,
padding: '24px',
minHeight: '200px',
});
六、TypeScript 支持 #
6.1 类型定义 #
tsx
import styled from 'styled-components';
import { CSSObject } from 'styled-components';
interface ButtonProps {
$variant?: 'primary' | 'secondary' | 'danger';
$size?: 'small' | 'medium' | 'large';
}
const buttonStyles: CSSObject = {
padding: '12px 24px',
borderRadius: '8px',
cursor: 'pointer',
transition: 'all 0.2s',
};
const Button = styled.button<ButtonProps>(props => ({
...buttonStyles,
backgroundColor: props.$variant === 'danger' ? '#ff4d4f' : '#667eea',
color: '#ffffff',
border: 'none',
}));
6.2 完整类型示例 #
tsx
import styled, { CSSObject, DefaultTheme } from 'styled-components';
type StyleFunction<P = {}> = (props: P & { theme: DefaultTheme }) => CSSObject;
interface CardProps {
$elevated?: boolean;
$rounded?: boolean;
}
const cardStyles: StyleFunction<CardProps> = (props) => ({
padding: props.theme.spacing[6],
backgroundColor: props.theme.colors.background,
borderRadius: props.$rounded ? '16px' : '8px',
boxShadow: props.$elevated
? '0 8px 24px rgba(0, 0, 0, 0.15)'
: '0 4px 12px rgba(0, 0, 0, 0.1)',
});
const Card = styled.div<CardProps>(cardStyles);
七、与模板字符串混合 #
7.1 混合使用 #
jsx
import styled, { css } from 'styled-components';
const baseStyles = {
padding: '12px 24px',
borderRadius: '8px',
cursor: 'pointer',
};
const hoverStyles = css`
&:hover {
opacity: 0.9;
transform: translateY(-1px);
}
`;
const Button = styled.button`
${baseStyles}
${hoverStyles}
background: #667eea;
color: white;
border: none;
`;
7.2 对象转 css #
jsx
import styled, { css } from 'styled-components';
const objectToCss = (obj) => css`${obj}`;
const styles = {
padding: '12px',
backgroundColor: '#667eea',
};
const Button = styled.button`
${objectToCss(styles)}
color: white;
border: none;
`;
八、性能考虑 #
8.1 对象 vs 模板字符串 #
jsx
const ObjectButton = styled.button({
padding: '12px 24px',
backgroundColor: '#667eea',
color: '#ffffff',
border: 'none',
borderRadius: '8px',
});
const TemplateButton = styled.button`
padding: 12px 24px;
background-color: #667eea;
color: #ffffff;
border: none;
border-radius: 8px;
`;
性能对比:
text
对象样式
├── 更快的解析速度
├── 更好的类型推断
├── 适合静态样式
└── 函数样式每次渲染都会重新计算
模板字符串
├── 更好的语法高亮
├── 支持完整 CSS 语法
├── 适合复杂选择器
└── 更接近原生 CSS 写法
8.2 缓存样式对象 #
jsx
const staticStyles = {
padding: '12px 24px',
borderRadius: '8px',
};
const Button = styled.button(props => ({
...staticStyles,
backgroundColor: props.$primary ? '#667eea' : '#ffffff',
}));
九、选择指南 #
9.1 使用对象样式的场景 #
text
✅ 推荐使用对象样式
├── 简单静态样式
├── 需要类型推断
├── 样式需要动态计算
├── 与 JavaScript 逻辑紧密耦合
└── 需要样式对象复用
9.2 使用模板字符串的场景 #
text
✅ 推荐使用模板字符串
├── 复杂 CSS 选择器
├── 需要嵌套语法
├── 大量伪类/伪元素
├── 复杂媒体查询
├── 需要 CSS 注释
└── 希望更好的语法高亮
十、总结 #
样式对象要点速查表:
| 特性 | 对象语法 | 模板字符串 |
|---|---|---|
| 属性命名 | 驼峰命名 | 短横线命名 |
| 嵌套选择器 | ':hover': {} |
&:hover {} |
| 媒体查询 | '@media ...': {} |
@media ... {} |
| Props | 函数返回对象 | 插值表达式 |
| 类型支持 | 天然支持 | 需要配置 |
下一步:学习 组件组合模式 掌握组件样式的组合技巧。
最后更新:2026-03-28