emotion性能瓶颈在于样式重复计算、ssr缓存错乱、global/keyframes长期驻留;需稳定css引用、复用cache实例、手动清理全局规则。

Emotion 写 CSS 本身不慢,性能瓶颈几乎全出在三件事上:样式重复计算、SSR 时缓存错乱、global/keyframes 长期驻留。不处理这三点,再“高性能”的库也会内存抖动、首屏闪、DevTools 里堆满 css-xxx。
css 函数必须稳定引用,否则每次 render 都新建规则
你在组件里写 css({ color: props.color }),哪怕 props.color 没变,Emotion 也会重新哈希、序列化、插入新 <style></style> 标签——因为对象字面量每次都是新引用。
- 错误写法:
function Button({ primary }) { const s = css({ color: primary ? 'blue' : 'gray' }); return <button css="{s}"></button> } - 正确做法:把静态部分提到组件外,动态部分用
useMemo包裹:const baseStyle = css({ padding: '8px 16px' }); const dynamicStyle = useMemo(() => css({ color: primary ? 'blue' : 'gray' }), [primary]) - 更推荐:直接用
styled,它内部已做 memoization:const StyledButton = styled.button(({ primary }) => ({ color: primary ? 'blue' : 'gray' }))
SSR 场景下必须复用同一 cache 实例
服务端生成的 HTML 如果不含内联样式,客户端 hydration 时就会重跑所有 css 调用,触发多次 insertRule,造成 layout thrashing 和内存抖动。
- 服务端:创建唯一
cache实例,传给CacheProvider,再调用renderStylesToString或extractCritical提取样式字符串,注入到<style>...</style> - 客户端:不能
new StyleSheetCache(),要从模块缓存或全局变量取服务端传来的同一实例 - Next.js 用户注意:
@emotion/server的版本必须与@emotion/react主版本一致,混用会导致缓存 key 错位,内存占用翻倍 - hydration 前执行
cache.reset()(仅 SSR 场景),否则服务端注入的规则和客户端新生成的规则可能冲突
global 和 keyframes 规则默认永不释放
global 和 keyframes 创建的样式规则被设计为“应用生命周期级”,不会随组件卸载自动清理——长期驻留会撑大内存,尤其在路由频繁切换的 SPA 中。
- 手动清理时机:比如在某个模块卸载后,调用
cache.inserted.clear()或重置特定 key(需提前记下 key) - 避免滥用:不要在组件内反复调用
global,改用主题变量或静态类名控制全局行为 - 动画场景慎用
keyframes:高频更新组件(如拖拽反馈)优先用 CSS 自定义属性 +@keyframes预定义,而非运行时生成
真正卡住性能的从来不是“怎么写样式”,而是样式逻辑和 React 生命周期、缓存机制、服务端上下文之间的交界点——这些地方没对齐,css 调用再多遍也白搭。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











