CSS 命名、主题、变量、避免深度选择器
- Standard:项目统一使用 BEM(Block Element Modifier)命名法,或 CSS Modules(类名哈希化)。二选一,项目内保持一致。
- Requirement:类名使用小写字母 + 连字符(kebab-case),禁止使用驼峰或下划线(CSS Modules 除外)。
/* Block:组件名 */
.user-card { }
/* Element:组件内元素,用双下划线连接 */
.user-card__header { }
.user-card__avatar { }
.user-card__name { }
/* Modifier:状态或变体,用双连字符连接 */
.user-card--active { }
.user-card__name--highlight { }
- Requirement:Block 名必须具有语义,禁止使用
.box、.item、.content 等无意义名称。
- Standard:Modifier 表示状态时,使用
is- 前缀作为辅助类,如 .is-active、.is-disabled。
- Default:React 项目优先使用 CSS Modules,类名使用 camelCase,编译后自动哈希避免冲突。
/* UserCard.module.css */
.userCard { }
.userCardHeader { }
.userCardAvatar { }
.isActive { }
import styles from './UserCard.module.css';
<div className={`${styles.userCard} ${isActive ? styles.isActive : ''}`}>
<div className={styles.userCardHeader}>...</div>
</div>
| 反模式 | 问题 | 建议 |
|---|
类名 .a、.b、.c | 完全无意义 | 使用语义化名称 |
| 混用 kebab-case 和 camelCase | 风格不统一 | 项目内统一一种风格 |
.item .content .text 嵌套命名 | 无法独立使用 | 使用 BEM 扁平化命名 |
- Standard:使用 CSS 自定义属性(CSS Variables)实现主题切换,支持运行时动态切换。
- Requirement:颜色、字号、间距、圆角等设计 Token 必须使用 CSS 变量,禁止硬编码。
:root {
/* 颜色 */
--color-primary: #1677ff;
--color-success: #52c41a;
--color-warning: #faad14;
--color-danger: #ff4d4f;
--color-text-primary: rgba(0, 0, 0, 0.88);
--color-text-secondary: rgba(0, 0, 0, 0.65);
--color-bg: #ffffff;
--color-border: #d9d9d9;
/* 字号 */
--font-size-xs: 12px;
--font-size-sm: 13px;
--font-size-base: 14px;
--font-size-lg: 16px;
--font-size-xl: 20px;
/* 间距 */
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--spacing-xl: 32px;
/* 圆角 */
--radius-sm: 4px;
--radius-md: 6px;
--radius-lg: 8px;
}
/* 暗色主题 */
[data-theme='dark'] {
--color-primary: #4096ff;
--color-text-primary: rgba(255, 255, 255, 0.88);
--color-bg: #141414;
--color-border: #434343;
}
// 切换主题
function setTheme(theme: 'light' | 'dark') {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
}
- Standard:组件样式中只引用 CSS 变量,不直接写颜色值,确保主题切换生效。
- Caution:新增颜色 Token 必须同步更新浅色和暗色两套主题值。
| 反模式 | 问题 | 建议 |
|---|
组件内硬编码颜色 #1677ff | 主题切换不生效 | 使用 var(--color-primary) |
| 颜色值散落各处 | 难以统一修改 | 集中定义在 styles/variables.css |
| 暗色主题只改背景不改文字 | 对比度不足 | 完整定义暗色变量 |
- Standard:样式变量分为三类:
- 全局变量:
src/styles/variables.css,定义设计 Token(颜色、字号、间距等)
- 组件变量:组件级 CSS 变量,允许外部覆盖
- 临时变量:
@apply 或 SCSS 变量,仅在当前文件内使用
- Standard:需要运行时动态修改的用 CSS 变量,仅编译时使用的用 SCSS 变量。
- Caution:禁止在组件内重复定义已存在的全局变量,统一引用全局变量。
- Standard:组件允许通过 CSS 变量实现外部定制,变量名以组件名为前缀。
.user-card {
--user-card-padding: var(--spacing-md);
--user-card-radius: var(--radius-md);
padding: var(--user-card-padding);
border-radius: var(--user-card-radius);
}
/* 外部覆盖 */
.user-card--large {
--user-card-padding: var(--spacing-lg);
}
| 反模式 | 问题 | 建议 |
|---|
| 全局变量重复定义 | 值不一致 | 统一定义在 variables.css |
| 用 SCSS 变量存主题色 | 无法运行时切换 | 用 CSS 变量 |
| 变量命名无前缀 | 命名冲突 | 全局变量 --color-*,组件变量 --组件名-* |
- Requirement:禁止使用深度选择器(
::v-deep、/deep/、>>>)覆盖第三方组件样式,除非无法通过官方 API 定制。
- Caution:如必须使用深度选择器,必须加注释说明原因,并限制在组件根类作用域内。
/* ❌ 反模式:无限制深度覆盖 */
::v-deep .ant-btn {
color: red;
}
/* ✅ 正确:限定作用域并注释 */
.user-form {
/* antd 表单按钮无法通过 props 定制,需深度覆盖 */
:deep(.ant-btn-primary) {
background: var(--color-primary);
}
}
- Standard:选择器嵌套层级不超过 3 层,超过时考虑使用类名直接选择。
- Requirement:禁止使用
!important,除非覆盖内联样式或第三方无法移除的样式。
/* ❌ 反模式:层级过深 */
.page .content .list .item .title { color: red; }
/* ✅ 正确:扁平化 */
.list-item__title { color: red; }
- Caution:避免使用标签选择器(
div、span),优先使用类名选择器,避免样式污染。
/* ❌ 反模式 */
.user-card div { margin-top: 8px; }
/* ✅ 正确 */
.user-card__body { margin-top: 8px; }
| 反模式 | 问题 | 建议 |
|---|
::v-deep 无限制使用 | 样式污染、难以维护 | 限定作用域并注释 |
| 嵌套超过 4 层 | 权重过高、难以覆盖 | 扁平化类名 |
滥用 !important | 破坏样式优先级 | 用更高权重的选择器 |
| 标签选择器 | 影响范围不可控 | 改用类名选择器 |
- Standard:避免使用触发重排(reflow)的属性作为动画属性(
width、height、top、left),优先使用 transform 和 opacity。
- Standard:动画使用
will-change 提示浏览器提前优化,但禁止滥用,仅在确实有动画的元素上使用。
/* ❌ 反模式:用 top 做动画,触发重排 */
.modal {
transition: top 0.3s;
top: -100%;
}
.modal.active { top: 0; }
/* ✅ 正确:用 transform 做动画,只触发重绘 */
.modal {
transition: transform 0.3s;
transform: translateY(-100%);
}
.modal.active { transform: translateY(0); }
- Standard:避免使用通配符选择器
* 和属性选择器 [type="text"],优先使用类名选择器。
- Standard:后代选择器比子代选择器慢,优先使用子代选择器
> 或直接类名。
- Standard:图片使用
background-image 时,大图片提供多倍图适配 Retina 屏幕。
- Suggestion:使用
contain: layout paint 或 content-visibility: auto 优化长列表渲染性能。
| 反模式 | 问题 | 建议 |
|---|
用 width/top 做动画 | 频繁重排,卡顿 | 用 transform/opacity |
全局 * { box-sizing: border-box } | 选择器性能差 | 用 *, *::before, *::after 且仅在 reset 中用 |
无意义的 will-change: all | 占用内存 | 只声明需要的属性 |