CSS助手函数 #
一、css 函数基础 #
1.1 基本语法 #
jsx
import styled, { css } from 'styled-components';
const flexCenter = css`
display: flex;
align-items: center;
justify-content: center;
`;
const Container = styled.div`
${flexCenter}
width: 100%;
height: 100vh;
`;
1.2 为什么使用 css 函数 #
text
普通插值 vs css 函数
普通插值(不推荐):
const mixin = 'color: red; font-size: 16px;';
const Text = styled.p`
${mixin}
`;
css 函数(推荐):
const mixin = css`
color: red;
font-size: 16px;
`;
const Text = styled.p`
${mixin}
`;
优势:
├── 语法高亮支持
├── 样式自动前缀
├── 嵌套选择器支持
└── 更好的 IDE 支持
二、样式复用 #
2.1 基础混入 #
jsx
import styled, { css } from 'styled-components';
const truncate = css`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
const cardShadow = css`
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`;
const smoothTransition = css`
transition: all 0.3s ease;
`;
const Title = styled.h1`
${truncate}
${smoothTransition}
font-size: 24px;
max-width: 300px;
`;
const Card = styled.div`
${cardShadow}
${smoothTransition}
padding: 24px;
background: white;
border-radius: 12px;
&:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}
`;
2.2 布局混入 #
jsx
const flexCenter = css`
display: flex;
align-items: center;
justify-content: center;
`;
const flexBetween = css`
display: flex;
align-items: center;
justify-content: space-between;
`;
const flexColumn = css`
display: flex;
flex-direction: column;
`;
const absoluteCenter = css`
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
`;
const fullScreen = css`
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
`;
const Container = styled.div`
${flexCenter}
width: 100%;
min-height: 100vh;
`;
const Header = styled.header`
${flexBetween}
padding: 16px 24px;
background: white;
`;
const Sidebar = styled.aside`
${flexColumn}
width: 280px;
height: 100vh;
`;
const Modal = styled.div`
${fullScreen}
${flexCenter}
background: rgba(0, 0, 0, 0.5);
`;
2.3 排版混入 #
jsx
const headingBase = css`
font-family: 'Poppins', sans-serif;
font-weight: 700;
line-height: 1.2;
color: #1a1a2e;
`;
const bodyText = css`
font-family: 'Inter', sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333333;
`;
const codeBlock = css`
font-family: 'Fira Code', monospace;
font-size: 14px;
background: #f5f5f5;
padding: 2px 6px;
border-radius: 4px;
`;
const H1 = styled.h1`
${headingBase}
font-size: 48px;
`;
const H2 = styled.h2`
${headingBase}
font-size: 36px;
`;
const Paragraph = styled.p`
${bodyText}
margin-bottom: 16px;
`;
const Code = styled.code`
${codeBlock}
`;
三、参数化混入 #
3.1 函数式混入 #
jsx
const padding = (size) => css`
padding: ${size};
`;
const margin = (size) => css`
margin: ${size};
`;
const borderRadius = (size) => css`
border-radius: ${size};
`;
const Box = styled.div`
${padding('24px')}
${margin('16px')}
${borderRadius('12px')}
background: white;
`;
3.2 配置对象 #
jsx
const card = ({ shadow = 'md', radius = 'lg', padding = '24px' } = {}) => css`
background: white;
border-radius: ${radius};
padding: ${padding};
${shadow === 'sm' && css`
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
`}
${shadow === 'md' && css`
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
`}
${shadow === 'lg' && css`
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
`}
`;
const Card = styled.div`
${card({ shadow: 'lg', radius: '16px' })}
`;
const SmallCard = styled.div`
${card({ shadow: 'sm', padding: '16px' })}
`;
3.3 响应式混入 #
jsx
const breakpoints = {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
};
const media = {
sm: (...args) => css`
@media (min-width: ${breakpoints.sm}) {
${css(...args)}
}
`,
md: (...args) => css`
@media (min-width: ${breakpoints.md}) {
${css(...args)}
}
`,
lg: (...args) => css`
@media (min-width: ${breakpoints.lg}) {
${css(...args)}
}
`,
xl: (...args) => css`
@media (min-width: ${breakpoints.xl}) {
${css(...args)}
}
`,
};
const Container = styled.div`
padding: 16px;
${media.md`
padding: 24px;
`}
${media.lg`
padding: 32px;
max-width: 1200px;
margin: 0 auto;
`}
`;
const Grid = styled.div`
display: grid;
gap: 16px;
grid-template-columns: 1fr;
${media.sm`
grid-template-columns: repeat(2, 1fr);
`}
${media.md`
grid-template-columns: repeat(3, 1fr);
`}
${media.lg`
grid-template-columns: repeat(4, 1fr);
gap: 24px;
`}
`;
四、条件样式 #
4.1 基于 Props 的条件 #
jsx
const buttonVariants = {
primary: css`
background: #667eea;
color: white;
border: none;
&:hover {
background: #5a6fd6;
}
`,
secondary: css`
background: transparent;
color: #667eea;
border: 2px solid #667eea;
&:hover {
background: #667eea;
color: white;
}
`,
danger: css`
background: #ff4d4f;
color: white;
border: none;
&:hover {
background: #ff7875;
}
`,
};
const Button = styled.button`
padding: 12px 24px;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
transition: all 0.2s;
${props => buttonVariants[props.$variant] || buttonVariants.primary}
`;
4.2 复杂条件 #
jsx
const sizes = {
small: css`
padding: 8px 16px;
font-size: 14px;
`,
medium: css`
padding: 12px 24px;
font-size: 16px;
`,
large: css`
padding: 16px 32px;
font-size: 18px;
`,
};
const Button = styled.button`
${props => sizes[props.$size] || sizes.medium}
${props => buttonVariants[props.$variant] || buttonVariants.primary}
${props => props.$fullWidth && css`
width: 100%;
`}
${props => props.$disabled && css`
opacity: 0.6;
cursor: not-allowed;
pointer-events: none;
`}
${props => props.$loading && css`
position: relative;
color: transparent;
&::after {
content: '';
position: absolute;
width: 16px;
height: 16px;
border: 2px solid white;
border-top-color: transparent;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
`}
`;
4.3 状态样式 #
jsx
const inputStates = {
error: css`
border-color: #ff4d4f;
&:focus {
border-color: #ff4d4f;
box-shadow: 0 0 0 3px rgba(255, 77, 79, 0.2);
}
`,
success: css`
border-color: #22c55e;
&:focus {
border-color: #22c55e;
box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.2);
}
`,
warning: css`
border-color: #f59e0b;
&:focus {
border-color: #f59e0b;
box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);
}
`,
};
const Input = styled.input`
padding: 12px 16px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 16px;
&:focus {
border-color: #667eea;
outline: none;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
}
${props => props.$state && inputStates[props.$state]}
${props => props.$disabled && css`
background: #f5f5f5;
cursor: not-allowed;
`}
`;
五、样式组合 #
5.1 组合多个混入 #
jsx
const baseButton = css`
display: inline-flex;
align-items: center;
justify-content: center;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
`;
const rounded = css`
border-radius: 9999px;
`;
const elevated = css`
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
&:hover {
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
}
`;
const outlined = css`
background: transparent;
border: 2px solid currentColor;
`;
const Button = styled.button`
${baseButton}
${props => props.$rounded && rounded}
${props => props.$elevated && elevated}
${props => props.$outlined && outlined}
padding: 12px 24px;
background: #667eea;
color: white;
border: none;
`;
function App() {
return (
<>
<Button>Default</Button>
<Button $rounded>Rounded</Button>
<Button $elevated>Elevated</Button>
<Button $outlined $rounded>Outlined Rounded</Button>
</>
);
}
5.2 样式集合 #
jsx
const mixins = {
flex: {
center: css`
display: flex;
align-items: center;
justify-content: center;
`,
between: css`
display: flex;
align-items: center;
justify-content: space-between;
`,
column: css`
display: flex;
flex-direction: column;
`,
},
text: {
truncate: css`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`,
center: css`
text-align: center;
`,
},
effects: {
smoothTransition: css`
transition: all 0.3s ease;
`,
hoverLift: css`
&:hover {
transform: translateY(-4px);
}
`,
},
};
const Card = styled.div`
${mixins.flex.column}
${mixins.effects.smoothTransition}
${mixins.effects.hoverLift}
padding: 24px;
background: white;
border-radius: 12px;
`;
六、主题混入 #
6.1 访问主题 #
jsx
const themed = (property) => css`
${property}: ${props => props.theme[property]};
`;
const ThemedButton = styled.button`
${themed('background')}
${themed('color')}
padding: 12px 24px;
`;
6.2 颜色混入 #
jsx
const color = (colorName, shade = 'main') => css`
color: ${props => props.theme.colors[colorName]?.[shade] || props.theme.colors[colorName]?.main};
`;
const backgroundColor = (colorName, shade = 'main') => css`
background-color: ${props => props.theme.colors[colorName]?.[shade] || props.theme.colors[colorName]?.main};
`;
const borderColor = (colorName, shade = 'main') => css`
border-color: ${props => props.theme.colors[colorName]?.[shade] || props.theme.colors[colorName]?.main};
`;
const Button = styled.button`
${backgroundColor('primary')}
${color('neutral', 'white')}
padding: 12px 24px;
border-radius: 8px;
&:hover {
${backgroundColor('primary', 'dark')}
}
`;
6.3 间距混入 #
jsx
const spacing = (size) => css`
${props => props.theme.spacing[size] || props.theme.spacing[4]};
`;
const padding = (size) => css`
padding: ${props => props.theme.spacing[size] || props.theme.spacing[4]};
`;
const margin = (size) => css`
margin: ${props => props.theme.spacing[size] || props.theme.spacing[4]};
`;
const gap = (size) => css`
gap: ${props => props.theme.spacing[size] || props.theme.spacing[4]};
`;
const Card = styled.div`
${padding(6)}
${margin(4)}
${gap(3)}
background: white;
border-radius: 12px;
`;
七、高级模式 #
7.1 链式混入 #
jsx
const styledMixin = (styles) => {
const chain = {
styles: css`${styles}`,
and: (moreStyles) => styledMixin(css`${chain.styles}${moreStyles}`),
};
return chain;
};
const base = styledMixin`
padding: 12px;
border-radius: 8px;
`;
const withShadow = base.and`
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
`;
const withHover = withShadow.and`
&:hover {
transform: translateY(-2px);
}
`;
const Card = styled.div`
${withHover.styles}
background: white;
`;
7.2 工厂函数 #
jsx
const createVariant = (variants) => (props) => {
const variant = variants[props.$variant] || variants.default;
return css`${variant}`;
};
const buttonVariant = createVariant({
default: css`
background: #667eea;
color: white;
`,
secondary: css`
background: transparent;
color: #667eea;
border: 2px solid #667eea;
`,
danger: css`
background: #ff4d4f;
color: white;
`,
});
const Button = styled.button`
${buttonVariant}
padding: 12px 24px;
border-radius: 8px;
`;
7.3 样式构建器 #
jsx
const StyleBuilder = {
styles: [],
add(cssInput) {
this.styles.push(cssInput);
return this;
},
padding(value) {
this.styles.push(css`padding: ${value};`);
return this;
},
margin(value) {
this.styles.push(css`margin: ${value};`);
return this;
},
background(value) {
this.styles.push(css`background: ${value};`);
return this;
},
borderRadius(value) {
this.styles.push(css`border-radius: ${value};`);
return this;
},
build() {
return css`${this.styles}`;
},
};
const cardStyles = StyleBuilder
.padding('24px')
.background('white')
.borderRadius('12px')
.add(css`box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);`)
.build();
const Card = styled.div`
${cardStyles}
`;
八、性能考虑 #
8.1 避免内联创建 #
jsx
const BadComponent = styled.div`
${css`
padding: 16px;
`}
`;
const paddingMixin = css`
padding: 16px;
`;
const GoodComponent = styled.div`
${paddingMixin}
`;
8.2 缓存复杂计算 #
jsx
import { useMemo } from 'react';
const useDynamicStyles = (variant) => {
return useMemo(() => css`
${variants[variant]}
`, [variant]);
};
const DynamicComponent = styled.div`
${props => props.$dynamicStyles}
`;
function App() {
const dynamicStyles = useDynamicStyles('primary');
return <DynamicComponent $dynamicStyles={dynamicStyles} />;
}
九、总结 #
css 函数使用技巧速查表:
| 用法 | 示例 |
|---|---|
| 基础混入 | const mixin = css\color: red;`` |
| 参数化 | const pad = (s) => css\padding: ${s};`` |
| 条件样式 | ${props => props.active && activeStyle} |
| 组合 | ${mixin1}${mixin2} |
| 主题访问 | ${props => props.theme.colors.primary} |
下一步:学习 样式对象 掌握对象样式定义方式。
最后更新:2026-03-28