如何写出一套可维护的CSS库?

更新日期: 2021-05-29阅读: 1.7k标签: css

前言

如何写出一套可维护的css库?不妨谈谈CSS的设计模式/架构吧。接下来将为你讲述三个主流的CSS设计思想和一个最近通用的CSS设计思想:OOCSS、SMACSS、BEMCSS、METACSS。


OOCSS

OOCSS,字面意思是面向对象的CSS,是由Nicole Sullivan提出的css理论,虽说是理论,实则更像一种程序员间约定的规范:

Separate structure and skin(分离结构和主题)减少对 html 结构的依赖
Separate container and content(分离容器和内容)增加样式的复用性

在 OOCSS 的观念中,强调重复使用 class,而应该避免使用 id 作为 CSS 的选择器。 OOCSS追求元件的复用,其class命名更为抽象,一般不体现具体事物,而注重表现层的抽取。


SMACSS

smacss通过一个灵活的思维过程来检查你的设计过程和方式是否符合你的架构

设计的主要规范有三点:

Categorizing CSS Rules(为css分类)
Naming Rules(命名规范)
Minimizing the Depth of Applicability(最小化适配深度)

Categorizing CSS Rules

这一点是SMACSS的核心。SMACSS认为css有5个类别,分别是: 1 Base 2 Layout 3 Module 4 State 5 Theme or Skin

Base Rules

基础规范,描述的是任何场合下,页面元素的默认外观。它的定义不会用到class和ID。css reset也属于此类。常见的如normalize.css,CSS Tools

Layout Rules

布局规范,元素是有层次级别之分的,Layout Rules属于较高的一层,它可以作为层级较低的Module Rules元素的容器。左右分栏、栅格系统等都属于布局规范。布局是一个网站的基本,无论是左右还是居中,甚至其他什么布局,要实现页面的基本浏览功能,布局必不可少。SMACSS还约定了一个前缀l-/layout-来标识布局的class。举个最普遍的例子。

.layout-header {}
.layout-container {}
.layout-sidebar {}
.layout-content {}
.layout-footer {}

Module Rules

模块规范,模块是SMACSS最基本的思想,同时也是大部分CSS理论的基本,将样式模块化就能达到复用和可维护的目的,但是SMACSS提出了更具体的模块化方案。SMACSS中的模块具有自己的一个命名,隶属于模块下的类皆以该模块为前缀,例子如下:

.todolist{}
.todolist-title{}
.todolist-image{}
.todolist-article{}

可以看到todolist作为一个模块,包含了title,image,article等组件,同时还可以加上如.todolist-background-danger等修饰类,在模块内可以使用其名称做前缀任意组织模块结构,但目的是让其变得更易用,提高可扩展性和灵活度,如果只是为了修饰而修饰,写出大量没有任何复用性的类,便是一种弄巧成拙的做法。

State Rules

状态规范,这个应该很多前端开发者都很好理解,描述的是任一元素在特定状态下的外观。例如,一个消息框可能有success和error等状态。与OOCSS抽取修饰类的方式的不同,SMACSS是抽取更高级别的样式类,得到更强的复用性,如隐藏某个元素的写法:

.is-hidden{
    display: none;
}

Theme Rules

主题规范,描述了页面主题外观,一般是指颜色、背景图。Theme Rules可以修改前面4个类别的样式,且应和前面4个类别分离开来(便于切换,也就是“换肤”)。SMACSS的Theme Rules不要求使用单独的class命名,也就是说,你可以在Module Rules中定义.header{ }然后在Theme Rules中也用.header { }来定义需要修改的部分(后加载覆盖前加载样式内容)

Naming Rules

命名规范

按照前面5种的划分:

Base Rules(Pass)
Layout Rules用l-或layout-这样的前缀,例如:.l-header、.l-sidebar。
Module Rules用模块本身的命名,例如图文排列的.media、.media-image。
State Rules用is-前缀,例如:.is-active、.is-hidden。
Theme Rules如果作为单独class,用theme-前缀,例如.theme-a-background、.theme-a-shadow。

Minimizing the Depth of Applicability

最小适配深度原则,简单的例子:

/* depth 1 */
.sidebar ul h3 { }

/* depth 2 */
.sub-title { }

两段css的区别在于html和css的耦合度(这一点上和OOCSS的分离容器和内容的原则不谋而合)。可以想到,由于上面的样式规则使用了继承选择符,因此对于html的结构实际是有一定依赖的。如果html发生重构,就有可能不再具有这些样式。对应的,下面的样式规则只有一个选择符,因此不依赖于特定html结构,只要为元素添加class,就可以获得对应样式。

当然,继承选择符是有用的,它可以减少因相同命名引发的样式冲突(常发生于多人协作开发)。但是,我们不应过度使用,在不造成样式冲突的允许范围之内,尽可能使用短的、不限定html结构的选择符。这就是SMACSS的最小化适配深度的意义。


BEMCSS

BEM 分别代表着:Block(块)、Element(元素/子块/组成部分)、Modifier(修饰符),是一种组件化的 CSS 命名方法和规范,由俄罗斯 Yandex 团队所提出。其目的是将用户界面划分成独立的(模)块,使开发更为简单和快速,利于团队协作开发。

特点

组件化/模块化的开发思路。 书写方式解耦化,不会造成命名空间的污染,如:.xxx ul li 写法带来的潜在嵌套风险。 命名方式化扁平,避免样式层级过多而导致的解析效率降低,渲染开销变大。 组件结构独立化,减少样式冲突,可以将已开完成的组件快速应用到新项目中。 有着较好的维护性、易读性、灵活性。 规则

BEM的命名模式在社区中有着不同方式,以下为 Yandex 团队所提出的命名规则为(本文中的代码使用该规则):

.[Block 块]__[Element 元素]_[Modifier 修饰符] 不同的命名模式,区别在于BEM之间的连接符号不同,依个人而定:
.[Block 块]__[Element 元素]--[Modifier 修饰符] 任何一种规范,都是基于实际需求而定,便于团队开发和维护扩展,每个规范都是经过合理评估后所得出的一种“思路”和“建议”。

Block(块)

是一个独立的实体,即通常所说的模块或组件。

例:header、menu、search

规则 块名需能清晰的表达出,其用途、功能或意义,具有唯一性。 块名称之间用-连接。 每个块名前应增加一个前缀,这前缀在 CSS 中有命名空间(如:m-、u-、分别代表:mod 模块、ui 元件)。 每个块在逻辑上和功能上都相互独立。 由于块是独立的,可以在应用开发中进行复用,从而降低代码重复并提高开发效率。 块可以放置在页面上的任何位置,也可以互相嵌套。 同类型的块,在显示上可能会有一定的差异,所以不要定义过多的外观显示样式,主要负责结构的呈现。 这样就能确保块在不同地方复用和嵌套时,增加其扩展性。 综上所述,最终我们可以把BEM规则最终定义成:

.[命名空间]-[组件名/块]__[元素名/元素]--[修饰符] 情景 需要构建一个 search 组件。

写法 .m-search{} 结构

如果打算开发一套框架,可以使用具有代表性的缩写,用来表示命名空间:Element UI(el-)、Ant Design(ant-)、iView(ivu-)。

Element(元素)

是块中的组成部分,对应块中的子元素/子节点。

例:header title、menu item、list item

规则 元素名需能简单的描述出,其结构、布局或意义,并且在语义上与块相关联。 块与元素之间用__连接。 不能与块分开单独使用。 块的内部元素,都被认为是块的子元素。 一个块中元素的类名必须用父级块的名称作为前缀,因此不能写成:block__elem1__elem2。 情景 search 组件中包含 input 和 button,是列表中的一个子元素。

写法 .m-search{} .m-search__input{} .m-search__button{} 结构

<!-- search 组件 -->
<form>
    <!-- input 是 search 组件的子元素 -->
    <input>
    <!-- button 是 search 组件的子元素 -->
    <button>Search</button>
</form>

原则上书写时不会出现两层以上的嵌套,所有样式都为平级,嵌套只出现在 .m-block_active ,状态激活时的情况。

Modifier(修饰符)

定义块和元素的外观、状态或类型。

例:color、disabled、size

规则 修饰符需能直观易懂表达出,其外观、状态或行为。 修饰符用_连接块与元素。 修饰符不能单独使用。 在必要时可进行扩展,书写成:block__elem_modifier_modifier,第一个modifier表示其命名空间。 情景 假定 search 组件有多种外观,我们选择其中一种。并且在用户未输入内容时,button 显示为禁用样式。

写法 .m-search{} .m-search_dark{} .m-search__input{} .m-search__button{} .m-search__button_disabled{} 结构

<!-- dark 表明 search 组件的外观 -->
<form>
    <input>
    <!-- disabled 表明 search__button 的状态 -->
    <button>Search</button>
</form>

小结

很多人觉得 BEM 写法难看,审美本是“智者见智,仁者见仁”的事。刚刚接触可能是会觉得有点奇怪,但所有东西都有一个适应过程。如果仅仅为了好看,规避其优点,我认为得不偿失。个人建议可以尝试使用 BEM 规范来书写代码。

BEM 命名会使得 Class 类名变长,但经过 GZIP 等压缩后,文件的体积其实并无太大影响。

就和早年提出 CSS语义化 一样,不要为了语义而去语义,语义化本身的作用就是帮助大家更好的识别代码,所有的规范都是基于项目的发展和团队的协作,团队可以根据成员的意愿选择最合适的方式。


METACSS

一些写在全局的通用方法,是SMACSS中通用方法思想的分支,一般以css属性、Emmet css缩写或功能来命名,通常以一个css属性为一个单位

表示属性的:

.df { display: flex; }

表示功能的:

.tcut {  
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
  }

以此类推,封装好放到全局来使用,快速添加属性来开发页面。


个人总结

smacss覆盖了所有的细节点;bemcss着重css的命名和语义化;oocss着重可复用,把每一个dom节点当成一个对象,是css返璞归真的思想;metacss着重快速开发快速添加属性,颗粒度更细,通过在html代码中添加类名来添加属性,不必再去找相对应的选择器中的css代码来修改样式。


作者:孟酋长
链接:https://juejin.cn/post/6958690548009926687

链接: https://fly63.com/article/detial/10371

css自动省略号...,通过css实现单行、多行文本溢出显示省略号

网页开发过程中经常会遇到需要把多行文字溢出显示省略号,这篇文章将总结通过多种方法实现文本末尾省略号显示。

深入理解letter-spacing,word-spacing的对比区别

word-spacing 属性增加或减少单词间的空白(即字间隔)。 letter-spacing 属性增加或减少字符间的空白(字符间距)。

整理一下CSS最容易躺枪的二十规则,大家能躺中几条?

满屏div之css最容易中枪的二十条规则,你中枪了吗?一、float:left/right 或者 position: absolute 后还写上 display:block?二、认为布局就是 Float,所有的地方都是 Float,全家都是 Float!

如何编写轻量级 CSS 框架

我想每个人都应该归纳总结工作中的常见需求,编写一套适合自己的 CSS 框架。大多数的轻量级框架只是 CSS 框架,不涉及 JS 部分,主要用于网页的布局。

精简CSS代码,提高代码的可读性和加载速度

定义简洁的CSS规则:CSS的每条规则中都包含了规则的属性及属性值。定义简洁的CSS规则主要是指合并相关规则和定义简洁的属性值。

css完美解决网页在iphoneX的头部刘海显示问题

css完美解决iphonX白条,网站扩展到整个屏幕,CSS Shapes中有个CSS属性名为shape-outside实现元素滚动自动环绕iPhone X刘海

css中 出现height为100%失效的原因及解决方案

我们都知道需要给html和body标签设置了高度height:100%之后,再给内部的div设置height:100%的时候,内部div的高度100%才会起到作用。这是由于:%是一个相对父元素计算得来的高度,要想使他有效,我们需要设置父元素的height。

CSS3 clip-path 用法介绍

clip-path属性可以创建一个只有元素的部分区域可以显示的剪切区域。区域内的部分显示,区域外的隐藏。剪切区域是被引用内嵌的URL定义的路径或者外部svg的路径,或者作为一个形状例如circle().。clip-path属性代替了现在已经弃用的剪切 clip属性。

CSS中可以和不可以继承的属性

这篇文章整理css中无继承性的属性、继承性的属性、所有元素可以继承的属性、内联元素可以继承的属性、块级元素可以继承的属性

你知道我们平时在CSS中写的%都是相对于谁吗?

编写CSS的时候,经常会用到百分比赋值(%)实现自适应。像我们最常使用的流式布局设计模式,基本所有的column的宽度都是通过%来取值的。或者比如经常会遇到的元素水平垂直居中问题

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!