Emotion:用 JavaScript 编写 CSS 的强大工具

简介

Emotion 是一个专为 JavaScript 设计的 CSS-in-JS 库,它允许开发者以编程的方式编写样式,提供高效、可预测的样式组合能力,同时带来出色的开发体验。无论是简单的静态样式,还是复杂的动态样式,Emotion 都能轻松应对。

它支持主流浏览器(包括 IE11),并且提供两种主要用法:

  • 框架无关的 @emotion/css

  • 专为 React 优化的 @emotion/react

本文将介绍 Emotion 的用法和底层原理,帮助你快速上手并理解其工作机制。


用法

Emotion 的用法灵活多样,开发者可以根据项目需求选择适合的方式。以下是两种主要的使用场景及其具体实现方法:

1. 框架无关的使用 (@emotion/css)

如果你不依赖 React 或其他框架,可以使用 @emotion/css 包。这是最轻量级的用法,只需一个简单的导入即可开始。

示例:动态生成样式

import { css } from '@emotion/css';

const buttonStyle = css`
  padding: 12px 24px;
  background-color: #ff69b4;
  border-radius: 4px;
  &:hover {
    background-color: #ff1493;
  }
`;

document.getElementById('myButton').classList.add(buttonStyle);

在这个例子中,css 函数接受一个模板字符串,返回一个类名。你可以将这个类名应用到任何 DOM 元素上。支持嵌套选择器(如 &:hover)和动态值,让样式编写既直观又强大。

动态样式

Emotion 支持基于变量的动态样式:

const color = 'darkgreen';
const dynamicStyle = css`
  color: ${color};
  font-size: 16px;
`;

这种方式非常适合需要根据状态或用户输入调整样式的场景。

2. 与 React 集成 (@emotion/react@emotion/styled)

对于 React 项目,Emotion 提供了更深度的集成,主要通过 @emotion/reactcss 属性和 @emotion/styled 的 styled-components 风格组件。

示例:使用 css 属性

import { css } from '@emotion/react';

function App() {
  const titleStyle = css`
    font-size: 24px;
    color: #4682b4;
  `;

  return <h1 css={titleStyle}>Hello, Emotion!</h1>;
}

在这里,css 属性直接将样式应用到 React 组件上,无需手动管理类名。样式与组件共存,代码更简洁。

示例:使用 styled-components

import styled from '@emotion/styled';

const Button = styled.button`
  padding: 10px 20px;
  background-color: #32cd32;
  border: none;
  &:hover {
    background-color: #228b22;
  }
`;

function App() {
  return <Button>Click Me</Button>;
}

通过 styled,你可以创建一个带有样式的可复用组件,支持动态 props 和主题化,非常适合构建组件库。

动态样式与主题

Emotion 支持通过 props 或主题对象动态调整样式:

const DynamicButton = styled.button`
  background-color: ${(props) => (props.primary ? '#1e90ff' : '#gray')};
`;

结合 ThemeProvider,还可以实现全局主题管理,让样式更具一致性。


原理

Emotion 的强大功能背后,是其精心设计的运行机制。以下是 Emotion 工作的核心原理:

1. CSS-in-JS 的核心思想

Emotion 的本质是将 CSS 逻辑融入 JavaScript,通过代码生成样式并注入到 DOM 中。相比传统 CSS 文件,它的优势在于:

  • 样式与逻辑共存:样式可以直接访问 JavaScript 变量和函数,实现动态性。

  • 作用域隔离:生成的样式类名是唯一的,避免全局样式冲突。

  • 按需注入:样式只在组件渲染时注入,未使用的样式不会出现在最终输出中。

2. 样式生成与注入

当你调用 css 函数或使用 styled 创建组件时,Emotion 会:

  1. 解析样式:将模板字符串或对象形式的样式解析为标准的 CSS 规则。

  2. 生成唯一类名:为每段样式生成一个唯一的类名(例如 .css-1a2b3c4),确保隔离性。

  3. 注入到 DOM:将解析后的 CSS 规则通过 <style> 标签注入到页面的 <head> 中。

例如:

const style = css`color: red;`;

会被转换为:

<style>
.css-1a2b3c4 { color: red; }
</style>

这种运行时注入的方式让 Emotion 既灵活又高效。

3. 性能优化

Emotion 在性能上做了大量优化:

  • 缓存机制:重复的样式只生成一次,避免冗余计算。

  • Babel 插件:通过 @emotion/babel-plugin,可以在构建时优化样式,压缩代码并提供更好的调试信息(如源映射和标签)。

  • 按需加载:支持服务器端渲染(SSR)和按需提取关键 CSS,提升首屏加载速度。

4. 支持对象样式

除了模板字符串,Emotion 还支持对象形式的样式(camelCase 格式),例如:

const style = css({ backgroundColor: '#ff0', fontSize: 16 });

这种方式更适合 TypeScript 项目,因为它能提供类型检查,减少错误。

5. 扩展性

Emotion 的插件化设计允许开发者扩展其功能。例如,可以通过自定义缓存或 Stylis 插件调整样式处理逻辑,满足特殊需求。


优势与适用场景

  • 开发者体验:支持源映射、自动标签和测试工具,提升调试效率。

  • 灵活性:支持字符串和对象样式,适配不同开发习惯。

  • 适用场景:适合 React 项目、组件库开发,或需要动态样式的复杂应用。

无论是小型项目还是大型企业应用,Emotion 都能通过其模块化和高性能特性满足需求。如果你希望在 JavaScript 中掌控样式的全部潜力,Emotion 无疑是一个值得尝试的工具。

最后更新于

这有帮助吗?