CSS属性 #
基本概念 #
css prop 是 Emotion 提供的一种在 JSX 元素上直接添加样式的方式。它比传统内联样式更强大,支持完整的 CSS 语法。
启用 css prop #
方式一:Pragma 注释 #
在文件顶部添加 jsx pragma:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
function App() {
return <div css={css`color: red;`}>Hello</div>
}
方式二:Babel 配置 #
在 .babelrc 中配置:
json
{
"presets": ["@babel/preset-react"],
"plugins": ["@emotion"]
}
方式三:TypeScript 配置 #
在 tsconfig.json 中配置:
json
{
"compilerOptions": {
"jsxImportSource": "@emotion/react"
}
}
样式语法 #
模板字符串语法 #
使用模板字符串编写标准 CSS:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
function App() {
return (
<div
css={css`
padding: 20px;
background-color: #f5f5f5;
border-radius: 8px;
&:hover {
background-color: #e0e0e0;
}
`}
>
Hover me
</div>
)
}
对象语法 #
使用 JavaScript 对象定义样式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const containerStyle = css({
padding: '20px',
backgroundColor: '#f5f5f5',
borderRadius: '8px',
':hover': {
backgroundColor: '#e0e0e0',
},
})
function App() {
return <div css={containerStyle}>Hover me</div>
}
属性命名规则 #
对象语法使用驼峰命名:
| CSS 属性 | 对象属性 |
|---|---|
| background-color | backgroundColor |
| border-radius | borderRadius |
| font-size | fontSize |
| margin-top | marginTop |
| padding-left | paddingLeft |
动态样式 #
基于 Props #
根据组件 props 动态设置样式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
function Alert({ type, children }) {
const alertStyles = css`
padding: 12px 16px;
border-radius: 4px;
margin-bottom: 12px;
background-color: ${type === 'success' ? '#d4edda' :
type === 'warning' ? '#fff3cd' :
type === 'error' ? '#f8d7da' : '#cce5ff'};
color: ${type === 'success' ? '#155724' :
type === 'warning' ? '#856404' :
type === 'error' ? '#721c24' : '#004085'};
border: 1px solid ${type === 'success' ? '#c3e6cb' :
type === 'warning' ? '#ffeeba' :
type === 'error' ? '#f5c6cb' : '#b8daff'};
`
return <div css={alertStyles}>{children}</div>
}
function App() {
return (
<>
<Alert type="success">操作成功!</Alert>
<Alert type="warning">请注意!</Alert>
<Alert type="error">发生错误!</Alert>
<Alert type="info">提示信息</Alert>
</>
)
}
基于 State #
根据组件 state 动态设置样式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
import { useState } from 'react'
function ToggleButton() {
const [isOn, setIsOn] = useState(false)
return (
<button
onClick={() => setIsOn(!isOn)}
css={css`
padding: 12px 24px;
border: none;
border-radius: 20px;
cursor: pointer;
font-size: 16px;
font-weight: bold;
transition: all 0.3s ease;
background-color: ${isOn ? '#28a745' : '#dc3545'};
color: white;
&:hover {
opacity: 0.9;
}
`}
>
{isOn ? 'ON' : 'OFF'}
</button>
)
}
基于 Theme #
使用主题中的值:
jsx
/** @jsxImportSource @emotion/react */
import { css, useTheme } from '@emotion/react'
function ThemedButton({ children }) {
const theme = useTheme()
return (
<button
css={css`
padding: 12px 24px;
background-color: ${theme.colors.primary};
color: ${theme.colors.white};
border: none;
border-radius: ${theme.borderRadius.medium};
cursor: pointer;
&:hover {
background-color: ${theme.colors.primaryDark};
}
`}
>
{children}
</button>
)
}
样式组合 #
数组组合 #
使用数组组合多个样式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const baseButton = css`
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
transition: all 0.2s ease;
`
const primaryButton = css`
background-color: #007bff;
color: white;
&:hover {
background-color: #0056b3;
}
`
const largeButton = css`
padding: 12px 24px;
font-size: 18px;
`
function Button({ variant, size, children }) {
return (
<button
css={[
baseButton,
variant === 'primary' && primaryButton,
size === 'large' && largeButton,
]}
>
{children}
</button>
)
}
条件组合 #
根据条件动态组合样式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const inputBase = css`
padding: 10px 14px;
border: 2px solid #ddd;
border-radius: 4px;
font-size: 14px;
outline: none;
transition: border-color 0.2s ease;
&:focus {
border-color: #007bff;
}
`
const inputError = css`
border-color: #dc3545;
&:focus {
border-color: #dc3545;
}
`
const inputDisabled = css`
background-color: #f5f5f5;
cursor: not-allowed;
opacity: 0.6;
`
function Input({ error, disabled, ...props }) {
return (
<input
css={[
inputBase,
error && inputError,
disabled && inputDisabled,
]}
disabled={disabled}
{...props}
/>
)
}
提取样式 #
提取为常量 #
将样式提取为可复用的常量:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const styles = {
container: css`
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
`,
section: css`
padding: 40px 0;
`,
title: css`
font-size: 32px;
font-weight: bold;
color: #333;
margin-bottom: 20px;
`,
text: css`
font-size: 16px;
line-height: 1.6;
color: #666;
`,
}
function App() {
return (
<div css={styles.container}>
<section css={styles.section}>
<h1 css={styles.title}>Welcome</h1>
<p css={styles.text}>Hello World</p>
</section>
</div>
)
}
提取为函数 #
创建动态样式函数:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const getFlexStyles = (direction = 'row', justify = 'center', align = 'center') => css`
display: flex;
flex-direction: ${direction};
justify-content: ${justify};
align-items: ${align};
`
const getSpacingStyles = (padding = 16, margin = 0) => css`
padding: ${padding}px;
margin: ${margin}px;
`
function FlexContainer({ direction, justify, align, padding, margin, children }) {
return (
<div css={[getFlexStyles(direction, justify, align), getSpacingStyles(padding, margin)]}>
{children}
</div>
)
}
嵌套选择器 #
伪类选择器 #
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const linkStyle = css`
color: #007bff;
text-decoration: none;
&:hover {
text-decoration: underline;
}
&:visited {
color: #6c757d;
}
&:active {
color: #0056b3;
}
`
伪元素选择器 #
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const clearfixStyle = css`
&::after {
content: '';
display: table;
clear: both;
}
`
const customListStyle = css`
list-style: none;
& li::before {
content: '✓';
margin-right: 8px;
color: #28a745;
}
`
子元素选择器 #
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const cardStyle = css`
padding: 20px;
background: white;
border-radius: 8px;
& > h2 {
margin-top: 0;
color: #333;
}
& > p {
color: #666;
line-height: 1.6;
}
& > button {
margin-top: 16px;
}
`
性能优化 #
避免内联对象 #
❌ 不推荐:每次渲染创建新对象
jsx
function Component() {
return (
<div css={{ padding: 20, margin: 10 }}>
Content
</div>
)
}
✅ 推荐:提取样式常量
jsx
const containerStyle = css`
padding: 20px;
margin: 10px;
`
function Component() {
return <div css={containerStyle}>Content</div>
}
使用 useMemo #
缓存动态样式:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
import { useMemo } from 'react'
function Component({ size, color }) {
const dynamicStyle = useMemo(() => css`
font-size: ${size}px;
color: ${color};
`, [size, color])
return <div css={dynamicStyle}>Content</div>
}
下一步 #
掌握了 css prop 的用法后,继续学习 Styled组件,了解 styled API 的更多高级特性。
最后更新:2026-03-28