两种使用方式 #

Emotion 提供了两种主要的样式编写方式:css propstyled 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 适合: #

  1. 快速原型开发
jsx
<div css={css`padding: 20px;`}>Quick prototype</div>
  1. 一次性样式
jsx
<div css={css`margin-top: 16px;`}>One-time style</div>
  1. 条件样式
jsx
<div css={css`
  background: ${isActive ? 'green' : 'gray'};
`}>
  Conditional
</div>

styled 适合: #

  1. 可复用组件
jsx
const Card = styled.div`...`
const Button = styled.button`...`
  1. 复杂组件
jsx
const Dropdown = styled.div`
  position: relative;
  
  & .trigger { ... }
  & .menu { ... }
  & .item { ... }
`
  1. 组件库开发
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