CSS模块化从入门到未知

个人使用CSS的过程中,有两个很困扰的问题就是作用域和优先级,还有一个主观问题,就是CSS的语义化

我之前写CSS的时候就在感慨好乱啊,又没有办法,难道真的没有好的方法吗?本文就是想寻求CSS的最佳实践

  1. 先来解析一下CSS都有哪些问题,一般的解决办法是什么,有没有什么其他的解决办法,哪一种更好?
  2. 听闻CSS有好多种模块化方案,我个人比较喜欢BEM,先介绍一下BEM
  3. 再解析一下其他的模块化方案,他们也有可借鉴之处,也可以融入到BEM中

CSS作用域

你根据需求修改订单列表的样式,把background修改为blue

.list {
  // background: grey;
  background: blue;
}

当你以为没有问题的时候,你发现了用户列表的背景也变成了blue

由于CSS只有全局作用域,订单列表和用户列表都使用了list修饰,所以修改为以下代码

.order .list {
  // background: grey;
  background: blue;
}

或者以下代码

.fuckyoulist {
  // background: grey;
  background: blue;
}

唯一性

其实CSS作用域的问题也好解决,也不好解决,只要保证class的唯一性就可以了

使用hash属性

Vue Loader的Scoped CSS就是采用这种方案

BEM

通过Block的命名的唯一(不强制)来保证唯一性
从规则上来讲,Bolck命名必须是不同的;如果相同,则表示同一个Block

使用后代选择器做限制

上面的解决办法就是使用了后代选择器做限制,这个办法很多时候可以解决问题,不过麻烦在于要多添加一个父类,甚至有可能需要修改HTML结构,而且还会引入优先级的陷阱



  
    
    
  
  
    
  

这里的.contact-list .item没有设置color,但是使用了.account-list .itemcolor样式,即使使用了命名空间,也没有避免样式污染,而这种情况在组件化的今天,很容易发生。根本原因就是item类名不够特殊。

个人观点:

  • 后代选择器,不是将一个类选择器作为另一个类选择器的后代来使用的,这样做意义不大,完全可以分开定义
  • 将元素选择器作为除了通配选择器以外的选择器的后代,倒是很方便的用法

CSS优先级

你根据需求修改订单列表的样式,把background修改为blue

.list {
  background: blue;
}

发现并没有生效,排查了很久,发现了以下代码

.wrapper .list {
  background: grey;
}

你修改为以下代码

.wrapper .list {
  // background: grey;
  background: blue;
}

如果这时候起作用了,也没什么其他问题了,那算你幸运,如果同时发生了作用域问题,其他页面也引用了这个样式,那么就要再次修改了,修改为以下代码

.order .wrapper .list {
  // background: grey;
  background: blue;
}

其实优先级的问题加重都是由于使用了后代选择器而引入的,想象一下,如果都是类选择器,就不会有很严重的优先级问题

为什么要使用后代选择器?

我仔细想了一下,好像很少的场景必须使用后代选择器才能解决,欢迎提问和反驳

有一种情况使用后代选择器会更方便,但也不是无法替代的

.wrapper ul li {
  color: grey;
}

这样使用虽然方便,不过要注意,因为(元素选择器)影响范围很广

尽量使用类选择器?

只要能使用类选择器解决的,就是用类选择器

可以使用伪类选择器,伪元素选择器,因为类选择器很难模拟同样的效果

尽量不使用后代选择器,子代选择器,兄弟选择器,ID选择器,因为他们会加重优先级问题

BEM

BEM,三个字母分别代表 Block、Element、Modifier。

他们提出了一套非常类似的代码原则。他们的核心概念是 —— 块(block)(Nicole 称之为“物体(object)”)由子元素(element)构成,并且可以修改(modified)(或“主题化”)。

命名约定

BEM 所做的另一件事是定义了非常严格的命名约定:
.block-name__element-name--modifier-name

不嵌套CSS

嵌套选择器扰乱了优先度,使得重用代码变得更加困难。例如,只需使用 .btn__price 而不是 .btn .btn__price

这个原则不出问题是因为严格的命名约定。我们曾经使用嵌套选择器将它们隔离在命名空间的上下文中。而 BEM 的命名约定本身就提供了命名空间,因此我们不再需要嵌套。即使 CSS 的根级别的所有内容都是单个类,但这些名称的具体程度足以避免冲突。

一般来说,选择器可以在没有嵌套的情况下生效,就不要嵌套它。 BEM 允许此规则的唯一例外是基于块状态或其修饰符的样式元素。例如,可以使用 .btn__text 然后用 .btn--orange .btn__text 来覆盖应用了修饰符按钮的文本颜色。

OOCSS

上下文无关

首先,无论你把它放在哪里,一个对象都应该看起来无差别,不应根据对象的上下文设置对象的样式。

例如,不是将侧边栏中的所有按钮都设置为橙色,将主区域中的所有按钮设置为蓝色,而是应该创建一个蓝色的按钮类,以及一个橙色的 modifier。这样做橙色按钮可以在任何地方使用,它们没有被绑定在侧边栏上,它们只是你的按钮样式之一。

使用Class

使用 class 来命名对象及其子元素,这样可以在不影响样式的情况下修改 HTML 标签。

她不希望 CSS 由 HTML 标签来确定,这样的话如果将标题从“h1”更改为“h4”,则不必更新 CSS。无论选择哪个标签,该标题应该有一个固有的 class。例如,你的导航应该类似于 .site-nav 而不是 #header ul

不使用ID

根据定义,ID 是唯一的。因此,如果在对象上设置 ID,则无法在同一页面上重复使用它,缺少了模块化对象的要点。

SMACSS

类别(Categories)

以下是他为 CSS 系统可能包含的规则定义的类别:

  1. 基础(Base) 规则是HTML元素的默认样式,如链接,段落和标题。
  2. 布局(Layout) 规则将页面分成几个部分,并将一个或多个模块组合在一起。它们只定义布局,而不管颜色或排版。
  3. 模块(Module)(又名“对象”或“块”)是可重用的,设计中的一个模块。例如,按钮,媒体对象,产品列表等。
  4. 状态(State) 规则描述了模块或布局在特定状态下的外观。通常使用 JavaScript 应用或删除。例如,隐藏,扩展,激活等。
  5. 主题(Theme) 规则描述了模块或布局在主题应用时的外观,例如,在 Yahoo Mail 中,可以使用用户主题,这会影响页面上的每个模块。(这非常适用于像雅虎这样的应用程序,但大多数网站都不会使用此类别。)

命名约定前缀

下一个原则是使用前缀来区分类别,他喜欢 BEM 明确的命名约定,但他还希望能够一目了然地看出模块的类型。

  • l- 用作布局规则的前缀:l-inline
  • m- 用作模块规则的前缀:m-callout
  • is- 用作状态规则的前缀:is-collapsed

自我总结实践

  1. 尽量使用类选择器
  2. 不使用ID选择器,不能复用
  3. 不嵌套CSS,会加重优先级问题
  4. 根据分类为命名添加前缀,提高可读性

示例






后续问题

怎么识别可复用css?

有些css是不能复用的或者很难复用,有些css是可以复用的,不过需要精心设计和维护,怎么区分他们?

不要过早封装,当出现了大量的重复样式,再去封装也不迟

不过要有一个蓝图,最终是形成什么样子的结构,里面包含什么,有什么好处

怎么使用scss变量,使得css变化更容易?

css中的变量一般都是数字和颜色,像素数

需要UI图有一整套规范,比如外边距都是偶数,标题1标题2的字体大小是多少?主要的文字什么颜色,次要的文字什么颜色?

如果UI目前没有这样的规范,那应该怎么做呢?

先写出一些基础的class,例如主要文字,可能会有几个,那就后缀加数字区分,后期去和UI核对,哪些可以修改,尽量统一,之后再抽取出来公共变量,也就是所谓的倒推

  1. 无论目前是什么样子,都按照UI去实现
  2. 实现的过程中,区分哪些是主要文字,哪些是次要文字,封装到不通的class中,如果有多个次要文字class,后缀加数字区分,里面的数字,颜色不需要使用变量,后面再修改
  3. 和UI核对,删除一些不必要的重复class,使样式更加统一
  4. 整理css,把class中公用的部分抽取出来,比如形成函数,定义变量

参考vant的做法,但是应该把各个组件的变量分散到各个组件中
我理解vant是分了层级,基础变量,组件变量,组件样式;组件变量是由基础变量组合而来的,组件样式是由组件变量组合而来的,

组件样式不再依赖具体的数值,而是依赖组件变量,如果组件样式需要调整,可能直接修改组件样式就可以了,可能需要修改组件变量,看情况,如果改动的样式是组件内部复用的样式,那就需要修改样式变量,否则直接修改组件样式

怎么构建css层次?

  1. 之前听说过reset.css和normalize.css,查阅了之后,发现normalize.css更符合需要,就只使用normalize.css
  2. 创建一些独立的布局,函数,mixin等公共样式,可以在页面中使用
  3. 页面样式需要使用scoped关键字,依然使用BEM规范
  4. 覆盖组件样式需要视情况而定

层次关系:normalize -> 公共样式 -> 页面样式 -> 组件样式

参考文章

你可能感兴趣的:(css,模块化,程序员)