Skip to content
On this page

CSS 最佳实践

CSS 最佳实践是编写高质量、可维护和可扩展的 CSS 代码的指导原则。

概述

CSS 最佳实践涵盖了从代码组织到性能优化的各个方面,帮助开发者编写更优秀的样式代码。

代码组织

文件结构

styles/
├── base/
│   ├── _reset.scss      # 重置样式
│   ├── _typography.scss # 字体样式
│   └── _helpers.scss    # 辅助类
├── components/
│   ├── _buttons.scss    # 按钮组件
│   ├── _cards.scss      # 卡片组件
│   └── _forms.scss      # 表单组件
├── layout/
│   ├── _header.scss     # 页头布局
│   ├── _navigation.scss # 导航布局
│   └── _footer.scss     # 页脚布局
├── pages/
│   ├── _home.scss       # 首页样式
│   └── _about.scss      # 关于页面样式
├── themes/
│   └── _dark.scss       # 深色主题
├── abstracts/
│   ├── _variables.scss  # 变量定义
│   ├── _mixins.scss     # 混合宏
│   └── _functions.scss  # 函数定义
└── main.scss            # 主文件,导入所有样式

主文件组织

scss
// main.scss - 按照逻辑顺序导入
// 1. 抽象层 - 变量、混合宏、函数
@import "abstracts/variables";
@import "abstracts/mixins";
@import "abstracts/functions";

// 2. 基础层 - 重置、基础样式
@import "base/reset";
@import "base/typography";
@import "base/helpers";

// 3. 布局层 - 页面布局
@import "layout/header";
@import "layout/navigation";
@import "layout/footer";

// 4. 组件层 - 可复用组件
@import "components/buttons";
@import "components/cards";
@import "components/forms";

// 5. 页面层 - 特定页面样式
@import "pages/home";
@import "pages/about";

// 6. 主题层 - 主题样式
@import "themes/dark";

命名约定

BEM 方法论

css
/* 块 (Block) */
.card { }

/* 元素 (Element) */
.card__header { }
.card__body { }
.card__footer { }

/* 修饰符 (Modifier) */
.card--featured { }
.card__button--primary { }
.card__button--secondary { }

/* 复杂示例 */
.nav {
  /* 导航块 */
}

.nav__list {
  /* 导航列表元素 */
}

.nav__item {
  /* 导航项目元素 */
}

.nav__link {
  /* 导航链接元素 */
}

.nav__link--active {
  /* 活跃状态的导航链接修饰符 */
}

.nav--horizontal {
  /* 水平导航修饰符 */
}

语义化命名

css
/* 好的命名 - 描述功能 */
.navigation { }
.article-content { }
.user-avatar { }
.search-form { }
.main-content { }

/* 避免的命名 - 描述外观 */
.red-text { }
.big-box { }
.left-blue { }

/* 推荐 - 结合功能和外观 */
.btn-primary { }
.text-large { }
.icon-menu { }

选择器优化

避免深层嵌套

scss
// 不推荐:过度嵌套
.product-card {
  .product-image {
    .image-container {
      .image-wrapper {
        img {
          width: 100%;
        }
      }
    }
  }
}

// 推荐:扁平化结构
.product-card { }
.product-image { }
.product-image-container { }
.product-image-wrapper { }
.product-image img { }

限制选择器深度

css
/* 不推荐:过深的层级 */
.main-content .container .article .header .title {
  color: #333;
}

/* 推荐:最多3层 */
.article .header .title {
  color: #333;
}

/* 更好:使用类名 */
.article-title {
  color: #333;
}

CSS 架构方法论

OOCSS (Object-Oriented CSS)

css
/* 结构与皮肤分离 */
.media {
  display: flex;
  align-items: flex-start;
}

.media-object {
  margin-right: 10px;
}

.media-body {
  flex: 1;
}

/* 皮肤 */
.btn {
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.btn-primary {
  background-color: #007bff;
  color: white;
}

.btn-secondary {
  background-color: #6c757d;
  color: white;
}

SMACSS (Scalable and Modular Architecture)

css
/* Base - 基础样式 */
* { box-sizing: border-box; }
body { font-family: Arial, sans-serif; }

/* Layout - 布局样式 */
.l-header { }
.l-sidebar { }
.l-main { }

/* Module - 模块样式 */
.nav { }
.nav-item { }
.nav-link { }

/* State - 状态样式 */
.is-active { }
.is-hidden { }
.is-loading { }

/* Theme - 主题样式 */
.theme-dark { }
.theme-light { }

变量和常量

CSS 自定义属性

css
:root {
  /* 颜色变量 */
  --color-primary: #007bff;
  --color-secondary: #6c757d;
  --color-success: #28a745;
  --color-danger: #dc3545;
  
  /* 尺寸变量 */
  --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: 0.25rem;
  --border-width: 1px;
  
  /* 阴影变量 */
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
  --shadow: 0 1px 3px rgba(0,0,0,0.1);
  --shadow-lg: 0 1px 8px rgba(0,0,0,0.2);
}

/* 使用变量 */
.button {
  background-color: var(--color-primary);
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--border-radius);
  font-size: var(--font-size-base);
}

预处理器变量

scss
// _variables.scss
// 颜色
$primary-color: #007bff;
$secondary-color: #6c757d;
$success-color: #28a745;
$danger-color: #dc3545;
$warning-color: #ffc107;
$info-color: #17a2b8;

// 间距
$spacer: 1rem;
$spacers: (
  0: 0,
  1: $spacer * 0.25,
  2: $spacer * 0.5,
  3: $spacer,
  4: $spacer * 1.5,
  5: $spacer * 3,
);

// 断点
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;

// 字体
$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
$font-size-base: 1rem;
$line-height-base: 1.5;

响应式设计最佳实践

移动优先方法

css
/* 基础样式 - 移动设备 */
.grid {
  display: flex;
  flex-direction: column;
}

.grid-item {
  width: 100%;
  margin-bottom: 1rem;
}

/* 平板及以上 */
@media (min-width: 768px) {
  .grid {
    flex-direction: row;
    flex-wrap: wrap;
  }
  
  .grid-item {
    width: calc(50% - 0.5rem);
    margin-bottom: 0;
    margin-right: 1rem;
  }
  
  .grid-item:nth-child(2n) {
    margin-right: 0;
  }
}

/* 桌面设备 */
@media (min-width: 1024px) {
  .grid-item {
    width: calc(33.333% - 0.667rem);
  }
  
  .grid-item:nth-child(2n) {
    margin-right: 1rem; /* 恢复间距 */
  }
  
  .grid-item:nth-child(3n) {
    margin-right: 0;
  }
}

断点管理

scss
// _breakpoints.scss
$breakpoints: (
  'xs': 0,
  'sm': 576px,
  'md': 768px,
  'lg': 992px,
  'xl': 1200px,
  'xxl': 1400px
);

// 混合宏
@mixin respond-to($breakpoint) {
  @if map-has-key($breakpoints, $breakpoint) {
    @media (min-width: map-get($breakpoints, $breakpoint)) {
      @content;
    }
  }
}

// 使用混合宏
.card {
  padding: 1rem;
  
  @include respond-to(md) {
    padding: 2rem;
  }
  
  @include respond-to(lg) {
    padding: 3rem;
  }
}

性能优化

关键渲染路径优化

css
/* 关键CSS内联到HTML头部 */
<style>
  /* 首屏必需的样式 */
  .header { height: 60px; background: #fff; }
  .hero { height: 400px; background: #f8f9fa; }
  .nav { display: flex; }
</style>

/* 非关键CSS异步加载 */
<link rel="preload" href="non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">

避免昂贵的CSS属性

css
/* 推荐:高性能属性 */
.performant {
  transform: translateX(100px);
  opacity: 0.8;
  will-change: transform;
}

/* 避免:可能引起重排的属性 */
.expensive {
  width: 100px; /* 可能触发重排 */
  height: 100px; /* 可能触发重排 */
  margin: 10px; /* 可能触发重排 */
  padding: 10px; /* 可能触发重排 */
  top: 10px; /* 可能触发重排 */
}

可维护性

组件化开发

scss
// _buttons.scss
// 按钮基础样式
%btn-base {
  display: inline-block;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 0.25rem;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: all 0.2s ease;
}

// 按钮变体
.btn-primary {
  @extend %btn-base;
  background-color: $primary-color;
  color: white;
  
  &:hover {
    background-color: darken($primary-color, 10%);
  }
  
  &:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
}

.btn-secondary {
  @extend %btn-base;
  background-color: $secondary-color;
  color: white;
}

注释规范

css
/*
 * 组件:卡片
 * 用途:显示内容摘要的卡片组件
 * 状态:active, featured, disabled
 */

/* 卡片容器 */
.card {
  /* 基础卡片样式 */
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

/* 
 * 卡片头部
 * 通常包含标题和副标题
 */
.card__header {
  padding: 1rem;
  border-bottom: 1px solid #e0e0e0;
}

/*
 * 修饰符:特色卡片
 * 使用方式:<div class="card card--featured">
 */
.card--featured {
  border-color: #007bff;
  box-shadow: 0 4px 8px rgba(0,123,255,0.2);
}

可访问性

无障碍最佳实践

css
/* 焦点管理 */
.focusable {
  outline: 2px solid #007cba;
  outline-offset: 2px;
}

.focusable:focus {
  outline: 2px solid #007cba;
  outline-offset: 2px;
}

/* 颜色对比度 */
.text-content {
  color: #212121; /* 深色文本 */
  background-color: #ffffff; /* 浅色背景 */
  /* 对比度 13.4:1,符合AA标准 */
}

/* 尊重用户偏好 */
@media (prefers-reduced-motion: reduce) {
  .animated-element {
    animation: none;
    transition: none;
  }
}

/* 高对比度模式支持 */
@media (prefers-contrast: high) {
  .element {
    border: 2px solid;
  }
}

/* 深色模式支持 */
@media (prefers-color-scheme: dark) {
  body {
    background-color: #1a1a1a;
    color: #ffffff;
  }
}

实用技巧

CSS Grid 和 Flexbox 选择

css
/* 使用 Flexbox 的场景 - 一维布局 */
.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* 使用 Grid 的场景 - 二维布局 */
.dashboard {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto 1fr auto;
  grid-template-areas: 
    "header header header"
    "sidebar main aside"
    "footer footer footer";
  height: 100vh;
}

现代CSS特性

css
/* 使用 CSS 自定义属性实现主题切换 */
:root {
  --bg-color: #ffffff;
  --text-color: #333333;
}

[data-theme="dark"] {
  --bg-color: #1a1a1a;
  --text-color: #ffffff;
}

.body {
  background-color: var(--bg-color);
  color: var(--text-color);
  transition: background-color 0.3s ease, color 0.3s ease;
}

/* 使用 clamp() 实现流体排版 */
.responsive-text {
  font-size: clamp(1rem, 2.5vw, 2rem);
  /* 最小值,首选值,最大值 */
}

/* 使用 :not() 减少嵌套 */
.card:not(.card--featured) {
  border: 1px solid #e0e0e0;
}

/* 使用 :is() 减少重复 */
:is(h1, h2, h3):not(.special) {
  margin-bottom: 1rem;
}

代码质量

代码审查清单

css
/* ✅ 好的做法 */
.well-structured {
  /* 使用语义化类名 */
  /* 遵循命名约定 */
  /* 适当的注释 */
  /* 避免过深嵌套 */
  /* 使用相对单位 */
  /* 考虑可访问性 */
  /* 优化性能 */
}

工具集成

json
// .stylelintrc.json
{
  "extends": ["stylelint-config-standard"],
  "rules": {
    "indentation": 2,
    "string-quotes": "single",
    "no-duplicate-selectors": true,
    "color-hex-case": "lower",
    "color-hex-length": "short"
  }
}

最佳实践总结

  • 使用一致的命名约定(如BEM)
  • 保持选择器简短高效
  • 合理组织文件结构
  • 使用预处理器提高可维护性
  • 考虑性能和可访问性
  • 编写有意义的注释
  • 遵循移动优先的响应式设计
  • 定期重构和清理代码
  • 使用工具自动化检查
  • 团队统一编码标准