我开源了一个css-in-js库:class-css

class-css 是一个css-in-js库,可以通过编写 js 样式对象的形式享受伪类、选择器等功能。

快速开始

shell 复制代码
npm install class-css

默认使用方式:

tsx 复制代码
import { css } from 'class-css';

export default () => {
  return (
     <div className={css({ color: 'red' })}>
       一段文字
     </div>
  )
};

或者创建一个新的实例并调用其方法:

tsx 复制代码
import { createClassCss } from 'class-css';

const { css, keyframes } = createClassCss({
    key: 'tiger-ui'
});

export default () => {
  return (
     <div className={css({ color: 'red' })}>
       一段文字
     </div>
  )
};

需要注意的是,具有相同key的实例是同一个实例。(默认key为"css")

支持 css、keyframe、'&'

js 生成 css 样式。

tsx 复制代码
import { css } from 'class-css';

export default () => {
    return (
       <div
          className={css({
              color: 'red'
          })}
       >
          一段文字
      </div>
    );
}

js 生成 keyframes

tsx 复制代码
import { css, keyframes } from 'class-css';

export default () => {
    const appear = keyframes({
       from: {
           opacity: 0,
       },
       to: {
           opacity: 1,
       },
    });

    return (
       <div
          className={css({
             animation: `${appear} 1s forwards`,
          })}
       >
          一段文字
      </div>
    );
};

强大的'&',可实现伪类、伪元素、选择器等复杂功能。

tsx 复制代码
import { css, keyframes } from 'class-css';

const myBtn = css({
    background: 'white',
    transition: 'all .3s',
    cursor: 'pointer',
    border: '1px solid #e8e8e8',
    padding: '4px 12px',
    borderRadius: 2,
    '&:hover': {
        background: 'whitesmoke'
    },
    '&:active': {
        background: 'gray'
    },
    '& + &': {
        marginLeft: 8
    },
    '& span': {
        color: 'red'
    }
})

export default () => {
    return (
       <div>
         <button className={myBtn}>按钮</button>
         <button className={myBtn}>按钮</button>
         <button className={myBtn}>
             <span>按钮</span>
         </button>
      </div>
    );
};

为什么要自己实现 css-in-js 类库?

我之前使用的是 @emotion/css,如果一个页面大量调用其css方法,它会在短时内不断创建大量的style标签。

为了解决这个问题,我编写了class-css,确保每个实例在全局仅一个style标签,同时设计了缓存方案避免大量重复计算。

测试代码:

tsx 复制代码
import { css as emotionCss } from "@emotion/css";
import { css } from "class-css";
import { useState } from "react";

function App() {
  const [className, setClassName] = useState("");
  const [className2, setClassName2] = useState("");

  return (
    <div>
      <div style={{ display: "flex", gap: 8, paddingBottom: 8 }}>
        {["green", "yellow", "blue", "red"].map((color) => {
          return (
            <button
              key={color}
              onClick={() => {
                setClassName(css({ color }));
                setClassName2(emotionCss({ color }));
              }}
            >
              {color}
            </button>
          );
        })}
      </div>
      <div className={className}>@emotion/css</div>
      <div className={className2}>class-css</div>
    </div>
  );
}

在项目中使用

可以用于任意支持打包的web应用框架。(后续会提供直接在原生html下开发css-in-js解决方法)

In React

tsx 复制代码
import React from "react";
import { css } from "class-css";

export default () => {
  return <div className={css({ color: "red" })}>一段文字</div>;
};

In Vue

tsx 复制代码
<template>
  <div :class="css({ color: 'red' })">一段文字</div>
</template>

<script setup>
  import { css } from 'class-css';
</script>

class-css的实现原理

调用过程:

  • 初始化实例。
  • 调用实例的 css(styleObject) 方法。
  • 对 styleObject 计算唯一hash。
  • 对 styleObject 计算样式表文本 styleText。
  • 将 hash、styleText 作为键值对的形式加入到缓存 cache 中。
  • 检查缓存中不存在该 hash,则增量更新 styleText 到全局 style 标签。
  • 返回唯一 className 类名。

简单来说,就是转化样式对象为样式文本,增量更新样式文本到style标签上,最后返回className。 (需要注意的是:相同的key对应同一个实例,包括缓存,对应的style标签等。)

性能优化

其中有几个耗时步骤:

  • (大)样式对象计算 hash 值(支持自定义hash函数)
  • (大)样式对象转为样式文本
  • (小)缓存检测
  • (中)style标签内容更新(何时更新、更新什么)

使用 css-in-js 类库有什么好处?

  • 无需引入 css 样式文件
  • 可以通过 js 方便控制样式,例如修改主题色
  • 实现 style 不支持的功能,例如:伪选择器(:hover)等。
  • 支持全局类名覆盖(使用hash配合计算唯一性)

一些额外的 monorepo 子库

  • class-css-cache:处理缓存的库。
  • class-css-stringify:处理JS样式对象转样式表文本的库。

代码仓库

class-css

相关推荐
用户0595401744623 分钟前
把AI聊天机器人记忆存储测试从3小时压到5分钟,我用Pytest + Docker搭了一套自动化回归
前端·css
明月_清风24 分钟前
显存即正义:不同显存容量能训多大的模型?一文说清硬件边界与训练策略
前端·后端·ai编程
Sterting29 分钟前
第 9 节:本地存储 — 数据不丢的前端缓存
前端·javascript·缓存
IT_陈寒31 分钟前
Vite的HMR在我项目上突然失效,排查三天找到离谱原因
前端·人工智能·后端
人间凡尔赛38 分钟前
React Compiler 1.0 正式落地:告别 useMemo / useCallback,2026 前端性能优化的新范式
前端·性能优化·react
灵析表格1 小时前
灵析表格功能函数深度分析报告
前端·数据库·microsoft
Data_Journal1 小时前
掌握网页抓取中的分页:完整指南
java·服务器·前端
breeze jiang1 小时前
React useRef + Web Worker:避免大计算阻塞页面的通信方案
前端·javascript·react.js
fthux1 小时前
MCP协议开发实战:从零搭建AI Agent工具链
前端·人工智能·ai·开源·github