CSS-in-JS:Styled-components 与 Emotion
使用 styled-components 将组件样式编写为带标签的模板字面量,或使用 Emotion 的 css 属性,并利用属性实现动态样式。
CSS-in-JS:Styled-components 与 Emotion 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。
什么是 CSS-in-JS
CSS-in-JS 将组件样式直接写在 JavaScript/TypeScript 中。样式与组件放在一起,支持使用 props 中的动态值,并且会自动限制作用域。最流行的两个库是 styled-components 和 Emotion。
styled-components 基础
使用带标签的模板字面量定义样式化组件。结果是一个 React 组件,它会渲染应用了这些样式的 HTML 元素。
import styled from 'styled-components';
const Button = styled.button`
background: ${props => props.primary ? '#6366f1' : 'white'};
color: ${props => props.primary ? 'white' : '#6366f1'};
padding: 8px 16px;
border: 2px solid #6366f1;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.9;
}
`;
<Button primary>Primary</Button>
<Button>Outline</Button>Emotion——css 属性
Emotion 的 css 属性可以为任意 JSX 元素应用样式。它需要 @emotion/react pragma 或 Babel 预设。
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
function Card({ featured }: { featured?: boolean }) {
return (
<div css={css`
padding: 16px;
border-radius: 8px;
border: ${featured ? '2px solid #6366f1' : '1px solid #e2e8f0'};
`}>
Content
</div>
);
}根据 props 生成动态样式
这两个库都可以读取 props 来计算样式。这是它们相较于静态 CSS 的主要优势——不需要切换类名。
使用 ThemeProvider 设置主题
styled-components 和 Emotion 都支持 ThemeProvider,它会将主题值注入所有样式化组件。
import { ThemeProvider } from 'styled-components';
const theme = { colors: { primary: '#6366f1', bg: '#f7fafc' }, space: { sm: 8, md: 16 } };
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
// Access in styled component:
const Card = styled.div`
background: ${props => props.theme.colors.bg};
padding: ${props => props.theme.space.md}px;
`;扩展样式化组件
扩展现有的样式化组件,即可创建变体,而无需重复样式。
const Button = styled.button`
padding: 8px 16px;
border-radius: 4px;
`;
const DangerButton = styled(Button)`
background: #e53e3e;
color: white;
`;全局样式
对于 body 样式和重置样式等全局 CSS,请使用 createGlobalStyle(styled-components)或 Global(Emotion)。
import { createGlobalStyle } from 'styled-components';
const GlobalStyle = createGlobalStyle`
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font-family: system-ui; }
`;
<><GlobalStyle /><App /></>CSS-in-JS 的运行时开销
CSS-in-JS 库会通过 JavaScript 在运行时注入样式。这会增加解析和注入样式所需的 CPU 开销,也会增大 JavaScript 包的体积。零运行时替代方案(vanilla-extract、linaria)会在构建时生成静态 CSS。
零运行时替代方案
vanilla-extract:使用 TypeScript 编写样式,并编译为静态 CSS。linaria:将 CSS-in-JS 语法编译为 CSS 模块。两者都能提供 CSS-in-JS 的使用体验,同时不产生运行时开销。
使用 styled-components 编写 TypeScript
定义 ThemeType,并扩展 styled-components 中的 DefaultTheme 接口,即可获得完全类型化的主题。
import 'styled-components';
import { theme } from './theme';
declare module 'styled-components' {
export interface DefaultTheme extends typeof theme {}
}何时选择 CSS-in-JS
CSS-in-JS 非常适合以下场景:由运行时 JavaScript 值驱动的动态样式、强烈需要主题功能的设计系统,以及偏好以 JS 为主工作流的团队。对于非性能关键型界面,其运行时开销通常可以接受。
快速检查
与静态 CSS 方案相比,运行时 CSS-in-JS 库的主要权衡是什么?
回顾:CSS-in-JS
styled-components:使用带标签的模板字面量,渲染样式化的 React 元素。Emotion:使用 css 属性或 styled API。根据 props 生成动态样式,从而无需切换类名。ThemeProvider 注入主题值。使用 createGlobalStyle 创建全局 CSS。主要权衡是运行时开销。零运行时替代方案:vanilla-extract、linaria。
用 AI 导师学习 HTML — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 41
- 课程
- 163
常见问题解答
「CSS-in-JS:Styled-components 与 Emotion」课时是免费的吗?
是的 — 「CSS-in-JS:Styled-components 与 Emotion」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Frontend Academy 课程的其余内容,请升级到 CoddyKit PRO。 Frontend Academy 课程共包含 4 节课。
「CSS-in-JS:Styled-components 与 Emotion」这节课中我会学到什么?
使用 styled-components 将组件样式编写为带标签的模板字面量,或使用 Emotion 的 css 属性,并利用属性实现动态样式。 你通过在浏览器中直接运行的动手代码来练习 Frontend Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Frontend Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Frontend Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「CSS-in-JS:Styled-components 与 Emotion」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Frontend Academy 课中编写并运行代码吗?
能。每节 Frontend Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- BEM 方法论:块、元素与修饰符
- CSS Modules:作用域类名
- CSS-in-JS:Styled-components 与 Emotion
- Tailwind CSS:实用优先方法