CSS模块化(六) 模块化设计

6. 模块化设计

6.1 样式的作用域──页面重构中的模块化设计(一)

模块化设计我已经提过很多了,都是跟模块化相关的,不过之前一直没有讲到具体实现方面的内容,只是一些思维。这次重点讲一下实现方面的内容,权当到目前为止我对模块化的一些总结整理。

要做好模块化,我觉得理解好样式的作用域是很重要的。写过程序的同学应该都知道,变量是有作用域的(不知道的同学自己去问谷歌,这里就不作解释了),样式的定义也同样存在着作用域的问题,即定义的作 用范围,很容易就能理解,如下面的p的作用域:

 CODE:

/*作用域:全局*/ p{text-indent:2em;}

 

 CODE:

/*作用域:.demo这个类中*/ .demo p{color:#000000;}

    样式选择器的优先级是学习样式的基础知识,一起简单回顾下:

● 标签的权值为0,0,0,1

● 类的权值为0,0,1,0

● 属性选择的权值为0,0,1,1

● ID的权值为0,1,0,0

● important的权值为最高1,0,0,0

使用的规则也很简单,就是 选择器的权值加到一起,大的优先;如果权值相同,后定义的优先 。虽然很简单,但如果书写的时候没有注意,很容易就会导致CSS的重复定义,代码冗余。从上面我们可以得出两个关键的因素:

1权值的大小跟选择器的类型和数量有关

2样式的优先级跟样式的定义顺序有关

了解样式的权值后有什么作用呢?比如可以这样用:举一个最简单的例子

CODE:

body{color:#555555;}.demo{color:#000000;}

 

CODE:

<p>这里的文字颜色受全局定义的影响</p>

<div class="demo"><p>这里的文字颜色受类demo定义的影响</p></div>

<p class="demo">这里的文字颜色受类demo定义的影响</p>

知道了样式的权值,你就知道上面例子的表现是怎样的了。进一步的应用,就是模块化了。

再来说说作用域,相信大家很容易就会想到全局公共这些词,关注过模块化的同学应该都知道,网上说得最多的一种模块化,就是像 headerfooter这样的以大区域划分。在去年web标准交流会(页面重构合理化讨论)上,克军提出了样式的三层架构”——公共规则层、公共模 块层、项目层。这些都有它们适用的范围,而且最大的优点是容易理解和应用。这里也不再作重诉了,上面已经讲过。

我在这一块的划分上,有点类似克军的样式的三层架构,有一点小的差别,我是以作用域来分的: 公共级(全局)、栏目级 (局部公共)、页面级 。如何划分这个作用域呢?很简单,全局的global就是公共级的;只在栏目中用到的局部global是属于栏目级的;只影响单个页面的就是属于页面 级的了。

最后几点要特别注意的:

除了标签选择器之外,哪些类是使用于公共级、栏目级中的,如

 CODE:

.tx_hit{color:#FF0000 !important;}

的适用范围是公共级的,应该放于全局的定义中。但,如果它只影响于某个栏目,那么就应该把它放于栏目级的作用域中。

● 标签选择器一般属于栏目定义,有时会用于公共级作用域中,除了最基础的reset之外,应尽可能少使用在公共级定义中

● 可继承的属性定义使用时须注意影响的范围,特别是在标签选择器中使用时

● 同类选择器无加权

接下来的内容就是以这个为基础的,希望大家能理解样式的作用域,对于后继内容的理解会很有帮助。

6.2 栏目级作用域──页面重构中的模块化设计(二)

在《 样式的作用域── 页面重构中的模块化设计(一)》中,我将样式的作用域分为了三个部分:公共级(全局)、栏目级(局部公共)、页面级。公共级(全局)容易理解,即影响站点中所有页面。简单解释下栏目级(局部公共)和页面级:

页面级

可分为两种情况:在多个页面间,页面级作用域指针对某一单独的页面定义;在同一个页面中,页面级作用指针对某 一标签的定义。它将决定最终的页面效果。

栏目级(局部公共)

介于全局与单个页面之间的一个作用 域,影响一个栏目(或某区域)。通常以某一类选择符做为开始,以包含选择符的方式将样式定义限定在某一区域中。

 CODE:

/* 只影响demo这个区域 */

.demo a{...}

.demo p{...}

.demo .title{...}

需要消化下的内容,决定一个样式定义是属于哪个作用域的因素有以下两点:

样式定义所在样式文件中的位置。(同样的一个定义,放在不同的位置,所影响的范围会有所不同。)

HTML中绑定demo这个类的标签位置。(同样一个类,绑定在body标签和绑定在页面中某个标签上,所影响的范围也会不同。)

在一个站点中,可能会分为几个不同的栏目,同一个栏目中,一般风格会保持一致。而不同的栏目间,相似的风格则不一定会相同。即使是全站通用的模 块,如翻页,也可能会因为栏目的不同而会有一些差异,比如链接的颜色等等。使用栏目级的样式定义,能很好的减少代码的冗余,提高模块的复用性。

另外需要在思维上注意的一点,以作用域划分,并不意味着有着对应的文件,可能有些同学会习惯的以为一个作用域就应该对应着一个文件。比如一个小的 栏目,可能只有两三个页面,这时我们就不一定需要再把栏目级的定义单独出来一个文件,而是与页面级的定义一起放在一个文件里,像这样:

CODE:

/* S 栏目级定义 */

.class{...}

/* E 栏目级定义 */

/* S 页面级定义 */

.page{...}

/* E 页面级定义 */

 

6.3 继承──页面重构中的模块化设计(三)

前面我们了解了 样式的作用域的分类  栏目级作用域。在权值中,还有一个很重要的因素,需要做下补充,起因是这样的,有个同学在CSS森林群里问了个问题:根据样式权值两个关键的因素

权值的大小跟选择器的类型和数量有关

样式的优先级跟样式的定义顺序有关

可以知道,如果10个标签选择器的权值应该比一个类选择的权值高,像这样:

 CODE:

div div div div div div div div div div div{color:blue;}

.c10{color:red;}

 

CODE:

<div class="c1">

  <div class="c2">

    <div class="c3">

      <div class="c4">

        <div class="c5">

          <div class="c6">

            <div class="c7">

              <div class="c8">

                <div class="c9">

                  <div class="c10">

                     <div>这段文字是什么颜色?</div>

                  </div>

                </div>

              </div>

            </div>

          </div>

        </div>

      </div>

    </div>

  </div>

</div>

先别急着看 答案 ,分析下。意料之中?如果 这样 呢?

CODE

div{color:blue;}

.c10{color:red;}

是不是跟想的不太一样?难道前面所说的权值是有问题的?前面讲的权值并没有问题,不过漏了一个重要的规则: 继承的权值小于 0,0,0,1

样式的继承

指被包在内部的标签将拥有外部标签的样式性质。

继承最大的意义在于可以减少重复的定义,比如要定义整个页面的文本颜色,只需要定义bodycolor样式,body里的所有标签都会继承 bodycolor定义。是不是很方便?方便是相对的,当你想要为body内部分标签定义另一种文本颜色时,继承也许会成为增加重复定义、降低性能的祸 首。

并不是所有的样式定义都具有继承的性质,整理了一下常用有继承性的定义, 这些定义在使用的时候要比较注意。

简单分析下上面的例子,最后一部分的代码:

 CODE

<div class="c10">

    <div>这段文字是什么颜色?</div>

</div>

 

当定义了c10后,根据权值,类定义的权值是0,0,1,0,应该是比div这个定义0,0,0,1要高的,但由于div是直接定义到标签上的, 比起从c10的定义中继承来的定义权值更高。稍微改下就清楚了:

CODE:

<div class="c1">

  <div class="c2">

    <div class="c3">

      <div class="c4">

        <div class="c5">

          <div class="c6">

            <div class="c7">

              <div class="c8">

                <div class="c9">

                  <div class="c10">

                     <p>这段文字是什么颜色?</p>

                     <div>这段文字是什么颜色?</div>

                  </div>

                </div>

              </div>

            </div>

          </div>

        </div>

      </div>

    </div>

  </div>

</div>

 

 修改后的例子 可以看到,p标签继承了c10的定义,显示为红色。因此,在使用标签选择器的时候,应特别注意它的作用域,个人的建议是,除了最基本的reset之外,在 公共作用域中最好不要使用标签选择器,在栏目级作用域中也应尽可能的少用。

常用有继承性的样式定义:

● text-indent

● text-align

● layout-flow

● writing-mode

● line-break

● white-space

● word-wrap

● list-style

● list-style-image

● list-style-position

● list-style-type

● font

● font-style

● font-variant

● font-weight

● font-size

● line-height

● font-family

● color

● text-transform

● letter-spacing

● word-spacing

6.4 模块化的核心思想──页面重构中的模块化设计(四)

有不少同学觉得前面的内容过于简单了,对于 样式的作用域的分类  栏目级作用域  继承等内容的确十分基础,不过基础还是很重要的。下面就一起进入这个系列真正的主题——“模块化吧。

早在Qzone4.0的页面架构中已经在项目中开始摸索提高代码复用的方法,只不过当时并没有很清晰的认识到模块化这个思想。从去年的《 从宜家的家具设计 讲模块化》开始,模块化成了我主要的一个学习方向。借着无数的提问、思考、讨论,渐渐形成了一个比较清晰的、较为完整的方案。后面的内容,更多的是出于我在实际项 目中总结出来的方法,虽然已经尽可能为出现的问题提供了解决方法,不过还是少不了会有些我没遇到过或没考虑到的,欢迎各位指出。

首先来了解下页面重构中模块化的核心思想: HTMLCSS通过一定的规则进行分类、组合,以达到特定HTMLCSS在特 定范围内最大程度的复用。 有三个关键词: 规则  特定范围  最大程度的复用 。怎么理解呢?

规则

编写模块时需要遵循的规范

特定范围

模块可使用的范围。与样式的作用域有关,大部分模块的使用范围仅仅是某一个栏目或站点。

最大程度的复用

做最少的修改即可重复使用。很多同学都把复用理解成不用修改的直接使用,但在页面 制作中,由于实际的项目环境,基本是不可能做到一个模块走天下的。不同的栏目会有不同的需求,大家应该都多少有所体会,我就不多讲了。

从实际出发,才能最终服务于实际。我们知道一个HTML标签可以绑定多个样式,所以我们可以这样去定义一个模块:

CODE:

<div class="class-a class-b class-c">

    ...

</div>

不少同学已经知道这个方法了,而且还很形像的称之为拼样式。这样的定义很容易引出其它的问题,比如样式类的个数多少个适合?样式类如何命名? 等等。下面讲下我的方法,从前面我们学到的样式作用域及模块化的核心思想,我们可以把样式进行一个分类,像这样:

 CODE:

.mode-a{/* 定义一个模块 */}

.type-a{/* 模块中的差异化定义 */}

.mode-name{/* 针对单个模块的个性化定义 */}

 

CODE:

<div class="mode-a type-a mode-name">

    ...

</div>

上面的“mode-a”,我称它叫为基类“type-a”扩展类“mode-name”模块名,作用分别是:

基类

(基础样式)模块的基础表现。包含了模块中大部分的状态。

扩展类

(扩展样式)用于对使用基类的模块进行小范围的修改

模块名

模块在某一作用域中的唯一名称。

这里有一个 简单的例子 可以帮助理解。

也有同学主张用ID去表示模块名,我认为这种方式扩展性比较差,而且很容易与开发的ID冲突,不过也不失为一个方法。

6.5 基类、扩展类──页面重构中的模块化设计(五)

基类  扩展类 是这个系列的主要内容,上一篇《 模块化的核心思想──页面重构中的模块 化设计(四)》中只是简单提了一下,我们再深入的来了解下它们。

一般所使用的模块化的方法,就是以某一个类做为定义的开始,比如:

 CODE:

/* S 图片列表 */

.pic_lists li,

.pic_lists li img{float:left;width:122px;height:122px;margin-bottom:8px;}

.pic_lists li{list-style:none;margin:0 0 0 6px;text-align:center;}

.pic_lists li .pic{display:block;border:1px solid #476081;}

/* E 图片列表 */

/* S mtv列表 */

.mtv_lists{width:930px;height:130px;}

.mtv_lists li,

.mtv_lists li img{float:left;width:120px;margin-bottom:8px;}

.mtv_lists li{list-style:none;margin:0 10px 0 0;text-align:center;}

.mtv_lists li img{height:90px;border:1px solid #476081;}

.mtv_lists li .pic{display:block;width:120px;height:90px;margin-bottom:8px;}

/* E mtv列表 */

 

这个例子: 两个列表模块 。这种方式是比较常见的,可以很好的将一个模块独立出来。如果使用新学习到的方法来写这两个列表模块,应该是怎样?

基类(基础样式)模块的基础表现。包含了模块中大部分的状态。也就是说,当出现多个类似的模块时,基类包含了这些模块的大部分的效果(或者理解为公共的部分),在基类的基础上,我们可以通过添加很少的代码 ——扩展类,来达到所需要要效果。像这样:

CODE:

/* S 列表 基类 */

.mode_lists li,

.mode_lists li img{float:left;width:122px;margin-bottom:8px;}

.mode_lists li{list-style:none;margin:0 10px 18px 0;text-align:center;}

.mode_lists li img{border:1px solid #476081;}

/* E 列表 基类 */

/* S 图片列表 */

.pic_lists li,

.pic_lists li img{height:122px;}

.pic_lists li{margin:0 0 8px 6px;}

.pic_lists li .pic{display:block;border:1px solid #476081;}

/* E 图片列表 */

/* S mtv列表 */

.mtv_lists{width:930px;height:130px;}

.mtv_lists li,

.mtv_lists li img{width:120px;height:90px;}

.mtv_lists li .pic{display:block;margin-bottom:8px;}

/* E mtv列表 */

 

可能你会觉得这样的样式不就多写了,还得把原先的模块类变成两个。的确不是所有的模块都值得这样去做,于是我们可以得到一种偷懒的作法,把其 中一个模块直接变成基类。对于经常会被使用的模块,像图片列表、播放列表等,这种写法在代码的复用和效率会有一定的提高。一般情况下只需要做下简单的修改 即可应用,来看一个复杂些的例子:

一个带头像的消息列表(A

 

看看这两个图,在脑中先想想如果是你,你要怎么实现。……5分钟过去了……差不多有方案了,按上面的思路,基类是包含了大部分的效果的,也就是说 基类应该能满足大部分效果的需要,两个模块间差异的地方,可以通过扩展类来完成。当然前提是这两个模块有能找到类似的点,能够形成基类。

在这两个模块中,我们不难看出,A模块和B模块在信息的部分是很类似的,虽然B模块的列表不需要A模块的评论部分,但这并不影响B模块的表现。所 以我们可以把这两个模块看成的类似模块。另个,以哪个为基类呢?从满足大部分效果这个要求来看,很明显A模块做为基类是要比B模块做为基类更合适的,如果 用B模块做基类,那么需要写更多的扩展类来满足A的需要。另外还有一个重要的点,之所以选择A模块为基类,是因为A在栏目中被更多的页面使用。

OK,来看看A模块怎么实现(样式部分):

 CODE:

/* S 消息 基类 */

.mode_message{position:relative;padding:8px 3px 8px 48px;

border-bottom:1px solid #DAECF6;_zoom:1;line-height:1.3;}

.mode_message .user_info{position:absolute;left:3px;top:10px;}

.mode_message .user_info .pic img{width:35px;height:35px;}

.mode_message .mode_message_cont{color:#797979;

word-break:normal;word-wrap:break-word;}

.mode_message .mode_message_cont .info{display:block;zoom:1;}

.mode_message .mode_message_cont .info .music_name{color:#22639B;}

.mode_message .mode_message_cont .info .op_music{display:none;}

.mode_message .mode_message_cont .info:hover .op_music,

.mode_message .mode_message_cont .info.hover .op_music{display:block;position:absolute;right:5px;top:7px;

background-color:#FFFFFF;}

.mode_message .msg{padding:2px 0;word-break:normal;word-wrap:break-word;}

.mode_message .mode_message_cont .op{margin-bottom:3px;}

.mode_message .time{display:inline-block;*display:inline;*zoom:1;font-size:10px;}

.mode_message .msg .p_zt_l,.mode_message .msg .p_zt_r{display:inline-block;*display:inline;*zoom:1;

width:13px;height:8px;background:url(img/_g_other.png) no-repeat -17px -17px;

vertical-align:text-middle;*vertical-align:middle;}

.mode_message .msg .p_zt_r{background-position:0 -28px;}

.mode_message .write_back .cont{margin-bottom:2px;padding:5px;background-color:#EAF6FA;_zoom:1;}

.mode_message .write_back .cont .cont{border-left:1px solid #ABCFE1;}

.mode_message .write_back .cont .zt{*overflow:hidden;}

.mode_message .write_back .cont .zt2{*padding-right:6px;}

.mode_message .write_back .cont .zt textarea{width:100%;height:40px;padding:0 2px;

border:1px solid #D1E1EC;line-height:20px;color:#4F4F4F;}

.mode_message .write_back .cont .zt .normal textarea{height:23px;color:#B1B4B8;}

.mode_message .write_back .cont .zt .normal .op{display:none;}

.mode_message .write_back .cont .op{margin:5px 0 0;}

.mode_message .write_back .cont .op .bt_v2{padding:0 2px;vertical-align:middle;}

.mode_message .write_back .cont .zt{width:98.5%;*width:99.9%}

.mode_message:nth-last-child(1){border-bottom:none;}

/* E 消息 基类 */

 

别忘了提示条,虽然是用于模块中,但它应该是可以被更广泛使用的模块,因此我把它单独提了出来:

CODE:

/* S 提示条 基类 */

.mode_hint{position:relative;margin:3px 0;padding:5px;

background-color:#FFFEAB;color:#000000;_zoom:1;}

.mode_hint .op{position:absolute;right:8px;top:5px;}

.mode_hint .op a{color:#000000;}

/* E 提示条 基类 */

还有像按钮、全局定义这些内容,就不列出了。完整的可以看: 基类、扩展类实例 。例子中可以看到,扩展类的定义很少,只是一些简单的定义,像B模块:

 CODE:

/* S 消息 扩展 */

.message_nopic{padding-left:0;}

/* E 消息 扩展 */

只需要一句,将头像去掉即可。

6.6 CSS模块的注释——页面重构中的模块化设计(六)

从前面的内容我们已经知道,样式是可以分成各个模块去写的,如何表示各个模块的作用及它们之间的关系呢?CSS的注释是不二的选择。

与普通的注释不同,模块的注释需要一些更详细的内容,比如:功能说明、模块版本、关联信息等等。 像 《基类、扩展类──页面重构中的模块化设计(五)》中例子的注释,显然是比较简单的。为了减少不必要的沟通,我们可以使用较为固定的格式去完成这个注释。

举个例子:

 CODE:

/**

  * @name:mode_name

  * @author:ghostzhang

  * @version:1.0

  * @type:基类

  * @explain:Demo

  */

.mode_name{...}

.mode_name h2{

    ...

}

.mode_name .cont{

    ...

}

/* @end **/

/**

  * @name:mode_name_b

  * @author:ghostzhang

  * @version:1.0

  * @type:扩展类

  * @explain:Demo

  * @dependent:mode_name

  */

.mode_name_b{...}

.mode_name_b h2{

    ...

}

.mode_name_b .cont{

    ...

}

/* @end **/

 

从注释中就可以知道mode_name_bmode_name_a之间的关系。

主要的关键字有:

@name

标明模块的名称

@author

标明模块的作者

@version

标明该模块的版本

@explain

功能说明

@relating

标明该关联的模块

@dependent

标明该所依赖的模块

@type标明该模块的类型:公共、基类、扩展类

需要注意的规则:

“/**”标记模块的开始

“/**”到第一个“*/”作为模块相关信息的说明,包含关键字

关键字以==@==开头,“:”后开始到“*”的内容为相关的值,即:

@关键字:*

“/* @end **/”标记模块的结束

模块注释内不可嵌套

提供了一个小工具( cssModeCODE: )帮助大家填写样式模块的注释。

 

展开阅读全文

没有更多推荐了,返回首页