为什么要CSS模块化?

你是否为class命名而感到苦恼?

你是否有怕跟别人使用同样class名而感到担忧?

你是否因层级结构不清晰而感到烦躁?

你是否因代码难以复用而感到不爽?

你是否因为common.css的庞大而感到恐惧?

如果有,恭喜你来对了地方!本文会为您一一解决这些难题!

那么如何解决CSS命名问题?

我们看一下CSS是怎么规范的:使用有意义的或通用的ID和class命名。ID和class的命名应反映该元素的功能或使用通用名称,而不要用抽象的晦涩的命名。反映元素的使用目的是首选;使用通用名称代表该元素不表特定意义,与其同级元素无异,通常是用于辅助命名;使用功能性或通用的名称可以更适用于文档或模版变化的情况。

常用命名(多记多查英文单词):page、wrap、layout、header(head)、footer(foot、ft)、 content(cont)、menu、nav、main、submain、sidebar(side)、logo、banner、 title(tit)、popo(pop)、icon、note、btn、txt、iblock、window(win)、tips等

注:类型选择器避免同时使用标签、ID和class作为定位一个元素选择器;从性能上考虑也应尽量减少选择器的层级。

如何构建结构清晰的CSS?

大家都说CSS学和写都简单,那么写了多年CSS的同学是否有静下来思考过,自己写CSS是有较为系统的和具有一定规范的,而不是草率的写CSS。另外就是自己写的CSS在团队中,别的同学是否能看到代码就知道您写的是什么?如果没有,那不仿看看这里提到的一些概念与思想,比如:Sass 、SCSS、LESS、BEM、OOCSS、AMCSS等。让我们一起来深入了解css吧?

  • 首先了解一下BEM(我个人比较喜欢的)

BEM的意思就是块(block)、元素(element)、修饰符(modifier),是由Yandex团队提出的一种前端命名方法论。这种巧妙的命名方法让你的CSS类对其他开发者来说更加透明而且更有意义。BEM命名约定更加严格,而且包含更多的信息,它们用于一个团队开发一个耗时的大项目。

命名约定的模式如下:

  1. .block{}   // 块即是通常所说的 Web 应用开发中的组件或模块。每个块在逻辑上和功能上都是相互独立的。

  2. .block__element{}  // 元素是块中的组成部分。元素不能离开块来使用。BEM 不推荐在元素中嵌套其他元素。

  3. .block--modifier{}   // 修饰符用来定义块或元素的外观和行为。同样的块在应用不同的修饰符之后,会有不同的外观。

BEM不是一个框架,它只是一种思想

BEM优缺点

优点:BEM 的优点在于所产生的 CSS 类名都只使用一个类别选择器,可以避免传统做法中由于多个类别选择器嵌套带来的复杂的属性级联问题。在 BEM 命名规则中,所有的 CSS 样式规则都只用一个类别选择器。因此所有样式规则的特异性(specificity)都是相同的,也就不存在复杂的优先级问题。这可以简化属性值的层叠规则。代码清单中的命名规则的好处在于每个 CSS 类名都很简单明了,而且类名的层次关系可以与 DOM 节点的树型结构相对应。 缺点: CSS 类名会比较长而且复杂。乍看之下,根据 BEM 命名规则产生的 CSS 类名都会很复杂,但实际上在熟悉了命名规则之后,可以很容易理解其含义。

  • 我们再看一下OOCSS(面向对象CSS)

OOCSS 表示的是面向对象 CSS(Object Oriented CSS),是一种把面向对象方法学应用到 CSS 代码组织和管理中的实践。 OOCSS最关键的一点就是:提高他的灵活性和可重用性。这个也是OOCSS最重要的一点。OOCSS主张是通过在基础组件中添加更多的类,从而扩展基础组件的CSS规则,从而使CSS有更好的扩展性。

我们有一个容器是页面page的1/4宽,有一个蓝色的背景,1px灰色的边框,10px的左右边距,5px的上边距,10px的下边距,以前对于这样一个样式,我们常常给这个容器创建一个类,并把这些样式全部加上。像下面这样。

  1.  // template
    
     <div class="size1of4"></div>
    
     // style
    
     .size1of4 {
    
      background: blue;
    
      border: 1px solid #ccc;
    
      margin: 5px 10px 10px;
    
      width: 25%;
    
     }

然而使用oocss的话,我们不这样做,我把为这个容器创建更多的类,并且每个样式对应一个类,这样是为了后面可以重复使用这些组件的样式,避免重复写相同的样式,就拿这个实例来说,我们给这个容器增加下面的类:bgBlue,solidGray,mts,mlm,mrm,mbm

  1.  // template
    
     <div class="size1of4 bgBlue solidGray mts mlm mrm mbm"></div>
    
     // style
    
     .size1of4 {width: 25%;}
    
     .bgBlue {background:blue}
    
     .solidGray {border: 1px solid #ccc}
    
     .mts {margin-top: 5px}
    
     .mrm {margin-right: 10px}
    
     .mbm {margin-bottom: 10px}
    
     .mlm {margin-left: 10px}

OOCSS的优点

  • 减少CSS代码。

  • 具有清洁的HTML标记,有语义的类名,逻辑性强的层次关系。

  • 语义标记,有助于SEO。

  • 更好的页面优化,更快的加载时间(因为有很多组件重用)。

  • 可扩展的标记和CSS样式,有更多的组件可以放到库中,而不影响其他的组件。

  • 能轻松构造新的页面布局,或制作新的页面风格。

OOCSS的缺点

  • OOCSS适合真正的大型网站开发,因为大型网站用到的可重用性组件特别的多,如果运用在小型项目中可能见不到什么成效。所以用不用OOCSS应该根据你的项目来决定。

  • 如果没用巧妙的使用,创建组件可能对于你来说是一堆没用的东西,成为一烂摊子,给你的维护带来意想不到的杯具,说不定还是个维护的噩梦。

  • 最好给每一个组件备写一份说明文档,有助于调用与维护。

  • AMCSS(属性模块)。

属性模块或者说AM,其核心就是关于定义命名空间用来写样式。通俗的讲就是,给一个元素加上属性,再通过属性选择器定位到这个元素。达到避免过多的使用class。

  1.  // template
    
     <div am- Row ></div>
    
     <div am- Column = "12"> Full < /div>
    
     </ div> <div am- Row > <div am- Column = "4"> Thirds </div>
    
     <div am- Column = "4"> Thirds </div>
    
     <div am- Column = "4"> Thirds < /div> </ div>
    
     // style
    
     [am- Row ] { /* max-width, clearfixes */ }
    
     [am- Column ~= "1" ] { /* 1/12th width, floated */ }
    
     [am- Column ~= "2" ] { /* 1/6th width, floated */ }
    
     [am- Column ~= "3" ] { /* 1/4th width, floated */ }
    
     [am- Column ~= "4" ] { /* 1/3rd width, floated */ }
    
     [am- Column ~= "5" ] { /* 5/12th width, floated */ } /* etc */
    
     [am- Column ~= "12" ] { /* 100% width, floated */ }

你会注意到第一件事情就是有am-前缀。这也是AM核心部分,确保属性模块不会与现有属性冲突。你可以使用你自己喜欢的任何前缀名,我常使用的是ui-、css-或者其他前缀,但这些示例中使用的是am-前缀。HTML的有效性对你或你的项目来说是非常重要,就类似于使用data-前缀开头定义的属性类似。 你可能会注意到的第二件事情就是类似于1、4或12这样的值,使用类名变得极为麻烦——造成冲突的机会很多。但定义了我们自己的命名空间,实际上将空间变得很小,用于工作中不会造成冲突。为了更好的工作,可以自由选择最简明而且有意义的标记。

我们虽然有这么多的好的方案去解决css的一些难题,但是有没有一种东西或者工具来代替我们去做这些呢,作为一个程序员我们不喜欢做太麻烦的事情。那么接下来我们谈一谈css的构建工具

OK,我们来探索一下webpack是怎么实现模块化的。

With :local (without brackets) local mode can be switched on for this selector. :global(.className) can be used to declare an explicit global selector. With :global (without brackets) global mode can be switched on for this selector. webpack会把class分为两种,一种是local(本地的),一种是global(全局的)。默认导出的都是本地的,但是你可以通过 :global(...)开关来控制导出全局。下面我们看一下栗子。

  1.  // 输入
    
     : local (.className) { background: red; }
    
     : local .className { color: green; }
    
     : local (.className .subClass) { color: green; }
    
     : local .className .subClass : global (. global - class -name) { color: blue; }
    
     // 导出
    
     ._23_aKvs-b8bW2Vg3fwHozO { background: red; }
    
     ._23_aKvs-b8bW2Vg3fwHozO { color: green; }
    
     ._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 { color: green; }
    
     ._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 . global - class -name { color: blue; }

:local(className)被编译为唯一可识别的标示,:global(className)原样输出,当然我们也可以控制导出的格式。配置如下:

  1.  {
    
      test: /\.css$/ ,
    
      use : [
    
        {
    
         loader: 'css-loader',
    
         options: {
    
           modules: true ,
    
           localIdentName: '[path][name]__[local]--[hash:base64:5]'
    
         }
    
       }
    
     ]
    
     }
CSS的scoped实现?

现在在各种框架中都会有scoped属性,使我们的css具有模块化性质,不会污染到其他模块,那么scoped是如何实现的呢?我们一起来揭开它神秘的面纱吧?

如果你是一个勤奋好学的同学,你一定会发现在HTML的style标签中有一个scoped属性。让我们来一起看一下这个属性的神奇吧。

一直以来,文档上的STYLE元素通常都是作用域全局的,选择器按照全局的CSS优先规则来设置的。要实现局部的选择需要先选到容器元素,再用后代选择器来实现。scoped属性可以让STYLE元素不再作用于全局,而从当前STYLE元素所在的容器开始选择后代。

  1.  <div>
    
      <style scoped >
    
        span {color:red;}
    
      </style>
    
      <span> 我是第1个DIV内的SPAN </span>
    
     </div>
    
     <div>
    
      <style scoped >
    
        span {color:green;}
    
      </style>
    
      <span> 我是第2个DIV内的SPAN </span>
    
     </div>
    
     <div>
    
      <span> 我是第3个DIV内的SPAN </span>
    
     </div>

结果:

我们可以看见第三个div并没有被第一及第二个style所感染,也就是说带有scoped属性的css是一个独立的作用域,不会影响到其它模块!!太好了,那我们以后在style里面加上scoped属性就可以完美解决啦慢!BUT,这种方法只有在火狐浏览器才生效,其它浏览器即使最新的chrome浏览器也不支持哦。我@#¥%……

不要急年轻人,我们来看一下vue的代码,当我们在style中加了scoped属性后

咦,这不就是我们刚刚讲过的AMCSS(属性模块)的应用吗?也就是说vue在编译的时候,把带有scoped属性的的模块,加上了一个唯一的属性,然后通过类名+属性选择器的方法来实现模块化!

其实其他框架也是用的类似的方法,我们再看一下,小程序wepy框架的实现吧?

这个是我们刚才讲过OOCSS(面对对象CSS)!!

对的,这样结合框架来讲是不是能够更能深刻理解我们刚才讲过的内容了啊?

如何按需加载css?

有时候我们需要把一些有用的常见的css放到一个common.css里面,但是当我们项目足够大的时候,common的内容就会变得异常庞大,而且难以维护。

首先我们不得不说一下当下有几个比较火的CSS预处理器,Less、Sass 、Stylus和postCss,这是一个CSS史上的巨大飞跃。他主要提供了以下功能

  • 嵌套语法

  • 变量

  • @import

  • 混入

  • 继承

  • 函数

  • 逻辑控制

了解了css预处理器,那么我们如何优化我们的common.css呢?

要想解决这个问题,我们首先来看一看LESS中的mixin是如何运作的。

  1.  // 你可以混合“类”选择器或者“id”选择器,例如:
    
     .a, #b {
    
      color: red;
    
     }
    
     .mixin-class
    
     {
    
      .a();
    
     }
    
     .mixin-id {  
    
      #b();
    
     }

以上将得到:

  1.  .a, #b {
    
      color: red;
    
     }
    
     .mixin-class
    
     {
    
      color: red;
    
     }
    
     .mixin-id {
    
      color: red;
    
     }  

小提示:当你调用混合集的时候,括号可加可不加。

  1.  .a();  //这两种调用方式效果是一样的
    
     .a;

如果你想要创建一个混合集,但是却不想让它输出到你的样式中,你可以在混合集的名字后面加上一个括号。

  1.  .my-mixin {
    
      color: black;
    
     }
    
     .my-other-mixin() {
    
      background: white;
    
     }
    
     .class {
    
      .my-mixin;
    
      .my-other-mixin;
    
     }

输出:

  1.  .my-mixin {
    
      color: black;
    
     }
    
     .class {
    
      color: black;
    
      background: white;
    
     }

好了,我们知道这个原理就可以用less中的mixins重新修改我们的common.less了,而且不会显得非常臃肿,我们可以按需加载我们的样式了,是不是很棒啊

我们的CSS模块化就讲到这里了,有什么意见或建议可以联系我哦!

——————————————————

如果你喜欢我们的文章,关注我们的公众号和我们互动吧。

浅谈CSS模块化的更多相关文章

  1. 转:浅谈CSS在前端优化中一些值得注意的关键点

    前端优化工作中要考虑的元素多种多样,而合理地使用CSS脚本可以在很大程度上优化页面的加载性能,以下我们就来浅谈CSS在前端优化中一些值得注意的关键点: 当谈到Web的“高性能”时,很多人想到的是页面加 ...

  2. 谈CSS模块化【封装-继承-多态】

    第一次听到“CSS模块化”这个词是在WebReBuild的第四届“重构人生”年会上,当时我还想,“哈,CSS也有模块化,我没听错吧?”事实上,我没听错,你也没看错,早就有CSS模块化这个概念了.之所以 ...

  3. 浅谈CSS的模块化

    一.简介 Web前端模块化:HTML模块化.CSS模块化以及JS模块化三个部分: 二.CSS模块化背景 对于小型项目来说,css的量还不至于庞大,问题没有凸显,而如果要开发和持续维护一个较为大型的项目 ...

  4. 谈 CSS 模块化

    以前看过模块化的相关资料以及解释,对模块化有了一个表皮的了解,自己也做了一些相关的实践,由于接触到的项目交小,所以也没能更好的去体现和理解模块化,但总体还是有那么一些感悟,但是如果要说怎么才能算是好的 ...

  5. 从头开始写框架(一):浅谈JS模块化发展

    博客申请下来已经过去一个月了,一直不知道写点什么,毕竟我的文笔不是很好orz. 不过既然申请下来了,不写点什么总是觉得很可惜.正好最近在自己写框架,就把自己的进程和一些心得体会分享出来吧. 写在前面: ...

  6. 浅谈css中的position

    什么是position,根据css 2.1中的描述,position和float的值决定了浏览器要采用那种定位算法来计算元素盒子的具体位置.先避开float不谈,本文主要介绍position属性的不同 ...

  7. 浅谈css中的盒模型(框模型)

    css中的盒模型是css的基础,盒模型的理解可以帮助我们进行对样式进行修改.废话不多说,进入正题: 在w3c中,CSS 框模型 (Box Model) 规定了元素框处理元素内容.内边框.边框 和 外边 ...

  8. 浅谈 CSS 预处理器: 为什么要使用预处理器?

    CSS 自诞生以来,基本语法和核心机制一直没有本质上的变化,它的发展几乎全是表现力层面上的提升.最开始 CSS 在网页中的作用只是辅助性的装饰,轻便易学是最大的需求:然而如今网站的复杂度已经不可同日而 ...

  9. 浅谈CSS盒子模型

    [摘要]盒子模型是CSS中的一个重要概念,虽然CSS中没有盒子这个单独的属性对象,但它却是CSS中无处不在的一个重要组成部分.掌握盒子模型的原理和使用方法可以极大地丰富HTML元素的表现效果,同时对于 ...

随机推荐

  1. Ambari 2.4.2 汉化

    1.ambari-web (1)apache-ambari-2.4.2-src/ambari-web/app/messages.js 该文件是KeyValue文件,3000多行.将Value部分翻译成 ...

  2. Java - static的注意点

    静态函数与静态变量无需生成对象 静态函数只能调用静态变量 装载类的时候执行静态代码块 静态函数中不能使用this /* * For test static * 2014-10-26 */ public ...

  3. Maven在导入其他项目时报错:Plugin execution not covered by lifecycle configuration

    这几天想把Spring 攻略第二版完整的学习下,所以就在网上下载了该教材的源码,寻思边看书边练习!之前有过一些Maven开发的相关经验,觉得Maven在引入jar包上的配置还是很方便的,所以这次源码的 ...

  4. Docker存储

    前言 上一篇文章中简单总结了一下docke的基础使用方法,这次我来总结一下有关docker存储方面的相关知识.本文同样建立在CloudMan的系列教程之上,有兴趣的可以直接移步. 有些人可能觉得这个很 ...

  5. 二.GC相关之Java内存模型

    根据上节描述的问题,我们知道其最终原因是GC导致的.本节我们就先详细探讨下与GC息息相关的Java内存模型. 名词解释:变量,理解为java的基本类型.对象,理解为java new出来的实例. Jav ...

  6. 基于三台主机部署phpwind

    PHPWind(简称:PW)的使命是让网站更具价值,让更多人从网络中享受便利,以提升生活品质. phpwind是一个基于PHP和MySQL的开源社区程序,是国内最受欢迎的通用型论坛程序之一.phpwi ...

  7. java_final修饰符

    1.修饰变量时,表示该变量一旦获得初始值就不可改变 final修饰的成员变量必须由程序员显示地指定初始值,系统不会进行隐式初始化 类变量:必须在初始化块中指定初始值或声明该类变量时指定初始值 实例变量 ...

  8. CVE-2016-3714 - ImageMagick 命令执行

    ImageMagick是一款使用量很广的图片处理程序,很多厂商都调用了这个程序进行图片处理,包括图片的伸缩.切割.水印.格式转换等等.但近来有研究者发现,当用户传入一个包含『畸形内容』的图片的时候,就 ...

  9. 原生JS实现各种经典网页特效——Banner图滚动、选项卡切换、广告弹窗等

    在制作网页过程中,我们可能会遇到各种常用的经典网页特效,比如Banner图片滚动.选项卡循环播放.右下角广告弹窗.评论提交展示.选项动态增删.剪刀石头布小游戏等等等...是不是感觉都见到过这些场景.那 ...

  10. js判断移动终端(手机浏览器)

    方法1: <script type="text/javascript">         var browser = {             versions: f ...