CSS 选型
1 CSS 方案横向对比
原生 CSS + BEM、Sass/Less、CSS Modules、CSS-in-JS、Tailwind、UnoCSS、vanilla-extract 横向对比
原生 + BEM:无运行时,靠规范防污染,规模大时易崩。
Sass/Less:变量、嵌套、mixins,仍是全局样式,需配合命名规范。
CSS Modules:局部作用域(类名 hash),构建期处理,无运行时,企业稳态选择。
CSS-in-JS:样式与组件同文件,动态样式强,有运行时成本,适合强主题/组件库。
Tailwind:原子类,开发快、一致性高,类名长、学习曲线。
UnoCSS:按需生成,更轻更快,生态不如 Tailwind。
vanilla-extract:零运行时 CSS-in-TS,类型安全,构建期生成。
Sass/Less:变量、嵌套、mixins,仍是全局样式,需配合命名规范。
CSS Modules:局部作用域(类名 hash),构建期处理,无运行时,企业稳态选择。
CSS-in-JS:样式与组件同文件,动态样式强,有运行时成本,适合强主题/组件库。
Tailwind:原子类,开发快、一致性高,类名长、学习曲线。
UnoCSS:按需生成,更轻更快,生态不如 Tailwind。
vanilla-extract:零运行时 CSS-in-TS,类型安全,构建期生成。
选型口诀:① 强动态/强主题 → CSS-in-JS 或 vanilla-extract ② 工程稳定+性能 → CSS Modules ③ 极致效率+一致性 → Tailwind/UnoCSS
各方案优缺点和适用场景
性能最好:原生 CSS、CSS Modules、SCSS(构建期)
动态能力最强:CSS-in-JS
开发效率最高:Tailwind / UnoCSS
团队协作最省心:CSS Modules、Tailwind
主题系统最强:CSS-in-JS、vanilla-extract
动态能力最强:CSS-in-JS
开发效率最高:Tailwind / UnoCSS
团队协作最省心:CSS Modules、Tailwind
主题系统最强:CSS-in-JS、vanilla-extract
中大型业务常用:CSS Modules + 设计 token + 少量全局基建,综合最稳。
2 CSS Modules 详解
CSS Modules 用法和原理
文件命名为
*.module.css,导入后类名自动加 hash,实现局部作用域。
/* Button.module.css */
.button {
background-color: blue;
color: white;
padding: 10px 20px;
}
import styles from './Button.module.css';
<button className={styles.button}>Click me</button>
// 实际类名:Button_button__x7f3a
作用域隔离、:global、组合类名
作用域:默认局部,编译时类名加唯一 hash。
:global:定义全局样式,不参与 hash。
组合:用
:global:定义全局样式,不参与 hash。
组合:用
classnames 或模板字符串组合多个类。
:global(.globalButton) {
background-color: green;
}
className={`${styles.button} ${styles.large}`}
CSS Modules 缺乏动态样式的灵活性?
样式是预定义的,只能通过类名切换,无法像 CSS-in-JS 那样根据 props 动态生成颜色等。需用 inline style 或预定义多套类。
3 CSS-in-JS
Styled Components、Emotion 用法
Styled Components:模板字面量定义样式,支持 props 动态样式、ThemeProvider。
Emotion:更灵活,支持 css 函数、styled 组件,性能更好。
Emotion:更灵活,支持 css 函数、styled 组件,性能更好。
// Styled Components
const Button = styled.button`
background-color: ${props => props.primary ? 'blue' : 'grey'};
color: white;
padding: 10px 20px;
`;
// Emotion
const buttonStyle = css`
background-color: blue;
color: white;
padding: 10px 20px;
`;
<button css={buttonStyle}>Click Me</button>
Styled Components 为什么有性能问题?
运行时生成样式:每次渲染根据 props 动态生成 CSS,插入 style 标签。
重复类名:相同样式可能生成多份,增加 CSSOM 复杂度。
SSR 开销:服务端需生成并注入样式。
无法缓存:动态样式难以被浏览器缓存。
重复类名:相同样式可能生成多份,增加 CSSOM 复杂度。
SSR 开销:服务端需生成并注入样式。
无法缓存:动态样式难以被浏览器缓存。
优化:减少动态 props、用 React.memo、避免 render 内创建 styled、考虑零运行时方案(Linaria、vanilla-extract)。
CSS-in-JS 解决了什么问题?
① 局部作用域,避免全局污染 ② 动态样式,直接用 JS 变量 ③ 样式与组件封装 ④ 按需生成,无冗余 ⑤ 支持 SSR。
4 Flex 布局
容器和项目、主轴和交叉轴
容器:
主轴:main axis,由
display: flex 的元素;项目:容器的直接子元素。主轴:main axis,由
flex-direction 决定(默认水平);交叉轴:cross axis,垂直于主轴。
容器属性:flex-direction、flex-wrap、flex-flow、justify-content、align-items、align-content
项目属性:order、flex-grow、flex-shrink、flex-basis、flex、align-self
flex-grow、flex-shrink、flex-basis
flex-grow:放大比例,默认 0。都为 1 时等分剩余空间;2 的占两倍。
flex-shrink:缩小比例,默认 1。空间不足时按比例缩小;0 则不缩小。
flex-basis:初始大小,默认 auto。
flex-shrink:缩小比例,默认 1。空间不足时按比例缩小;0 则不缩小。
flex-basis:初始大小,默认 auto。
flex: 1 等价于 flex-grow: 1; flex-shrink: 1; flex-basis: 0%;
5 防全局污染方案
各方案如何避免样式冲突?
命名空间/BEM:类名前缀、Block__Element--Modifier,靠规范。
CSS Modules:编译时类名 hash,天然隔离。
Scoped CSS(Vue):自动加 data 属性,限制在当前组件。
Shadow DOM:完全隔离,内外互不影响。
CSS-in-JS:自动生成唯一类名,局部作用域。
CSS Modules:编译时类名 hash,天然隔离。
Scoped CSS(Vue):自动加 data 属性,限制在当前组件。
Shadow DOM:完全隔离,内外互不影响。
CSS-in-JS:自动生成唯一类名,局部作用域。
/* BEM 示例 */
.button {} /* Block */
.button__icon {} /* Element */
.button--primary {} /* Modifier */
Ant Design 如何处理全局类名污染?
BEM + ant- 前缀:类名如
Less 变量定制:通过修改变量统一改主题,少直接覆盖类。
按需加载:只引入用到的组件样式。
部分组件用 @emotion/css:按需动态生成样式。
ant-btn ant-btn-primary,降低冲突。Less 变量定制:通过修改变量统一改主题,少直接覆盖类。
按需加载:只引入用到的组件样式。
部分组件用 @emotion/css:按需动态生成样式。