第14章: CSS架构和最佳实践
🎯 本章重点
- 现代CSS架构方法论
- 组件化CSS开发
- 性能优化技巧
- 可维护性和可扩展性
- 团队协作规范
📖 内容概述
14.1 CSS架构方法论
14.1.1 BEM (Block Element Modifier)
/* BEM 命名规范 */
.block { } /* 块 */
.block__element { } /* 元素 */
.block--modifier { } /* 修饰符 */
/* 实际应用示例 */
.card { } /* 卡片块 */
.card__header { } /* 卡片头部元素 */
.card__title { } /* 卡片标题元素 */
.card__body { } /* 卡片主体元素 */
.card__footer { } /* 卡片底部元素 */
.card--featured { } /* 特色卡片修饰符 */
.card--disabled { } /* 禁用卡片修饰符 */
/* 复杂组件示例 */
.accordion { }
.accordion__item { }
.accordion__item--active { }
.accordion__header { }
.accordion__content { }
.accordion__icon { }
.accordion__icon--expanded { }
/* 表单组件 */
.form { }
.form__group { }
.form__label { }
.form__input { }
.form__input--error { }
.form__error { }
.form__submit { }
.form__submit--loading { }
/* 响应式BEM */
@media (min-width: 768px) {
.card--desktop { }
.card__header--desktop { }
}
/* JavaScript交互类 */
.card--js-active { }
.accordion--js-initialized { }
14.1.2 SMACSS (可扩展和模块化CSS架构)
/* SMACSS 分类 */
/* 基础规则 */
html, body, h1, h2, h3, p { }
/* 布局规则 */
.l-header { }
.l-main { }
.l-sidebar { }
.l-grid { }
/* 模块规则 */
.module { }
.module-title { }
.module-content { }
/* 状态规则 */
.is-hidden { }
.is-active { }
.is-loading { }
.is-error { }
/* 主题规则 */
.theme-dark { }
.theme-light { }
/* 实际应用示例 */
/* 布局类 */
.layout { }
.layout--with-sidebar { }
.layout__header { }
.layout__main { }
.layout__sidebar { }
/* 状态类 */
.state-hidden { display: none; }
.state-visible { display: block; }
.state-active { background-color: #007bff; color: white; }
.state-disabled { opacity: 0.5; pointer-events: none; }
/* 主题切换 */
.theme-default { }
.theme-dark {
--bg-primary: #1a1a1a;
--text-primary: #ffffff;
}
.theme-high-contrast {
--bg-primary: #000000;
--text-primary: #ffffff;
}
14.1.3 ITCSS (倒三角形CSS)
/* ITCSS 层次结构 */
/* 1. Settings - 变量和配置 */
:root {
--color-primary: #007bff;
--spacing-unit: 1rem;
}
/* 2. Tools - 混合和函数 */
@mixin responsive($breakpoint) { }
@function spacing($multiplier) { }
/* 3. Generic - 重置和标准化 */
* { box-sizing: border-box; }
/* 4. Elements - 基础HTML元素 */
h1, h2, h3 { }
a { }
/* 5. Objects - 布局和结构 */
.o-container { }
.o-grid { }
/* 6. Components - 具体组件 */
.c-button { }
.c-card { }
/* 7. Utilities - 辅助类 */
.u-hidden { }
.u-text-center { }
/* 实际文件结构示例 */
/* settings/_colors.css */
:root {
--color-primary: #007bff;
--color-secondary: #6c757d;
}
/* settings/_spacing.css */
:root {
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
}
/* tools/_mixins.css */
@mixin respond-to($breakpoint) {
@media (min-width: $breakpoint) {
@content;
}
}
/* generic/_reset.css */
* { margin: 0; padding: 0; box-sizing: border-box; }
/* elements/_typography.css */
h1 { font-size: 2rem; }
p { line-height: 1.6; }
/* objects/_layout.css */
.o-container { max-width: 1200px; margin: 0 auto; }
/* components/_button.css */
.c-button { padding: 0.5rem 1rem; border: none; }
/* utilities/_display.css */
.u-hidden { display: none; }
.u-block { display: block; }
14.1.4 Atomic CSS / 功能类优先
/* 原子CSS类 */
/* 间距 */
.m-0 { margin: 0; }
.m-1 { margin: 0.25rem; }
.m-2 { margin: 0.5rem; }
.p-0 { padding: 0; }
.p-1 { padding: 0.25rem; }
.p-2 { padding: 0.5rem; }
/* 布局 */
.flex { display: flex; }
.grid { display: grid; }
.block { display: block; }
/* 对齐 */
.items-center { align-items: center; }
.justify-center { justify-content: center; }
/* 颜色 */
.text-primary { color: #007bff; }
.bg-white { background-color: white; }
/* 响应式前缀 */
.md\:flex { }
.lg\:hidden { }
/* 实际应用示例 */
<!-- 传统CSS -->
<div class="card featured-card">
<h3 class="card-title">标题</h3>
</div>
<!-- 原子CSS -->
<div class="p-4 bg-white rounded shadow flex flex-col">
<h3 class="text-lg font-bold mb-2">标题</h3>
</div>
/* 自定义原子类系统 */
/* 间距系统 */
.space-x-1 > * + * { margin-left: 0.25rem; }
.space-y-2 > * + * { margin-top: 0.5rem; }
/* 颜色系统 */
.text-primary-500 { color: #007bff; }
.bg-primary-100 { background-color: #d1edff; }
/* 响应式系统 */
@media (min-width: 768px) {
.md\:flex-row { flex-direction: row; }
.md\:space-x-4 > * + * { margin-left: 1rem; }
}
/* 组合使用 */
.component {
composes: p-4 bg-white rounded from global;
composes: flex flex-col space-y-3 from global;
}
14.2 组件化CSS开发
14.2.1 CSS模块化
/* 组件样式隔离 */
/* Button.module.css */
.button {
padding: 0.5rem 1rem;
border: none;
border-radius: 0.25rem;
}
.primary {
composes: button;
background-color: #007bff;
color: white;
}
.secondary {
composes: button;
background-color: #6c757d;
color: white;
}
/* Card.module.css */
.card {
background: white;
border-radius: 0.5rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.header {
padding: 1rem;
border-bottom: 1px solid #eee;
}
.body {
padding: 1rem;
}
/* 实际React/Vue组件使用 */
// React组件
import styles from './Button.module.css';
function Button({ variant = 'primary', children }) {
return (
<button className={styles[variant]}>
{children}
</button>
);
}
// Vue组件
<template>
<button :class="[$style.button, $style[variant]]">
<slot></slot>
</button>
</template>
<style module>
.button { /* 基础样式 */ }
.primary { /* 主要样式 */ }
.secondary { /* 次要样式 */ }
</style>
14.2.2 CSS-in-JS
/* Styled Components 示例 */
import styled from 'styled-components';
// 基础按钮组件
const Button = styled.button`
padding: 0.5rem 1rem;
border: none;
border-radius: 0.25rem;
cursor: pointer;
transition: all 0.3s ease;
/* 变体支持 */
${props => props.primary && `
background-color: #007bff;
color: white;
`}
${props => props.secondary && `
background-color: #6c757d;
color: white;
`}
/* 响应式设计 */
@media (max-width: 768px) {
padding: 0.75rem 1.5rem;
font-size: 1.1rem;
}
/* 交互状态 */
&:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
&:active {
transform: translateY(0);
}
/* 禁用状态 */
&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
`;
// 扩展组件
const IconButton = styled(Button)`
display: inline-flex;
align-items: center;
gap: 0.5rem;
svg {
width: 1rem;
height: 1rem;
}
`;
// 主题支持
const ThemedButton = styled(Button)`
background-color: ${props => props.theme.primary};
color: ${props => props.theme.text};
&:hover {
background-color: ${props => props.theme.primaryDark};
}
`;
14.2.3 设计令牌系统
/* 设计令牌定义 */
:root {
/* 颜色系统 */
--color-primary-50: #e3f2fd;
--color-primary-100: #bbdefb;
--color-primary-500: #2196f3;
--color-primary-900: #0d47a1;
/* 间距系统 */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
/* 字体系统 */
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
/* 边框圆角 */
--border-radius-sm: 0.125rem;
--border-radius-md: 0.25rem;
--border-radius-lg: 0.5rem;
/* 阴影系统 */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
/* 语义化令牌 */
:root {
/* 语义化颜色 */
--color-background: var(--color-white);
--color-text: var(--color-gray-900);
--color-primary: var(--color-blue-500);
/* 语义化间距 */
--spacing-container: var(--spacing-md);
--spacing-section: var(--spacing-xl);
/* 语义化字体 */
--font-body: var(--font-size-base);
--font-heading: var(--font-size-xl);
}
/* 主题切换 */
[data-theme="dark"] {
--color-background: var(--color-gray-900);
--color-text: var(--color-white);
--color-primary: var(--color-blue-300);
}
[data-theme="high-contrast"] {
--color-background: var(--color-black);
--color-text: var(--color-white);
--color-primary: var(--color-yellow-500);
}
/* 组件使用设计令牌 */
.button {
background-color: var(--color-primary);
color: var(--color-text-on-primary);
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--border-radius-md);
font-size: var(--font-body);
}
.card {
background-color: var(--color-background);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-md);
padding: var(--spacing-container);
}
14.3 性能优化技巧
14.3.1 CSS选择器性能
/* 高效选择器 */
/* 好 - 类选择器 */
.button { }
.nav-item { }
/* 好 - ID选择器 */
#header { }
/* 一般 - 标签选择器 */
div { }
a { }
/* 差 - 通用选择器 */
* { }
/* 差 - 属性选择器 */
[data-type="button"] { }
/* 差 - 后代选择器 */
.container div { }
/* 选择器优化技巧 */
/* 避免过度具体的选择器 */
/* 差 */
body div.container ul.nav li a.button { }
/* 好 */
.nav-link { }
/* 使用类而不是标签 */
/* 差 */
div.card { }
/* 好 */
.card { }
/* 避免通用选择器 */
/* 差 */
* { margin: 0; padding: 0; }
/* 好 */
html, body, div, span, h1, h2, h3, p {
margin: 0;
padding: 0;
}
/* 性能测试工具使用 */
/* 使用浏览器开发者工具测试选择器性能 */
/* 在Chrome DevTools中检查Recalc Style时间 */
/* 实际优化示例 */
/* 优化前 */
.sidebar .navigation .menu .item a.link {
color: blue;
}
/* 优化后 */
.nav-link {
color: blue;
}
/* 复杂选择器分解 */
/* 优化前 */
.form input[type="text"],
.form input[type="email"],
.form textarea {
border: 1px solid #ccc;
}
/* 优化后 */
.form-control {
border: 1px solid #ccc;
}
/* 或者使用类组合 */
.input-text,
.input-email,
.textarea {
border: 1px solid #ccc;
}
14.3.2 文件组织和加载优化
/* 文件分割策略 */
/* main.css - 核心样式 */
@import "base/reset.css";
@import "base/typography.css";
@import "layout/grid.css";
/* components.css - 组件样式 */
@import "components/button.css";
@import "components/card.css";
/* utilities.css - 工具类 */
@import "utilities/spacing.css";
@import "utilities/display.css";
/* 条件加载 */
/* 使用媒体查询加载 */
<link rel="stylesheet" href="mobile.css" media="(max-width: 768px)">
<link rel="stylesheet" href="desktop.css" media="(min-width: 769px)">
/* 关键CSS内联 */
<style>
/* 关键CSS - 首屏内容 */
.header { }
.hero { }
.navigation { }
</style>
/* 非关键CSS异步加载 */
<link rel="preload" href="non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
/* CSS压缩和优化 */
/* 使用工具进行压缩 */
/* 原始CSS */
.button {
background-color: #007bff;
color: white;
padding: 10px 20px;
border-radius: 5px;
}
/* 压缩后 */
.button{background-color:#007bff;color:#fff;padding:10px 20px;border-radius:5px}
/* 使用PostCSS优化 */
/* postcss.config.js */
module.exports = {
plugins: [
require('autoprefixer'),
require('cssnano')({
preset: 'default',
})
]
}
/* 实际构建配置示例 */
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1
}
},
'postcss-loader'
]
}
]
}
};
14.3.3 渲染性能优化
/* 减少重排和重绘 */
/* 使用transform代替top/left */
/* 差 */
.animate {
position: absolute;
left: 100px;
top: 100px;
transition: left 0.3s, top 0.3s;
}
.animate.move {
left: 200px;
top: 200px;
}
/* 好 */
.animate {
position: absolute;
left: 100px;
top: 100px;
transition: transform 0.3s;
}
.animate.move {
transform: translate(100px, 100px);
}
/* 使用will-change优化动画 */
.animated-element {
will-change: transform, opacity;
transition: transform 0.3s, opacity 0.3s;
}
/* 硬件加速优化 */
.accelerated {
transform: translateZ(0);
backface-visibility: hidden;
}
/* 图片优化 */
.lazy-image {
opacity: 0;
transition: opacity 0.3s;
}
.lazy-image.loaded {
opacity: 1;
}
/* 字体加载优化 */
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2'),
url('font.woff') format('woff');
font-display: swap; /* 显示后备字体 */
}
/* 实际性能优化示例 */
/* 滚动性能优化 */
.sticky-header {
position: sticky;
top: 0;
/* 启用硬件加速 */
transform: translateZ(0);
will-change: transform;
}
/* 图片懒加载优化 */
.lazy-container {
position: relative;
overflow: hidden;
}
.lazy-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
/* 优化加载 */
loading: lazy;
decoding: async;
}
/* 动画性能优化 */
@keyframes slideIn {
from {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.animate-in {
animation: slideIn 0.5s cubic-bezier(0.4, 0, 0.2, 1);
/* 优化属性 */
will-change: transform, opacity;
}
14.4 可维护性和可扩展性
14.4.1 代码组织规范
/* CSS文件组织结构 */
styles/
├── base/ /* 基础样式 */
│ ├── reset.css
│ ├── typography.css
│ └── variables.css
├── components/ /* 组件样式 */
│ ├── button.css
│ ├── card.css
│ └── form.css
├── layout/ /* 布局样式 */
│ ├── grid.css
│ ├── header.css
│ └── footer.css
├── utilities/ /* 工具类 */
│ ├── spacing.css
│ ├── display.css
│ └── text.css
└── themes/ /* 主题样式 */
├── dark.css
└── light.css
/* 代码注释规范 */
/**
* 按钮组件
*
* 使用示例:
* <button class="btn btn--primary">主要按钮</button>
*
* 变体:
* - .btn--primary 主要按钮
* - .btn--secondary 次要按钮
* - .btn--large 大号按钮
*/
.btn {
/* 基础样式 */
display: inline-flex;
align-items: center;
justify-content: center;
/* 间距 */
padding: 0.5rem 1rem;
/* 边框和圆角 */
border: 1px solid transparent;
border-radius: 0.25rem;
/* 文本 */
font-size: 1rem;
line-height: 1.5;
text-decoration: none;
/* 交互 */
cursor: pointer;
transition: all 0.2s ease;
}
/* 主要按钮变体 */
.btn--primary {
background-color: #007bff;
color: white;
/* 悬停状态 */
&:hover {
background-color: #0056b3;
}
}
/* 命名约定文档 */
/*
命名约定:
- 组件:.component
- 元素:.component__element
- 修饰符:.component--modifier
- 工具类:.u-utility
- JavaScript钩子:.js-hook
- 状态:.is-state
*/
14.4.2 团队协作规范
/* CSS样式指南 */
/* 1. 格式化规则 */
/* 使用2空格缩进 */
.selector {
property: value;
}
/* 每行一个声明 */
.selector {
margin: 0;
padding: 1rem;
color: #333;
}
/* 2. 命名约定 */
/* 使用kebab-case */
.main-navigation { } /* 好 */
.mainNavigation { } /* 差 */
/* 3. 属性顺序 */
.selector {
/* 定位 */
position: absolute;
top: 0;
left: 0;
z-index: 10;
/* 盒模型 */
display: block;
width: 100%;
height: 100%;
margin: 0;
padding: 1rem;
border: 1px solid #ccc;
/* 文本 */
font-family: Arial, sans-serif;
font-size: 1rem;
color: #333;
text-align: center;
/* 视觉 */
background-color: white;
border-radius: 0.25rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
/* 动画 */
transition: all 0.3s ease;
}
/* 4. 响应式设计规范 */
/* 移动优先 */
.component {
/* 移动端样式 */
padding: 1rem;
/* 平板端 */
@media (min-width: 768px) {
padding: 2rem;
}
/* 桌面端 */
@media (min-width: 1024px) {
padding: 3rem;
}
}
/* 5. 变量使用规范 */
:root {
/* 颜色变量 */
--color-primary: #007bff;
--color-secondary: #6c757d;
/* 间距变量 */
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
}
.component {
color: var(--color-primary);
padding: var(--spacing-md);
}
/* 6. 代码审查清单 */
/*
代码审查清单:
- [ ] 选择器是否高效?
- [ ] 命名是否语义化?
- [ ] 是否有重复代码?
- [ ] 响应式设计是否正确?
- [ ] 可访问性是否考虑?
- [ ] 浏览器兼容性如何?
*/
💡 架构和最佳实践总结
- 架构方法论: 选择合适的CSS架构(BEM、SMACSS、ITCSS等)
- 组件化开发: 使用CSS模块化或CSS-in-JS实现组件隔离
- 性能优化: 优化选择器、文件加载和渲染性能
- 可维护性: 建立清晰的代码组织和团队规范
- 设计系统: 使用设计令牌确保一致性
- 团队协作: 制定统一的编码标准和审查流程
通过遵循这些最佳实践,可以创建出可维护、高性能且易于团队协作的CSS代码库。