Goober logo

Goober

极致轻量的跨框架 CSS-in-JS 方案

CSS-in-JS轻量级框架无关styled

Goober 以极小包体积提供类似 styled-components 和 Emotion 的开发体验,适合追求性能和跨框架兼容性的项目。

Goober

🐿️ 不到 1KB 的极致轻量 CSS-in-JS 方案,为追求极致包体积的项目而生


技术简介说明

Goober 是一个体积极小(gzip 后仅约 1.25KB)的 CSS-in-JS 样式库,由罗马尼亚工程师 Cristian Bote 创建并维护。它提供了与 Emotion、styled-components 相似的 API(styled()css()keyframes()createGlobalStyles() 等),但包体积仅为其 1/6 到 1/10——这让它成为对性能敏感的 Web 应用、嵌入式组件、微前端和 Web Components 场景中的理想选择。

与大多数 CSS-in-JS 库强绑定 React 生态不同,Goober 采用框架无关的设计哲学。它通过 setup(pragm) 将任意 vDOM 渲染函数(React 的 createElement、Preact 的 h、Fre 的 h,甚至原生 DOM 操作)接入核心,真正实现了"一套 API,多框架通用"。这种极小的体积和极高的兼容性,让 Goober 在 Web Components、微前端、跨框架组件库等场景下有着不可替代的优势。

2025–2026 年,Goober 持续保持活跃迭代(最新 v2.1.19,2026 年 5 月发布),新增了 CSP nonce 支持、迁移至 Vite 构建、持续优化 TypeScript 类型导出等。在 CSS-in-JS 整体向"零运行时"演进的大背景下,Goober 凭借极致的轻量运行时和零配置体验,依然在特定场景下保持独特竞争力。


基本信息

项目说明
名称Goober
最新版本v2.1.19(2026 年 5 月 13 日发布)
官网goober.js.org
文档站goober.rocks
GitHubgithub.com/cristianbote/goober
npmnpmjs.com/package/goober
LicenseMIT
Stars~3.3k ⭐
维护者Cristian Bote
框架依赖无(框架无关,通过 setup() 接入)
TypeScript内置类型定义(goober.d.ts
包体积gzip 后约 1.25KB(同类最小)

快速上手

安装

# npm
npm install goober
 
# yarn
yarn add goober
 
# pnpm
pnpm add goober

基础配置(React)

import React from 'react'
import { styled, setup } from 'goober'
 
// 必须调用 setup,传入框架的 createElement 函数
setup(React.createElement)
 
// 使用模板字符串语法定义组件
const Button = styled('button')`
  background: palevioletred;
  color: white;
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
 
  &:hover {
    background: darkorchid;
  }
`
 
export default function App() {
  return <Button>Click me</Button>
}

基础配置(Preact)

import { h } from 'preact'
import { setup, styled } from 'goober'
 
// Preact 使用 h 函数作为 pragma
setup(h)
 
const Title = styled('h1')`
  color: #333;
  font-size: 24px;
`
 
export default function App() {
  return <Title>Hello Goober!</Title>
}

原生 JS(Web Components)

import { styled, setup, css } from 'goober'
 
// 原生 DOM 场景,传入自定义渲染函数
setup((tag, props, ...children) => {
  const el = document.createElement(tag)
  Object.entries(props || {}).forEach(([k, v]) => {
    if (k === 'className') el.setAttribute('class', v)
    else if (k.startsWith('on')) el.addEventListener(k.slice(2).toLowerCase(), v)
    else el.setAttribute(k, v)
  })
  children.flat().forEach(child => el.appendChild(
    child instanceof Node ? child : document.createTextNode(child)
  ))
  return el
})
 
// 定义样式
const btnClass = css`
  background: #007bff;
  color: white;
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
`
 
// 应用样式
const btn = document.createElement('button')
btn.className = btnClass
btn.textContent = 'Click me'
document.body.appendChild(btn)

核心概念与架构

架构设计

Goober 采用极简的运行时架构,核心只有几个关键模块:

goober
├── core        # 核心:样式注入引擎、类名哈希生成
├── styled      # styled() API —— 创建 styled 组件
├── css         # css() API —— 生成类名字符串
├── glob        # glob/glob`...` —— 注入全局样式
├── extractCss  # SSR 支持 —— 提取并清空已生成的 CSS
├── prefixer    # goober/prefixer —— 自动添加浏览器前缀
└── should-forward-prop  # 控制 DOM 属性转发

工作流程

1. setup(pragm)          接入框架渲染函数
2. styled('div')`...`    定义组件时:
   ├── 解析模板字符串 / 样式对象
   ├── 生成哈希类名(如 go1234567)
   └── 返回包装组件(挂载 className)
3. 渲染时:
   ├── 组件渲染为 vDOM 节点(含 className)
   └── 样式注入到 <style> 标签(幂等去重)
4. SSR 时:
   └── extractCss() 提取所有已注入样式为 <style> 字符串

样式生成原理

Goober 将模板字符串或样式对象解析后,通过一个轻量哈希函数生成唯一类名(如 go1a2b3c),然后将 CSS 规则注入到 DOM 中的 &lt;style&gt; 标签。相同的样式内容只会注入一次,避免重复。


核心特性

1. 极致轻量(<1KB gzip)

Goober gzip 后仅约 1.25KB,是同类 CSS-in-JS 库中最小的:

gzip 大小
Goober~1.25 KB
Emotion~7.4 KB
styled-components~12.6 KB

2. 框架无关

通过 setup(pragm) 接入任意 vDOM 框架,官方支持 React、Preact、Fre 和原生 JS。

3. 完整的 API 体系

  • styled() —— 创建 styled 组件
  • css() —— 生成类名字符串
  • keyframes() —— 定义动画
  • createGlobalStyles() —— 全局样式组件
  • glob —— 全局样式(函数式)
  • extractCss() —— SSR 样式提取

4. SSR(服务端渲染)支持

通过 extractCss() 在服务端提取所有已生成的 CSS,插入到 HTML 的 &lt;head&gt; 中,实现关键 CSS 注入,避免 FOUC(Flash of Unstyled Content)。

5. TypeScript 完整支持

内置 goober.d.ts 类型定义文件,支持泛型 props、组件类型推断、样式对象类型检查。

6. 主题支持(Theming)

import { styled, setup, ThemeProvider } from 'goober'
 
const theme = {
  colors: {
    primary: '#007bff',
    secondary: '#6c757d',
  },
  spacing: {
    sm: '8px',
    md: '16px',
  },
}
 
const Button = styled('button')(
  (props) => `
    background: ${props.theme.colors.primary};
    padding: ${props.theme.spacing.sm};
    color: white;
    border: none;
    border-radius: 4px;
  `
)

7. 嵌套规则与媒体查询

const Card = styled('div')`
  padding: 16px;
  background: white;
 
  &:hover {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  }
 
  h2 {
    font-size: 20px;
    margin-bottom: 8px;
  }
 
  @media (max-width: 768px) {
    padding: 8px;
  }
`

8. 动态样式(Props 驱动)

const Box = styled('div')`
  background: ${(props) => props.primary ? '#007bff' : '#6c757d'};
  padding: ${(props) => props.large ? '24px' : '12px'};
  color: white;
  border-radius: 4px;
`
 
// 使用
<Box primary large>Primary & Large</Box>
<Box>Secondary & Default</Box>

9. 自动前缀(Autoprefixer)

通过 goober/prefixer 插件自动为 CSS 属性添加浏览器前缀:

import { styled, setup } from 'goober'
import { prefix } from 'goober/prefixer'
 
setup(React.createElement, prefix)
 
const Box = styled('div')`
  display: flex;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
`

10. CSP(内容安全策略)支持

自 v2.1.17(2025 年 10 月)起支持 CSP nonce:

// 在 setup 时传入 nonce
setup(React.createElement, undefined, () => ({
  nonce: 'your-csp-nonce-value'
}))

⚠️ CSP nonce 支持是 v2.1.17 新增特性,早期版本需要自行处理。参考 Issue #471


生态图

核心集成

包名说明
goober核心库(<1KB)
goober/prefixer自动浏览器前缀插件
goober/should-forward-prop控制 DOM 属性转发

框架集成

集成方式说明
Reactsetup(React.createElement)
Preactsetup(h)
Fresetup(h)
原生 JS / Web Components自定义 setup 函数

构建工具集成

工具包名 / 说明
Babelbabel-plugin-transform-goober —— 支持 styled.div 语法糖
Babel Macrogoober/macro —— 零配置 Babel macro
CSS Prop@agley/babel-plugin-goober-css-prop —— 支持 css prop
Next.js官方示例:stackblitz.com/edit/github-mlwqmi
Gatsbygatsby-plugin-goober —— 自动 pragma 配置 + SSR
Preact CLIpreact-cli-goober-ssr —— 预渲染页面关键 CSS 提取
Vite官方文档站使用 Vite 构建,开箱支持

社区插件

插件说明
goober-global全局样式工具
goober-autoprefixer社区 autoprefixer 实现
@nksaraf/goober社区 fork 版本

适用场景

1. Web Components / 自定义元素

Web Components 对包体积极为敏感,Goober 的 <1KB 特性使其成为 shadow DOM 内样式的理想选择。

2. 微前端子应用

微前端架构中,每个子应用都需要独立的样式方案。Goober 的轻量特性让每个子应用的样式开销降到最低。

3. 嵌入式组件 / Widget

嵌入第三方网站的 Widget(客服插件、支付按钮、评论组件等)需要极小的包体积以避免影响宿主页面性能,Goober 是绝佳选择。

4. 跨框架组件库

当你需要构建同时兼容 React、Preact 等多框架的组件库时,Goober 的框架无关设计让样式层无需为每个框架重复实现。

5. 性能敏感型应用

对于 Lighthouse 分数至关重要的高性能网站,Goober 的 <1KB 体积和极快的运行时(~169,157 ops/sec SSR)可以显著减少首屏加载时间。

6. 原型开发与小型项目

无需复杂配置,npm install goobersetup() 一下即可使用,适合快速原型验证和小型单页应用。

7. CSP 严格环境

需要遵守严格内容安全策略的企业应用,v2.1.17+ 的 CSP nonce 支持使 Goober 可以合规使用。


开发与工程化

开发模式

Goober 本身不提供 HMR(热模块替换)支持,但由于样式通过类名注入,搭配 Vite/Webpack 的 HMR 可以正常工作。修改样式代码后,新类名会自动生成并注入。

生产构建

Goober 的样式在运行时生成,无法像 Linaria/vanilla-extract 那样在构建时提取为静态 CSS 文件。这意味着:

  • ✅ 支持动态样式(props 驱动)
  • ❌ 不支持零运行时(runtime-free)构建
  • ⚠️ 样式计算开销在运行时发生

Babel 优化

使用 babel-plugin-transform-goober 可以获得更优雅的语法:

npm install -D babel-plugin-transform-goober
// .babelrc
{
  "plugins": ["babel-plugin-transform-goober"]
}
// 转换前
const Title = styled('h1')`...`
 
// 转换后(更优雅的语法)
const Title = styled.h1`...`

TypeScript 配置

Goober 内置类型定义,无需额外安装 @types/goober。对于 styled 组件的 props 类型:

import { styled } from 'goober'
 
interface ButtonProps {
  primary?: boolean
  size?: 'sm' | 'md' | 'lg'
}
 
const Button = styled('button')<ButtonProps>`
  background: ${(props) => props.primary ? '#007bff' : '#6c757d'};
  padding: ${(props) => {
    switch (props.size) {
      case 'sm': return '4px 8px'
      case 'lg': return '12px 24px'
      default: return '8px 16px'
    }
  }};
  color: white;
  border: none;
  border-radius: 4px;
`

样式对象(替代模板字符串)

使用 JSON 对象语法可以进一步减小包体积:

const Button = styled('button')({
  background: '#007bff',
  color: 'white',
  padding: '8px 16px',
  border: 'none',
  borderRadius: '4px',
  '&:hover': {
    background: '#0056b3',
  },
  '@media (max-width: 768px)': {
    padding: '4px 8px',
  },
})

💡 使用样式对象代替模板字符串,可以进一步减小约 200B 的包体积。


性能与安全

性能数据

指标Gooberstyled-componentsEmotion
gzip 体积~1.25 KB~12.6 KB~7.4 KB
SSR 吞吐量~169,157 ops/sec~10,000 ops/sec~73,000 ops/sec
运行时开销极低中等较低

数据来源:LogRocket Blog 基准测试

性能优势

  • 极小体积:1.25KB gzip,解析和执行速度极快
  • 高效哈希:轻量哈希算法生成唯一类名,去重注入
  • 无额外依赖:核心库无第三方依赖,不增加 node_modules 解析负担
  • SSR 友好extractCss() 一次性提取所有样式,避免额外 I/O

安全注意事项

  • CSP 支持:v2.1.17+ 支持 nonce 属性,可在严格 CSP 环境下安全使用(参考 Issue #471
  • XSS 防护:模板字符串插值会经过 Goober 内部的样式解析,不会被直接注入为 HTML
  • DOM 注入:样式通过 &lt;style&gt; 标签注入到 &lt;head&gt;,不直接操作用户内容
  • SSR 并发:单例 store 在高并发 SSR 场景下可能存在竞态条件(参考 Issue #158),建议在请求级别隔离样式缓存

技术对比

综合对比表

特性Gooberstyled-componentsEmotionLinariavanilla-extractTailwind CSS
体积(gzip)~1.25 KB~12.6 KB~7.4 KB~0 KB(零运行时)~0 KB(零运行时)~0 KB(原子化)
运行时✅ 轻量✅ 较重✅ 中等❌ 编译时提取❌ 编译时提取❌ 编译时提取
框架绑定❌ 无关ReactReact/PreactReact框架无关框架无关
TypeScript✅ 内置✅ 内置✅ 内置✅ 内置✅ 内置✅ 内置
SSR✅ extractCss✅ 内置✅ 内置✅ 自动✅ 自动✅ 自动
CSP nonce✅ v2.1.17+✅ 内置✅ 内置N/AN/AN/A
动态样式⚠️ 有限
主题系统
嵌套语法
媒体查询
Autoprefixer✅ 插件N/AN/AN/A
零运行时
学习曲线极低
社区规模中等(3.3k⭐)大(40k+⭐)大(17k+⭐)中(9k+⭐)中(5k+⭐)极大(85k+⭐)

选型建议

  • 极致包体积优先 → Goober
  • 零运行时 + 类型安全 → Linaria / vanilla-extract
  • 原子化 CSS + 设计系统 → Tailwind CSS / Panda CSS
  • React 生态成熟方案 → Emotion / styled-components
  • 跨框架组件库 → Goober / vanilla-extract

最佳实践

1. 始终调用 setup()

这是最常见的遗漏。Goober 必须通过 setup() 知道如何创建 vDOM 元素,否则会报错:

// ✅ 正确:在应用入口调用一次
import { setup } from 'goober'
setup(React.createElement) // 或 h(Preact)
 
// ❌ 错误:不调用 setup 直接使用 styled
import { styled } from 'goober'
const Box = styled('div')`...` // 运行时报错

2. 优先使用样式对象

样式对象比模板字符串更小、更快,且更容易被 TypeScript 类型检查:

// ✅ 推荐:样式对象
const Box = styled('div')({
  padding: 16,
  color: 'white',
})
 
// ⚠️ 可用:模板字符串(适合需要动态插值的场景)
const Box = styled('div')`
  padding: 16px;
  color: white;
`

3. 合理使用 shouldForwardProp

防止自定义 props 被透传到 DOM 元素(避免 React 警告):

import { styled, setup } from 'goober'
import { shouldForwardProp } from 'goober/should-forward-prop'
 
setup(React.createElement, undefined, undefined, shouldForwardProp)
 
const Box = styled('div')<{ $primary?: boolean }>`
  background: ${(props) => props.$primary ? '#007bff' : '#6c757d'};
  color: white;
  padding: 8px 16px;
`

💡 使用 $ 前缀命名自定义 props 是 styled-components 社区的惯例,Goober 的 shouldForwardProp 默认过滤 $ 开头的 props。

4. SSR 场景正确使用 extractCss()

// server.js(Node.js)
import { extractCss } from 'goober'
import { renderToString } from 'react-dom/server'
import App from './App'
 
const html = renderToString(<App />)
const css = extractCss() // 提取并清空样式缓存
 
const fullHtml = `
<!DOCTYPE html>
<html>
<head>
  <style>${css}</style>
</head>
<body>
  <div id="root">${html}</div>
</body>
</html>
`

5. 全局样式用 createGlobalStyles()

不要在组件内使用 glob 注入全局样式(每次渲染都会执行),应该使用 createGlobalStyles()

import { createGlobalStyles } from 'goober'
 
const GlobalStyles = createGlobalStyles`
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
  body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    line-height: 1.5;
  }
`
 
// 在应用根部渲染一次
function App() {
  return (
    <>
      <GlobalStyles />
      <Main />
    </>
  )
}

6. 动画复用 keyframes()

import { keyframes, styled } from 'goober'
 
const spin = keyframes`
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
`
 
// 多个组件共享同一个动画定义
const Spinner = styled('div')`
  animation: ${spin} 1s linear infinite;
  width: 24px;
  height: 24px;
  border: 2px solid #ccc;
  border-top-color: #007bff;
  border-radius: 50%;
`

技术局限与边界

1. 无零运行时支持

Goober 是运行时方案,所有样式在浏览器(或 Node.js SSR)中动态计算并注入。无法像 Linaria、vanilla-extract、Panda CSS 那样在构建时提取为静态 CSS 文件。这意味着:

  • 增加运行时 CPU 开销(虽然极小)
  • 首屏需要等待 JS 执行后才能注入样式
  • 与 React Server Components(RSC)的兼容性存在挑战

2. SSR 并发竞态风险

Goober 使用单例 store 存储所有已生成的样式。在高并发 SSR 环境下,多个请求共享同一 store 可能导致样式串扰或提前清空(参考 Issue #158)。需要自行在请求级别做缓存隔离。

3. 社区规模有限

相比 styled-components(40k+ ⭐)和 Emotion(17k+ ⭐),Goober 的 3.3k ⭐ 社区规模较小,意味着:

  • 第三方插件和工具较少
  • 遇到问题的社区解答资源有限
  • 企业级采用案例相对较少

4. 无组件交换(Component Swapping)

Goober 不支持 as prop 等组件交换语法(如 &lt;Button as="a" href="/"&gt;),这在某些设计系统中是常见需求。

5. 无自动标签(Labels)

Goober 不生成人类可读的类名(如 Button-primary-abc123),只生成哈希类名(如 go1a2b3c),调试时需要依赖 source map 或浏览器 devtools 反查。

6. 生态绑定度低

不像 Emotion 有 @emotion/reactcss prop 和 JSX pragma 的深度集成,Goober 的 css prop 支持依赖第三方 Babel 插件,配置相对繁琐。

7. RSC(React Server Components)兼容性

作为运行时方案,Goober 在 React Server Components 环境中无法正常工作(服务端无法执行 setup() 和样式注入)。这是所有运行时 CSS-in-JS 方案的共同挑战,但在 2026 年 RSC 日益普及的背景下,这一局限变得更加突出。


学习资源

官方资源

教程与文章

视频

在线示例


2026 年现状

版本迭代

截至 2026 年 7 月,Goober 最新版本为 v2.1.19(2026 年 5 月 13 日发布)。近期重要更新:

版本时间变更
v2.1.192026-05-13迁移至 Vite 构建、精简包体积
v2.1.182025-10-03修复 CSP nonce 属性注入时序
v2.1.172025-10-02新增 CSP(内容安全策略)支持
v2.1.162025-10-11修复 :has 伪类多选择器 bug
v2.1.152025-10-07TypeScript 类型:JSX → React.JSX

CSS-in-JS 行业趋势

2025–2026 年,CSS-in-JS 领域正经历显著范式转变:

  1. 零运行时成为主流 — Linaria、vanilla-extract、Panda CSS、StyleX 等编译时方案快速增长
  2. 原子化 CSS 持续扩张 — Tailwind CSS 周下载量超 1200 万,稳居生态第一
  3. 传统运行时方案承压 — styled-components(进入维护模式)和 Emotion 在新项目中的采用率下降
  4. RSC 加速范式迁移 — React Server Components 的普及使得运行时样式注入方案面临根本性挑战

Goober 的定位

在这个趋势下,Goober 的独特价值在于:

  • 极致轻量无可替代 — 在 <1KB 体积下提供完整 CSS-in-JS 能力,没有任何竞品能在同一量级匹敌
  • 框架无关的稀缺性 — 在 Emotion/styled-components 强绑定 React 的市场中,Goober 的跨框架能力是其护城河
  • Web Components / 微前端的刚需 — 这些场景对包体积极度敏感,Goober 是最佳选择之一

但也面临挑战:

  • 零运行时方案(vanilla-extract、Panda CSS)在类型安全和构建时优化方面优势明显
  • 原生 CSS 能力(@scope:has()、容器查询)的增强减少了部分 CSS-in-JS 的需求
  • RSC 生态的成熟对运行时方案构成结构性威胁

结论

Goober 在 2026 年依然是一个健康、活跃的项目,在极致包体积框架无关这两个维度上保持着独特且不可替代的地位。对于 Web Components、嵌入式组件、微前端、跨框架组件库等场景,Goober 仍然是最推荐的 CSS-in-JS 方案。但对于以 React 为主、追求零运行时和类型安全的大型应用,vanilla-extract、Panda CSS 或原生 CSS 方案可能是更面向未来的选择。


参考资料