命名约定
一致的命名约定是代码可读性和可维护性的基石。在 HTML 开发中,class 命名直接影响 CSS 选择器和 JavaScript DOM 操作的效率。本节将详细介绍三种主流 CSS class 命名方法论(BEM、OOCSS、SMACSS)、id 命名规范、文件命名规范,帮助团队建立统一的命名体系。
前置知识
阅读本节前,建议先了解:缩进与格式化
为什么命名约定重要
- 可读性:清晰的命名让代码自解释
- 可维护性:统一的命名降低理解和修改成本
- 可扩展性:好的命名规范支持项目规模的扩大
- 协作效率:团队成员能快速理解代码结构
BEM 命名法
BEM(Block Element Modifier)是最流行的 CSS 命名方法论。
BEM 三个组成部分
| 组成部分 | 说明 | 命名规则 | 示例 |
|---|---|---|---|
| Block(块) | 独立的功能组件 | .block | .card、.nav |
| Element(元素) | 块的组成部分 | .block__element | .card__title、.nav__link |
| Modifier(修饰符) | 块或元素的变体 | .block--modifier | .card--featured、.nav--dark |
BEM 示例
html
<!-- Block: 独立的用户卡片组件 -->
<div class="user-card user-card--featured">
<!-- Element: 卡片的组成部分 -->
<img class="user-card__avatar" src="avatar.jpg" alt="用户头像" />
<h3 class="user-card__name">张三</h3>
<p class="user-card__bio">前端工程师</p>
<!-- Modifier: 修饰符表示变体 -->
<div class="user-card__stats user-card__stats--expanded">
<span class="user-card__stat">128 篇文章</span>
<span class="user-card__stat">256 粉丝</span>
</div>
<!-- 块级修饰符 -->
<button class="btn btn--primary user-card__follow-btn">
关注
</button>
</div>html
<!-- 导航栏 BEM 示例 -->
<nav class="nav nav--dark">
<div class="nav__logo">
<a href="/" class="nav__link nav__link--logo">Logo</a>
</div>
<ul class="nav__menu">
<li class="nav__item">
<a href="/" class="nav__link nav__link--active">首页</a>
</li>
<li class="nav__item">
<a href="/about" class="nav__link">关于</a>
</li>
</ul>
<button class="nav__toggle nav__toggle--open" aria-label="打开菜单">
<span class="nav__icon"></span>
</button>
</nav>OOCSS 命名法
OOCSS(Object-Oriented CSS)强调结构和皮肤分离。
核心原则
| 原则 | 说明 | 示例 |
|---|---|---|
| 结构与皮肤分离 | 布局和视觉样式分开 | .btn + .btn-primary |
| 容器与内容分离 | 组件不依赖父容器 | .card 可在任何容器中使用 |
html
<!-- 结构 -->
<div class="media">
<img class="media__img" src="avatar.jpg" alt="头像" />
<div class="media__body">
<h3 class="media__title">标题</h3>
<p class="media__desc">描述内容</p>
</div>
</div>
<!-- 皮肤(可复用的视觉样式) -->
<div class="card card--shadow card--rounded">
<div class="card__header card__header--dark">
<h2 class="card__title">标题</h2>
</div>
<div class="card__body">
<p>内容</p>
</div>
</div>SMACSS 命名法
SMACSS(Scalable and Modular Architecture for CSS)将样式分为五类。
五大分类
| 类别 | 前缀 | 说明 | 示例 |
|---|---|---|---|
| Base | 无 | 基础元素样式 | h1、a、body |
| Layout | l- 或 layout- | 页面布局 | .l-header、.l-sidebar |
| Module | 无 | 可复用组件 | .card、.nav |
| State | is- 或 s- | 状态变体 | .is-active、.is-hidden |
| Theme | theme- | 主题样式 | .theme-dark、.theme-light |
html
<!-- SMACSS 示例 -->
<div class="l-wrapper">
<header class="l-header">
<nav class="nav is-expanded">
<ul class="nav__list">
<li class="nav__item is-active">
<a href="/" class="nav__link">首页</a>
</li>
</ul>
</nav>
</header>
<main class="l-content">
<div class="card is-featured">
<h2 class="card__title">标题</h2>
<p class="card__body">内容</p>
</div>
</main>
</div>命名规范对照
class 命名规则
| 规则 | 推荐 | 不推荐 |
|---|---|---|
| 使用小写 | .product-card | .ProductCard |
| 连字符分隔 | .nav-item | .navItem、.nav_item |
| 避免缩写 | .navigation | .nav(除非团队约定) |
| 语义化命名 | .article-title | .title-red-big |
| 避免使用 ID 作为样式 | .header(class) | #header(id) |
id 命名规则
html
<!-- id 命名:用于 JavaScript 钩子和锚点 -->
<div id="main-content"></div>
<div id="user-profile"></div>
<div id="order-form"></div>
<!-- id 使用驼峰式或连字符式 -->
<div id="mainContent"></div>
<div id="main-content"></div>JavaScript 钩子命名
html
<!-- 使用 data 属性标记 JS 钩子,避免依赖 class -->
<button class="btn btn-primary" data-js="submit-form">
提交
</button>
<div class="dropdown" data-js="user-menu">
...
</div>
<!-- JavaScript 选择 -->
// 推荐:使用 data 属性
document.querySelector('[data-js="submit-form"]')
// 不推荐:使用 class
document.querySelector('.btn-primary') // 如果 class 改变就失效文件命名规范
| 文件类型 | 命名规则 | 示例 |
|---|---|---|
| HTML 页面 | 小写连字符 | product-detail.html |
| CSS 文件 | 小写连字符 | main-navigation.css |
| 图片文件 | 小写连字符+描述 | hero-banner-home.jpg |
| JavaScript | 小写连字符或驼峰 | product-slider.js |
| 字体文件 | 小写连字符 | noto-sans-regular.woff2 |
项目目录结构示例:
├── index.html
├── product-detail.html
├── css/
│ ├── base.css
│ ├── layout.css
│ ├── components/
│ │ ├── card.css
│ │ ├── navigation.css
│ │ └── button.css
│ └── main.css
├── js/
│ ├── main.js
│ ├── navigation.js
│ └── product-slider.js
└── images/
├── logo.svg
├── hero-banner.jpg
└── icons/
├── arrow-right.svg
└── search.svg实战示例:统一的命名风格
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>BEM 命名示例</title>
</head>
<body>
<!-- 页面布局:SMACSS l- 前缀 -->
<div class="l-page">
<header class="l-header">
<!-- 组件:BEM 命名 -->
<nav class="nav" aria-label="主导航">
<div class="nav__brand">
<a href="/" class="nav__logo">品牌</a>
</div>
<ul class="nav__list">
<li class="nav__item is-active">
<a href="/" class="nav__link">首页</a>
</li>
<li class="nav__item">
<a href="/products" class="nav__link">产品</a>
</li>
</ul>
<button
class="nav__toggle"
data-js="nav-toggle"
aria-label="切换菜单"
aria-expanded="false"
>
<span class="nav__icon"></span>
</button>
</nav>
</header>
<main class="l-main">
<div class="l-container">
<!-- 产品卡片组件 -->
<article class="card card--featured">
<img
class="card__image"
src="product.jpg"
alt="产品描述"
loading="lazy"
>
<div class="card__content">
<h2 class="card__title">产品名称</h2>
<p class="card__description">产品简介</p>
<div class="card__footer">
<span class="card__price">¥299.00</span>
<button
class="btn btn--primary card__action"
data-js="add-to-cart"
data-product-id="12345"
>
加入购物车
</button>
</div>
</div>
</article>
</div>
</main>
<footer class="l-footer">
<div class="l-container">
<p class="l-copyright">© 2024 品牌</p>
</div>
</footer>
</div>
</body>
</html>注意事项
- 选择一种方法论:BEM、OOCSS、SMACSS 各有优势,选择最适合团队的
- 保持一致性:一旦选择就坚持使用,不要混用不同风格
- 避免过度嵌套:BEM 中避免超过两层的
__嵌套 - JS 钩子与样式分离:使用
data-js属性标记 JS 交互元素 - 命名要有语义:避免使用颜色、位置等无语义的名称
最佳实践
- 推荐使用 BEM 命名法
- 使用连字符
-分隔单词 - 语义化命名,避免描述性名称
- JS 钩子使用
data-*属性 - 文件命名使用小写连字符
- 在项目中编写命名规范文档
- 使用 stylelint 检查命名一致性
下一节
继续学习:注释规范