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