【CSS Tricks】深入聊聊前端编写css的方法论

目录

  • 引言
  • BEM 规范
  • OOCSS 规范
    • 结构与样式分离
    • 容器与内容分离
  • SMACSS 规范
  • ITCSS 规范
    • 设置层
    • 工具层
    • 通用层
    • 元素层
    • 对象层
    • 组件层
    • 微调层
    • 由此分层后的项目代码结构也会相应做修改,主要有两种形式:
      • 文件夹形式
      • 文件名形式
      • 引用方式按照层级顺序引用
  • ACSS 规范
  • 总结

引言

本篇内容旨在探讨前端css编写的规范,不讨论某种特定效果的css实现逻辑方法。

css作为前端开发工程师重要的一门技术,在开发工作中可能会花费比写js脚本更多的时间,就为了能让页面更贴合乃至1:1还原UI设计稿(往往事与愿违~)。且不谈最终实现的样式效果如何,单从css代码的混乱程度,就非常让人头大。如果遇到产品优化迭代,需要更新样式时,简直是团队噩梦。一个开发团队中每个人都有自己的编码习惯,有些人喜欢用拼音简称去命名样式类名,有些人喜欢在标签里写样式,有些人可能编写过程中忘记自己写过什么样式就重复覆盖了,偶尔会冒出几个机灵鬼用important去压制别人的样式。如果不采用某种规范去统一编写习惯,则会大大提高团队开发成本。

本篇搜罗了一些比较科学的css编写规范,供大家参考。结合自身编码环境希望可以总结出来一套属于自己的编写方法论。


BEM 规范

BEM 全称为 Block Element Modifier,分别表示块(Block)、元素(Element)、修饰符(Modifier),它是由 Yandex 团队提出的一种 CSS 命名方法。这种命名方法让 CSS 便于统一团队开发规范和方便维护。

该方法论由以下三部分组成:

  • Block: 尽量以元素的性质来命名对象,例如:.list、.card、.navbar。
  • Element: 使用 __ 两个下划线来连接 Block 对象,例如:.list__item、.card__img、.navbar__brand。
  • Modifier : 使用 -- 两个连字符连接 Block 或 Element 对象,例如:.list__item--active、.card__img--rounded、.navbar--dark。

BEM规范中命名规则以功能为导向,遵循几个基本原则:

  • 不能使用class以外的选择器来编写样式(非硬性规定)
  • 不要过度模块化导致类名过长,适当控制模组化深度。

OOCSS 规范

OOCSS 是 Object Oriented CSS 的缩写,意为面向对象的CSS。它是所有 CSS 方法论中最早提出的一个,由 Nicole Sullivan 提出。可以把它理解为将 CSS 模块化。
主要有两个基本原则:

  • 结构与样式分离
  • 容器与内容分离。

结构与样式分离

在 OOCSS 的概念中,表现型的 style 就属于样式 ,封装型的 style 就属于结构,如下所示:

  • 结构(structure):display、box-sizing、padding、margin。
  • 样式(skin):color、background-color、border-color;
css 复制代码
.btn {
  display: inline-block;
  padding: 0.375rem 0.75rem;
  border: 1px solid transparent;
  border-radius: 0.25rem;
  color: black;
  background-color: transparent;
}

.btn-primary {
  color: #fff;
  background-color: map-get($theme-colors, primary);
  border: 1px solid map-get($theme-colors, primary);
}

这样做的意义在于,可以在设置按钮样式的时候按照结构、样式的顺序去填写class,先通过结构类使按钮具备基础结构,然后通过样式类覆盖部分结构以及表现特定样式。

html 复制代码
<button  class = "btn btn-primary"> Primary </button>

实践案例:在编写组件库时,可以借助sass的@each来实现多主题样式

css 复制代码
$theme-colors: (
  primary: blue,
  success: green,
  danger: red,
);

.btn {
  display: inline-block;
  padding: 0.375rem 0.75rem;
  color: black;
  background-color: transparent;
  border: 1px solid transparent;
  border-radius: 0.25rem;
}

@each $key, $value in $theme-colors {
  .btn-#{$key} {
    color: #fff;
    background-color: $value;
    border: 1px solid $value;
  }
}

使用方式为

html 复制代码
<button class="btn btn-primary">Primary</button>
<button class="btn btn-success">Success</button>
<button class="btn btn-danger">Danger</button>

容器与内容分离

这是个比较考验实践经验的概念,需要在实际工作中灵活运用:

  • 核心宗旨是将父子元素分离,达到父子间不相互依赖的目的。
  • 有些子元素脱离父元素会失去本身的意义,则不应该分离。
  • 有些子元素将会在其他元素中复用,例如btn、input等独立性比较强的子元素。

SMACSS 规范

SMACSS 全称为 Scalable and Moduler Architecture for CSS,意为可扩展的模块化 CSS 结构,由 Jonathan Snook 提出。SMACSS 不仅包含了结构与样式分离的概念,还具有极具特色的结构化命名的概念。所谓的结构化命名,就是将元素做结构分类并限制其命名,以此达到易扩展和模块化的目的。

SMACSS 相对于 OOCSS 更偏向于整体结构的分类及模组化 CSS,其中结构的分类包括:

  • Base(基础): 不需要特别的提供前缀,且不会使用到 class、id 选择器,目的在于设定元素基本样式。例如:html、*:before、img。
  • Layout(布局): 使用 l- 或 layout- 为次要布局样式提供前缀,目的在于将布局样式与其他样式做区分。例如:.l-header、.l-sidebar、.l-grid。
  • Module(模块): 使用块本身命名为子元素样式提供前缀,目的在于快速了解其相关性。例如:.card、.card-header、.card-body。
  • State(状态): 使用 is- 为状态样式提供前缀,通过语意化方式了解当前状态。例如:.is-active、.is-hidden、.is-collapsed。
  • Theme(状态): 不需要特别的提供前缀,使用对象本身的名称覆盖其原先的主题样式。例如:.l-header-dark、.card-dark。

ITCSS 规范

ITCSS 全称为 Inverted Triangle CSS,意为倒三角CSS,由 Harry Robers 开发。ITCSS 是一种可扩展和可管理的架构,独立于预处理器存在。它出现的主要目的是帮助组织项目的 CSS 文件,从而解决由级联和选择器的特殊性引起的问题。

核心思想:自上而下的管理体制,上层代码的影响比下层代码影响范围更大,下层代码可具体的覆盖上层代码的部分样式,但不影响上层代码的相关样式在其他下层代码处的表现状态。

该思想将项目中css分为七层,这里以sass作为预处理工具。

设置层

第一层 SETTINGS 表示设置,这一层包含项目的所有全局设置。通常会定义一些全局变量,例如颜色、字体大小等,这一层不会生成实际的 CSS。

css 复制代码
$main-color: #6834cb;
$main-font-size: 24px;

工具层

第二层 TOOLS 表示工具,如果使用了预处理器,可以在这一层定义 function 和 mixins。Tools 层位于 Settings 层之后,因为 mixin 可能需要全局设置中的一些变量来作为默认参数。同样,这一层也不会生成实际的 CSS。

css 复制代码
@function sum($numbers...) {
  $sum: 0;
  @each $number in $numbers {
    $sum: $sum + $number;
  }
  @return $sum;
}

@mixin sample-mixin () {
  ...
}

通用层

第三层 GENERIC 表示通用,可以在这一层来定义重置或者标准化浏览器的基本样式,这一层很少会被修改。这也是第一个实际会生成 CSS 的层。

css 复制代码
* {
  padding: 0;
  margin: 0;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

元素层

第四层 ELEMENTS 表示元素,通常用来定义影响 HTML 单个标签的样式,例如 h1、p 标签的默认样式

css 复制代码
h1 {
  color: $main-color;
  font-size: $main-font-size;
}

对象层

第五层 OBJECTS 表示对象,可以在这一层定义整个项目中可重用的页面结构类。与上一层相比,这一层对 DOM 的影响更小,具有更高的特异性(优先级),并且更加明确,因为现在将 DOM 的部分作为目标来设置了样式。

css 复制代码
.grid-container {
  display: grid;
  grid-template-columns: auto auto auto auto;
}

组件层

第六层 COMPONENTS 表示 UI 组件,与对象层不同,组件是页面的特定部分。比如搜索框的样式,为组件定义的样式只会影响到对应的组件。这一层比上一层更加明确,因为现在为 DOM 设计了明确的样式。

css 复制代码
.c-btn {
  display: flex;
  justify-content: center;
  align-items: center;
  ...

  &--primary {
    background-color: #ff5959;
    color: #fff;
  }

  &--large {
    font-size: 16px;
    padding: 16px 14px;
    ...
  }
}

微调层

这一层也称为 Utilities,包含所有那些覆盖之前层中定义的任何其他规则的规则。它是唯一允许使用 !important 的层。

css 复制代码
.d-none {
  display: none!important;
}

由此分层后的项目代码结构也会相应做修改,主要有两种形式:

文件夹形式

文件名形式

引用方式按照层级顺序引用

css 复制代码
@import "settings.global.scss";
@import "settings.colors.scss";

@import "tools.functions.scss";
@import "tools.mixins.scss";

@import "generic.box-sizing.scss";
@import "generic.normalize.scss";

@import "elements.headings.scss";
@import "elements.links.scss";

@import "objects.wrappers.scss";
@import "objects.grid.scss";

@import "components.site-nav.scss";
@import "components.buttons.scss";
@import "components.carousel.scss";

@import "trumps.clearfix.scss";
@import "trumps.utilities.scss";
@import "trumps.ie8.scss";

ACSS 规范

ACSS 的全称为 Atomic CSS,意为原子CSS。它专注于创建很多小型的 CSS 样式类,以便在 HTML 上使用。这种方法旨在提供高度精细和可重用的样式,而不是为每个组件提供规则。这可以减少特异性(优先级)冲突并以可预测的方式使样式更具可变性。这种方法有助于减少代码冗余和覆盖 CSS 样式的混淆。

个人观点:

  • 不建议使用。
  • 当原子类过于庞大之后,学习成本将会非常高。
  • 对于复杂的dom结构原子类数量过多,可读性不强。不利于后续开发人员维护。
  • 如果非要用可以参考tailwindcss

总结

每个人的开发习惯有所不同,所处项目环境也有不同,所以不必要强求使用哪一种规范。个人比较建议各取所长融会贯通找到属于自己的方法论。

  • 推荐使用 ITCSS 规范管理项目中的CSS文件。
  • 使用 BEM 对类进行命名规范。
  • 结合OOCSS && SMACSS 两个方法论抽象结构和样式,编写具体的CSS样式。这一条切记不要用力过猛,虽然可以增强复用性优化代码量,但是你会在设置某个DOM样式时填写一大堆类名,反而更像是 ACSS 的样子,有点本末倒置。
相关推荐
Pedantic2 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘3 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆3 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师4 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆4 小时前
VSCode自动格式化三要素
前端
爱勇宝5 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen5 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518137 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode7 小时前
Redis 在生产项目的使用
前端·后端