两种使用方式 #
Emotion 提供了两种主要的样式编写方式:css prop 和 styled API。理解它们的区别和适用场景,能帮助你做出更好的选择。
css prop 方式 #
基本用法 #
css prop 允许你直接在 JSX 元素上添加样式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
function App() {
return (
<div
css={css`
padding: 20px;
background: #f5f5f5;
border-radius: 8px;
`}
>
Content
</div>
)
}
对象语法 #
使用 JavaScript 对象定义样式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const containerStyle = css({
padding: '20px',
backgroundColor: '#f5f5f5',
borderRadius: '8px',
})
function App() {
return <div css={containerStyle}>Content</div>
}
动态样式 #
基于 props 或 state 创建动态样式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
function Box({ isActive, size }) {
return (
<div
css={css`
padding: ${size === 'large' ? '32px' : '16px'};
background: ${isActive ? '#007bff' : '#6c757d'};
color: white;
border-radius: 4px;
transition: background 0.2s ease;
`}
>
{isActive ? 'Active' : 'Inactive'}
</div>
)
}
样式组合 #
组合多个样式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const baseStyle = css`
padding: 16px;
border-radius: 4px;
`
const primaryStyle = css`
background: #007bff;
color: white;
`
const dangerStyle = css`
background: #dc3545;
color: white;
`
function Button({ variant }) {
return (
<button css={[baseStyle, variant === 'danger' ? dangerStyle : primaryStyle]}>
Click me
</button>
)
}
styled API 方式 #
基本用法 #
styled API 创建带有样式的 React 组件:
jsx
import styled from '@emotion/styled'
const Container = styled.div`
padding: 20px;
background: #f5f5f5;
border-radius: 8px;
`
function App() {
return <Container>Content</Container>
}
基于 props 的动态样式 #
jsx
import styled from '@emotion/styled'
const Button = styled.button`
padding: ${props => props.size === 'large' ? '16px 32px' : '8px 16px'};
background: ${props => props.primary ? '#007bff' : '#6c757d'};
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.9;
}
`
function App() {
return (
<>
<Button primary size="large">Primary Large</Button>
<Button size="small">Default Small</Button>
</>
)
}
样式继承 #
扩展已有组件的样式:
jsx
import styled from '@emotion/styled'
const Button = styled.button`
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
`
const PrimaryButton = styled(Button)`
background: #007bff;
color: white;
&:hover {
background: #0056b3;
}
`
const DangerButton = styled(Button)`
background: #dc3545;
color: white;
&:hover {
background: #c82333;
}
`
组件选择器 #
使用组件作为选择器:
jsx
import styled from '@emotion/styled'
const Container = styled.div`
padding: 20px;
&:hover button {
background: #0056b3;
}
`
const Button = styled.button`
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
transition: background 0.2s ease;
`
function App() {
return (
<Container>
<p>Hover the container to change button color</p>
<Button>Click me</Button>
</Container>
)
}
两种方式对比 #
语法对比 #
| 特性 | css prop | styled |
|---|---|---|
| 定义方式 | 内联样式 | 创建组件 |
| 复用性 | 需要提取 | 天然可复用 |
| Props访问 | 直接访问组件props | 通过styled函数参数 |
| 调试 | 显示原始元素 | 显示样式组件名 |
性能对比 #
jsx
const items = Array.from({ length: 1000 }, (_, i) => i)
function CSSPropList() {
return (
<div>
{items.map(item => (
<div
key={item}
css={css`
padding: 8px;
background: #f5f5f5;
margin: 4px 0;
`}
>
Item {item}
</div>
))}
</div>
)
}
const Item = styled.div`
padding: 8px;
background: #f5f5f5;
margin: 4px 0;
`
function StyledList() {
return (
<div>
{items.map(item => (
<Item key={item}>Item {item}</Item>
))}
</div>
)
}
两种方式性能相近,styled 在大量重复元素时略有优势。
使用场景 #
css prop 适合: #
- 快速原型开发
jsx
<div css={css`padding: 20px;`}>Quick prototype</div>
- 一次性样式
jsx
<div css={css`margin-top: 16px;`}>One-time style</div>
- 条件样式
jsx
<div css={css`
background: ${isActive ? 'green' : 'gray'};
`}>
Conditional
</div>
styled 适合: #
- 可复用组件
jsx
const Card = styled.div`...`
const Button = styled.button`...`
- 复杂组件
jsx
const Dropdown = styled.div`
position: relative;
& .trigger { ... }
& .menu { ... }
& .item { ... }
`
- 组件库开发
jsx
export const Button = styled.button`...`
export const Input = styled.input`...`
export const Card = styled.div`...`
混合使用 #
在实际项目中,可以混合使用两种方式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
import styled from '@emotion/styled'
const Card = styled.div`
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`
const Title = styled.h2`
font-size: 20px;
color: #333;
margin: 0 0 12px;
`
function ProductCard({ product, featured }) {
return (
<Card css={featured && css`
border: 2px solid gold;
background: linear-gradient(white, #fffbe6);
`}>
<Title>{product.name}</Title>
<p css={css`color: #666; margin: 0;`}>
{product.description}
</p>
</Card>
)
}
最佳实践 #
1. 一致性 #
在项目中保持一致的风格:
jsx
const styles = {
container: css`...`,
title: css`...`,
}
const Container = styled.div`...`
const Title = styled.h1`...`
2. 提取复杂逻辑 #
对于复杂的样式逻辑,提取为函数:
jsx
const getButtonStyles = (variant, size) => {
const baseStyles = css`
border: none;
border-radius: 4px;
cursor: pointer;
`
const variantStyles = {
primary: css`background: #007bff; color: white;`,
secondary: css`background: #6c757d; color: white;`,
danger: css`background: #dc3545; color: white;`,
}
const sizeStyles = {
small: css`padding: 4px 8px; font-size: 12px;`,
medium: css`padding: 8px 16px; font-size: 14px;`,
large: css`padding: 12px 24px; font-size: 16px;`,
}
return [baseStyles, variantStyles[variant], sizeStyles[size]]
}
3. 类型安全 #
使用 TypeScript 获得更好的类型提示:
tsx
import styled from '@emotion/styled'
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'danger'
size?: 'small' | 'medium' | 'large'
}
const Button = styled.button<ButtonProps>`
padding: ${props => props.size === 'large' ? '12px 24px' : '8px 16px'};
background: ${props => {
switch (props.variant) {
case 'primary': return '#007bff'
case 'secondary': return '#6c757d'
case 'danger': return '#dc3545'
default: return '#007bff'
}
}};
color: white;
`
下一步 #
理解了两种使用方式后,继续学习 CSS属性,深入了解 css prop 的高级用法。
最后更新:2026-03-28