---
title: css-in-js
group:
  title: 设计
  path: /style
  order: 4
---
## 概述

组件库基于 `antd-style`实现css-in-js样式，同时提供了一套通用的 CSS-in-JS 样式自动 rem 转换解决方案，可以自动将 CSS-in-JS 中使用的 `px` 单位转换为 `rem` 单位，实现移动端适配。

## 特性

- ✅ **自动转换**：自动将 CSS 字符串中的 `px` 值转换为 `rem`
- ✅ **智能识别**：自动排除 `calc()`、`var()`、`url()` 等函数中的值
- ✅ **配置灵活**：支持自定义基准值、最小转换值、排除属性等
- ✅ **向后兼容**：无需修改现有代码，自动生效
- ✅ **类型安全**：完整的 TypeScript 类型支持

## 使用方法

### 基本使用

直接使用 `css` 函数，所有 `px` 值会自动转换为 `rem`：

```ts
import { css, createStyles } from '@/style';

// 方式 1: 使用 createStyles
const useStyles = createStyles(({ css, prefixCls }) => {
  return {
    container: css`
      width: 100%;
      padding: 12px 24px;  // 自动转换为 padding: 0.12rem 0.24rem;
      font-size: 16px;     // 自动转换为 font-size: 0.16rem;
      border-radius: 8px;   // 自动转换为 border-radius: 0.08rem;
    `,
  };
});

// 方式 2: 直接使用 css
const styles = css`
  width: 100%;
  margin: 10px 20px;  // 自动转换为 margin: 0.1rem 0.2rem;
`;
```

### 配置说明

默认配置（与 `smallfish.config.ts` 保持一致）：

- **rootValue**: `100` (1rem = 100px)
- **minPixelValue**: `2` (小于 2px 的值不转换)
- **enabled**: `true` (默认启用)
- **exclude**: `['border', 'border-top', ...]` (边框相关属性不转换)

可以通过环境变量覆盖配置：

```bash
# 设置 rem 基准值
REACT_APP_REM_ROOT_VALUE=100

# 启用/禁用自动转换
REACT_APP_REM_ENABLED=true
```

### 高级用法

#### 1. 使用原始 css 函数（不转换）

如果需要某些样式不进行转换，可以使用 `cssRaw`：

```ts
import { cssRaw } from '@/style';

const styles = cssRaw`
  width: 12px;  // 保持为 12px，不转换
`;
```

#### 2. 手动转换单个值

```ts
import { pxToRem } from '@/style';

const fontSize = pxToRem(16); // 返回 "0.16rem"
```

#### 3. 自定义转换函数

```ts
import { createPx2Rem } from '@/style';

const customPx2Rem = createPx2Rem({
  rootValue: 75,  // 自定义基准值
  minPixelValue: 1,
  exclude: ['font-size'],  // 排除字体大小
});

const cssText = customPx2Rem('width: 100px; font-size: 16px;');
// 结果: "width: 1.3333rem; font-size: 16px;"
```

## 转换规则

### 自动转换

以下情况会自动转换：

- ✅ 普通属性值：`width: 12px;` → `width: 0.12rem;`
- ✅ 多个值：`padding: 10px 20px;` → `padding: 0.1rem 0.2rem;`
- ✅ 小数：`font-size: 14.5px;` → `font-size: 0.145rem;`
- ✅ 负值：`margin: -12px;` → `margin: -0.12rem;`
- ✅ 0px：`margin: 0px;` → `margin: 0;`（无单位）

### 不转换的情况

以下情况不会转换：

- ❌ 小于 `minPixelValue` 的值：`border: 1px solid;` (保持为 `1px`)
- ❌ 排除的属性：`border-width: 2px;` (保持为 `2px`)
- ❌ 函数中的值：`calc(100px - 20px)` (保持原样)
- ❌ CSS 变量：`var(--spacing-12)` (保持原样)
- ❌ URL 中的值：`url(image@2x.png)` (保持原样)
- ❌ 注释中的值：`/* width: 12px */` (保持原样)
- ❌ 字符串中的值：`content: "12px"` (保持原样)

## 文件结构

```
src/style/
├── index.ts          # 主入口，导出增强的 css 函数
├── config.ts         # 配置文件
├── px2rem.ts         # px 转 rem 核心工具函数
├── cssWithRem.ts     # css 函数包装器
├── global.ts         # 全局样式
└── README.md         # 本文档
```

## 实现原理

1. **字符串解析**：解析 CSS 模板字符串，识别所有 `px` 值
2. **智能过滤**：排除函数、注释、特定属性中的值
3. **自动转换**：根据配置的基准值进行转换
4. **函数包装**：包装 `antd-style` 的 `css` 函数，在调用时自动转换

## 注意事项

1. **基准值一致性**：确保 `src/style/config.ts` 中的 `rootValue` 与 `smallfish.config.ts` 中的 `px2rem.rootValue` 保持一致
2. **排除属性**：`border` 相关属性默认不转换，因为边框通常使用 1px 等小值
3. **性能考虑**：大量样式时可能影响性能，可考虑添加缓存机制

## 已知问题

1. **属性选择器无引号**：`[data-size=12px]` 中的 px 会被转换（CSS 规范不推荐无引号）
2. **媒体查询**：`@media (max-width: 768px)` 中的 px 会被转换（通常是期望的行为）

## 更新日志

### 修复 border-radius 等属性未转换的问题

**问题**：`border-radius`、`border-color`、`border-style` 等属性中的 px 值没有被正确转换成 rem。

**原因**：排除逻辑使用了过于宽泛的前缀匹配，导致 `border-radius` 被错误地匹配到排除项 `border`。

**修复**：修改排除逻辑，只对明确列出的复合属性（包含 `-` 的排除项）进行前缀匹配，避免 `border` 匹配 `border-radius` 等属性。


