Styled Components 是目前功能最强大的 React CSS 方案,支持动态样式、主题系统、组件绑定等 SCSS 无法实现的功能。
| 功能 | SCSS | Styled Components |
|---|---|---|
| 动态样式(根据 props/state) | ❌ | ✅✅✅ |
| 组件绑定 | ❌ | ✅✅✅ |
| 主题系统 | ⚠️ 手动实现 | ✅✅✅ 内置 |
| 条件样式 | ❌ | ✅✅✅ |
| 运行时修改 | ❌ | ✅✅✅ |
| TypeScript 支持 | ⚠️ 基础 | ✅✅✅ 完美 |
| 变量系统 | ✅✅✅ | ✅✅✅ |
| 嵌套 | ✅✅✅ | ✅✅✅ |
| 函数/混入 | ✅✅✅ | ✅✅✅ |
| 编译时性能 | ✅✅✅ | ⚠️ 运行时 |
| 运行时性能 | ✅✅✅ | ⚠️ 有开销 |
// device.scss
.device-active { background: #28a745; }
.device-inactive { background: #0769fb; }
// 需要手动切换类名
<div className={isActive ? 'device-active' : 'device-inactive'}>
import styled from 'styled-components'
const Device = styled.div`
background-color: ${props => props.isActive ? '#28a745' : '#0769fb'};
color: ${props => props.isActive ? 'white' : 'black'};
transform: ${props => props.isActive ? 'scale(1.05)' : 'scale(1)'};
transition: all 0.3s;
`
// 直接使用,自动根据 props 变化
<Device isActive={isActive}>设备</Device>
优势: 样式完全由 JavaScript 控制,可以根据任何条件动态生成。
// 需要写多个主题类
.theme-light { background: #fff; color: #000; }
.theme-dark { background: #1a1a1a; color: #fff; }
<div className={`container ${theme === 'dark' ? 'theme-dark' : 'theme-light'}`}>
import styled, { ThemeProvider } from 'styled-components'
const Container = styled.div`
background-color: ${props => props.theme.bg};
color: ${props => props.theme.text};
`
const theme = {
light: { bg: '#fff', text: '#000' },
dark: { bg: '#1a1a1a', text: '#fff' }
}
// 一键切换主题
<ThemeProvider theme={theme[currentTheme]}>
<Container>内容</Container>
</ThemeProvider>
优势: 内置主题系统,切换主题无需修改组件代码。
// device.scss
.device-container { }
.device-title { }
.device-button { }
// device.jsx
import './device.scss'
<div className="device-container">
<h1 className="device-title">标题</h1>
<button className="device-button">按钮</button>
</div>
import styled from 'styled-components'
const DeviceContainer = styled.div`
width: 100%;
background-color: #0769fb;
`
const DeviceTitle = styled.h1`
font-size: 24px;
color: white;
`
const DeviceButton = styled.button`
padding: 12px 24px;
background: white;
border: none;
border-radius: 4px;
`
// 样式和组件完全绑定,不会冲突
function Device() {
return (
<DeviceContainer>
<DeviceTitle>标题</DeviceTitle>
<DeviceButton>按钮</DeviceButton>
</DeviceContainer>
)
}
优势: 样式和组件绑定,自动作用域隔离,不会产生样式冲突。
.button { }
.button-primary { background: blue; }
.button-danger { background: red; }
.button-large { padding: 20px; }
.button-small { padding: 10px; }
<button className={`button button-${type} button-${size}`}>
const Button = styled.button`
padding: ${props => props.size === 'large' ? '20px' : '10px'};
background-color: ${props => {
if (props.variant === 'primary') return '#0769fb';
if (props.variant === 'danger') return '#dc3545';
return '#6c757d';
}};
${props => props.disabled && `
opacity: 0.5;
cursor: not-allowed;
`}
`
<Button variant="primary" size="large" disabled={false}>
按钮
</Button>
优势: 使用 JavaScript 逻辑,更灵活强大。
.container {
width: 100%;
@media (max-width: 768px) {
width: 50%;
}
}
const Container = styled.div`
width: 100%;
${props => props.theme.breakpoints.md} {
width: 50%;
}
// 或者使用 props
width: ${props => props.isMobile ? '100%' : '50%'};
`
优势: 可以根据 props 动态调整,不局限于媒体查询。
// 无法类型检查
.container { }
interface ButtonProps {
variant?: 'primary' | 'danger' | 'success';
size?: 'small' | 'medium' | 'large';
}
const Button = styled.button<ButtonProps>`
background-color: ${props => {
// TypeScript 会自动提示 variant 的值
switch (props.variant) {
case 'primary': return '#0769fb';
case 'danger': return '#dc3545';
default: return '#6c757d';
}
}};
`
优势: 完整的 TypeScript 支持,类型安全,自动补全。
.device-online { background: green; }
.device-offline { background: red; }
.device-unknown { background: gray; }
<div className={`device-${status}`}>
const Device = styled.div`
background-color: ${props => {
if (props.status === 'online') return 'green';
if (props.status === 'offline') return 'red';
return 'gray';
}};
`
<Device status={status}>
优势: 无需预定义所有状态类,动态生成。
@keyframes slideIn {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
.slide-in { animation: slideIn 0.3s; }
const SlideIn = styled.div`
animation: ${props => props.duration || '0.3s'} slideIn;
@keyframes slideIn {
from { transform: translateX(-${props => props.distance || '100%'}); }
to { transform: translateX(0); }
}
`
<SlideIn duration="0.5s" distance="200px">
优势: 动画参数可以动态配置。
// 需要写很多类
.button { }
.button-primary { }
.button-primary-large { }
.button-primary-large-disabled { }
.button-danger { }
.button-danger-large { }
// ... 组合爆炸
const Button = styled.button`
padding: ${props => props.size === 'large' ? '20px' : '10px'};
background: ${props => props.variant === 'primary' ? '#0769fb' : '#dc3545'};
opacity: ${props => props.disabled ? 0.5 : 1};
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
`
// 任意组合,无需预定义
<Button variant="primary" size="large" disabled={false}>
<Button variant="danger" size="small" disabled={true}>
优势: 无需预定义所有组合,动态生成。
注意: 对于大多数应用,Styled Components 的性能开销可以忽略不计。
原因:
使用 Styled Components 当你需要:
使用 SCSS 当你需要:
npm install styled-components
import styled from 'styled-components'
const Container = styled.div`
background-color: ${props => props.bgColor || '#0769fb'};
padding: 16px;
`
function App() {
return <Container bgColor="#28a745">内容</Container>
}
Styled Components 比 SCSS 功能更强大,主要体现在:
但 SCSS 在性能上更优(编译时处理,零运行时开销)。
选择建议: