软件开发领域所有的工程问题,归根结底衍生自一个问题:代码量大了怎么办?

对于CSS而言,因代码量增大导致的核心问题是命名冲突。

解决命名冲突的方法论是模块化,围绕此方法论,演化出种种模块化方案。

一、命名的模块化

基本思路是确保全局空间下一级域名不冲突,那么子域名就被限定在了独立的局部作用域中,从而保证命名的唯一性。

根据域名的划分方式,出现了不同的命名方案:

   BEM:Block-Element-Modifier,比较笼统,没有过多限制规定

   SUIT CSS

   1、将命名对象划分为组件(component)和功能(Utility)。组件直接命名,功能额外加前缀,比如专门给js调用的类名可加上js前缀:js-button

   2、规定了连字符的用法。普通隔断用单个连字符,描述性词汇用两个连字符:

   .nav-button { }

   .nav-button--primary { }

   沿着这个思路,其实还可以把下划线引进来,用来设置其它规则。

   3、状态切换用is-state型的相邻类名(adjoining class)

   .button { }

   .button.is-clicked { }

   <button class=”button is-clicked”></button>

   OOCSS

   简单的说就是抽象公共类,把复用度高的样式抽取出来,例如:

   .mt20 { margin-top: 20px }

   .tc { text-align: center }

   .abs { position: absolute }

   .clearfix:after { content: ‘’; display: block; clear: both; height: 0 }

   这种方案的思路是通过提高复用性,减少命名的需要,因为有的样式直接用公共类名就能实现,不需要额外命名。

   它的缺点是滥用就可能付出代价,比如有10个组件用同一个普通类名,那么修改样式只需要改一处CSS即可,但是在10个组件上用同一个公共类名比如mt20,意味着把mt20改成mt15,你需要改10处的class。所以公共样式少用公共类,不要图省事儿。

   SMACSS

   针对数量庞大的类名,SMACSS提出了一个分类的方案:

   1、Base:基础的样式规则

   2、Layout:用于布局的样式规则

   3、Module:可复用的模块样式规则

   4、State:状态样式

   5、Theme:UI样式

   针对不同分类,可以使用不同的前缀来划分命名空间,就不多赘述了。

   ITCSS

   此方案更像是CSS整体架构方案,与SMACSS横向分类不同,它综合了以上各种方法,提出了一个纵向分层模型:

   1、Settings:简单的说就是在SCSS中预设好变量

   2、Tools:简单的说就是在SCSS中预设好mixins和functions

   3、Generic:简单的说就是reset.css或normalize.css

   4、Elements:对元素的基本格式化,如h1 { font-size: 20px }

   5、Objects:使用OOCSS抽象公共类

   6、Components:UI组件的样式

   7、Trumps:辅助性、功能性的特殊样式,例如动画

二、CSS in JS

在大型项目中通过命名来避免冲突,是一件颇费脑力的事情,既需要记住所有规则,还需要判断你的命名是否符合规则。更深刻的问题是,这似乎不像是程序员解决问题的方式,命名这样的低级劳动也值得如此费劲?

   于是React提出了CSS in JS的思路,React是这样考虑的:在JS以及所有程序语言的最佳实践里,都会避免使用全局变量,而在CSS里,不管用什么命名方式,满屏幕都是全局变量,怎样才能避免使用全局变量呢?办法是采用内联样式,根本不用CSS选择器。

   var styles = {

   button: { width: ‘50px’, height: ‘30px’ , backgroundColor: ‘#ff4444’}

   }

   <div style = { styles.button }>

   我们不能简单的用“开历史倒车”这样的论调来判断一种技术方案,而应结合应用场景,在成本和收益上权衡。具体的说就是这种方案所解决的问题与其带来的问题相比,是否更划算。

   来源:https://speakerdeck.com/vjeux/react-css-in-js

大型CSS存在的问题有:

1、全局的命名空间容易污染、冲突

2、依赖管理复杂

3、无用代码难以清除

4、长命名导致代码体积无法进一步压缩

5、不利于和JS共享常量

6、不确定的解析结果(CSS中存在层叠,如果层叠系数高的代码加载更慢,会导致最终解析的样式发生突变)

   7、不能解耦(改一处CSS,所有使用该CSS的UI样式都会受影响)

   用JS + inline style 解决了上述所有问题,当然也带来了其它副作用,比如难以调试、不能用CSS预处理器、不能实现Media Query和伪元素等,而且如果你不用React……

三、CSS Module

  CSS Module可以看做是CSS in JS思路的另一条路线,就是使用JS编译原生的CSS文件,使其具备模块化的能力。

  CSS Module根据CSS文件划分模块,模块内部的类名都会使用哈希算法编译成独一无二的名称,因此不会出现模块之间命名冲突的问题。

  当然,必须使用构建工具如webpack,才能使用CSS Module提供的功能。

   CSS Module要求每个元素只能携带一个类名,不能用多个类名,那么要使用组合样式怎么办?解决方案是在CSS中使用component,这个其实在预处理器中已经有类似的实现:

   .common { }

   .normal {

   composes: common  // 继承common所有的样式

   }

   composes不仅可以引用本文件的类名,还可以引用其它文件的类名:

   .normal {

   composes: common;

   composes: primary from "../shared/colors.css";

   }

   另外,使用:global(.className)语法可以定义全局类名,结合PostCSS可以使用变量,具体请参见阮一峰的教程:

   http://www.ruanyifeng.com/blog/2016/06/css_modules.html

四、PostCSS

   PostCSS是近年来非常热门的一种编译工具,Vue官方提供的脚手架Vue-cli默认采用的CSS处理工具就是PostCSS。PostCSS和预处理器Less、Sass不同,预处理器仅仅是提供了一套语法糖,而PostCSS是一个全面的处理工具,通过丰富的插件,可以实现用于处理CSS的几乎所有的功能:类名编译、auto-prefixer、压缩、预处理器功能、属性简写……

PostCSS并不是唯一,前端界历来奉行的宗旨是“生命不息,折腾不止”,关于CSS in JS的方案,大家感受一下:

五、Atomic CSS

   代码量与复用性呈反比例关系,因此写CSS有两个极端:一是单独为每个元素写一份样式,完全不复用,这样每个元素只需要一个class,而CSS代码是最多的;二是把每一条样式单独写在一个class中,确保整个样式表没有一条重复的样式,这样复用性是最高的,代码也最少,但是每个元素就需要一堆的class。

   通常我们会在两个极端中取折中方案,确保适度的复用性和适度的代码规模,如何把握这个“度”,正是体现方案优劣和架构功力的地方。然而Atomic选择了走第二种极端的方式,即使用原子化的样式,最小化CSS代码,并且Atomic解决命名冲突的方式也非常激进:你完全不用考虑命名,因为根本不需要命名。

   <div class="Bgc(#ccc) C(#fff) P(20px) W(100px)">

   编译出的CSS是这样的:

   .Bgc\(\#ccc\) {background-color: #ccc}

   .C\(\#fff\) {color: #fff}

   .P\(20px\) {padding: 20px}

.W\(100px\) {width: 100px}

这种思路可谓另辟蹊径,独树一帜。当然优缺点都很明显:CSS代码最小化了,而HTML膨胀了;虽然不用考虑命名,但是要记一堆新规则。

六、小结

命名方案很适合中小型项目。在大型项目中,命名方案仍然具有指导作用,但是仅凭命名方案是不够的。

   新的思路有两种:一是抛弃CSS,二是补强CSS的能力。

   React采用的是第一种思路,能用JS解决的都用JS解决。

   第二种思路大多采用编译工具。虽然编译的方案各不相同,但是要解决的核心问题是一致的,就是命名冲突。最直接的策略是将名称编译为独一无二的名称,CSS module和PostCSS都采取该策略。Atomic提出了一种新颖的思路,即将样式表彻底原子化,类名与样式规则一一映射,直接使用类名编写样式,完全消灭了命名的需要。

   每一种方案都各有所长,也各有所短。从来没有最好的方案,只有最不坏的方案。如果一种方案在特定场景、特定约束条件下找不到更好的替代,那么无论它的缺点有多么明显,都可以认为是“最优”方案。

CSS方法论完全总结的更多相关文章

  1. CSS躬行记(10)——CSS方法论

    方法论是一个哲学术语,会对一系列具体的方法进行分析研究.系统总结并最终提出较为一般性的原则.CSS方法论是一种面向CSS.由个人和组织设计.已被诸多项目检验且公认有效的最佳实践.这些方法论都会涉及结构 ...

  2. CSS代码重构与优化之路

    作者:@狼狼的蓝胖子 网址:http://www.cnblogs.com/lrzw32/p/5100745.html 写CSS的同学们往往会体会到,随着项目规模的增加,项目中的CSS代码也会越来越多, ...

  3. CSS 继承深度解析

    FROM ME: 之前在研究前端性能优化的时候,就有学习关于CSS中“善用CSS中的继承”. 原文:CSS Inheritance, The Cascade And Global Scope: You ...

  4. CSS代码重构

    CSS代码重构的目的 我们写CSS代码时,不仅仅只是完成页面设计的效果,还应该让CSS代码易于管理,维护.我们对CSS代码重构主要有两个目的:1.提高代码性能2.提高代码的可维护性 提高代码性能 提高 ...

  5. CSS代码重构与优化

    CSS代码重构的基本方法 前面说到了CSS代码重构的目的,现在我们来说说一些如何达到这些目的的一些基本方法,这些方法都是易于理解,容易实施的一些手段,大家平时可能也不知不觉地在使用它. 提高CSS性能 ...

  6. CSS代码重构与优化之路(转)

    CSS代码重构与优化之路   阅读目录 CSS代码重构的目的 CSS代码重构的基本方法 CSS方法论 我自己总结的方法 写CSS的同学们往往会体会到,随着项目规模的增加,项目中的CSS代码也会越来越多 ...

  7. CSS性能优化的8个技巧

    本文作者:高峰,360奇舞团前端工程师,W3C性能工作组成员,同时参与WOT工作组的学习. 我们都知道对于网站来说,性能至关重要,CSS作为页面渲染和内容展现的重要环节,影响着用户对整个网站的第一体验 ...

  8. Web优化躬行记(1)——CSS

    Web优化的对象包括页面性能.用户体验.开发效率.代码优化.网络延迟等,本系列会列举出众多常用的优化技巧,每个技巧都可深入分析,在此只做抛砖引玉. 本系列优化内容提炼于<前端面试宝典>.& ...

  9. CSS品控与流程

    精通CSS意味着不仅能写出可用的标记和样式,还能让代码好阅读.方便移植.易维护. 1.外部代码质量:调试CSS 外部代理质量就是用户能体验到的最终结果.主要体现在几个方面. 正确性.CSS属性名都写对 ...

随机推荐

  1. OAF_VO系列3 - Binding Style绑定方式

    在OAF VO开发中,Binding Style主要用于对VO的where clause做动态传值,总共有三种方式 1.       Oracle Named 2.       Oracle Posi ...

  2. 你好,C++(22) 排排坐,吃果果——4.3.3 for循环:某个范围内…每个都…

    4.3.3  for循环:某个范围内…每个都… 既然while语句和do…while…语句都已经可以满足我们表达循环现象的需要,那为什么C++还要专门提供for语句来表达循环现象呢?在现实世界中,常常 ...

  3. idea导入java项目

    https://blog.csdn.net/m0_37106742/article/details/70154244 ( 主要 )https://blog.csdn.net/u012099869/ar ...

  4. Python flask+react+antd实现登陆demo

    这两天在研究flask和antd,想把这俩个东西结合来使用,单独学antd的时候用的是dva来配置,但是发现这样与flask结合的话需要启动两个服务,作为flask只是作为数据的接口,并没用用到其强大 ...

  5. PD915温度太高,通过设置BIOS降底CPU的核心电压来降温。

    由于对电脑配置不是很懂,去年去配了台电脑,用的CPU是PD915,不用不知道,一用吓一跳. PD915在冬天的时候,运行起来温度大概在30多度,感觉很正常. 可是一到了夏天,温度就升到了70到80度之 ...

  6. Android View坐标系详解(getTop()、getX、getTranslationX...)

    View 提供了如下 5 种方法获取 View 的坐标:1. View.getTop().View.getLeft().View.getBottom().View.getRight();2. View ...

  7. python之获取微信access_token

    # -*- coding: cp936 -*- #python 27 #xiaodeng #获取微信access_token #办法一:将该url直接填写到浏览器地址中可以获得access_token ...

  8. POJ 2674 Linear world(弹性碰撞)

    Linear world Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 4426   Accepted: 1006 Desc ...

  9. vue.js开发之开关(switch)组件

    最近开发组件的时候,自定义开发了开关(switch)组件,现将代码整理如下,方便日后复用. toggle-switch.vue <template> <label role=&quo ...

  10. 转:Hive性能优化之ORC索引–Row Group Index vs Bloom Filter Index

    之前的文章<更高的压缩比,更好的性能–使用ORC文件格式优化Hive>中介绍了Hive的ORC文件格式,它不但有着很高的压缩比,节省存储和计算资源之外,还通过一个内置的轻量级索引,提升查询 ...