CSS设计模式之三权分立模式篇

市面上我们常常会看到各种各样的设计模式书籍,Java设计模式、C#设计模式、Ruby设计模式等等。在众多的语言设计模式中我唯独找不到关于CSS设计模式的资料,即使在网上找到类似内容,细细一看之下才发觉是南辕北辙。经过浩瀚文章搜索发掘下依旧一无所获之后,直接导致了我萌生一股写一篇CSS设计模式的冲动,至此写下这篇文章,其中叙述如有不当之处,也恳请各位提出意见,分享出您宝贵的经验。

在写页面之中,width, margin, padding这三个CSS属性可以说是用到频率最高的几个属性之一。但根据我的观点来看,许多人,甚至于大多数前端对于这三个属性的书写把握上乏善可陈,以至于兼容和灵活性不得兼顾,导致日后的开发维护成本直线上升,代码不断增长,覆盖重写样式,接着再修复一个又一个的Bug。这样的情况下,使用一种合理高效的CSS设计模式不失为一种明智的选择,个人称之为:width,margin,padding三权分立模式(以下简称三权分立模式)。

什么是三权分立模式:

说明这个模式之前,必定先要明白什么是盒子模型,你可以参考如下Firebug的盒模型截图:

注意:在图上表示margin的颜色为白色(实质是透明)。Margin比较特别,它不会影响盒子本身的大小,但是它会影响和盒子有关的其他内容,因此margin也是盒模型的一个重要的组成部分。

盒子本身的大小是这样计算的:

Width: width + padding-left + padding-right + border-left + border-right
Height: height + padding-top + padding-bottom + border-top + border-bottom

通过图中我们得知,Width(物理总宽度)/Height(物理总高度),是由width/height,padding,border三者之和来决定的。但简单浅显的盒模型一旦牵涉到CSS中,便会出现不小的意外。

假设,需要要一个300px宽,80px高的盒子,里面放一段文字,文字离边有10px间距。那么一般Html和CSS写法为:

HTML代码:


1

2

3

<div class="box">

  市面上我们常常会看到各种各样的设计模式书籍,Java设计模式、C#设计模式、Ruby设计模式等等。

</div>

CSS代码:

.box{width:280px; height:60px; padding:10px;}

来分析一下这段CSS代码,因为需要满足300px宽,且文字间隔为10px,所以Width(300px) = width(280px) + padding(10px) X 2。假设过了段时间需要改版,要求为这个Box添加1px颜色为#ccc的边框,那么我们再次找到这段CSS,开始动手修改,加个boder:1px solid #ccc;:

CSS代码:

.box{width:280px; height:60px; padding:10px; border:1px solid #ccc;}

之后测试一下,咦!似乎有点问题,哦,因为加了边框所以又多了2px像素的宽,所以要减去这2px。

CSS代码:

.box{width:278px; height:58px; padding:10px; border:1px solid #ccc;}

测试一下,问题解决了。正当欢心不已准备休息时候,设计师跑来说,根据最新要求,希望能再把文字与边距拉大,上下边距为10px,左右改为15px。继续修改:

CSS代码:

.box{width:268px; height:58px; padding:10px 15px; border:1px solid #ccc;}

经过“精确”计算后终于得出了如上的CSS结果。一次又一次的不断改版,修改的页面数量越来越大,其中的代码越发复杂,计算量也越发庞大,你只能一边为自己的精确到1px像素级的“专业”功力而沾沾自喜,而后又不得不疲于奔波与各个页面中的宽高计算。就这样一个又一个只有你才能明白的代码出现了!

如何才能摆脱这样的无效代码问题呢?这里使用CSS三权分立模式可谓是最佳解决方案。

CSS三权分立模式的核心在于完全分离width,margin,padding这三个CSS属性,一个class里只能拥有三个属性里的其中一个,而通过增加一个额外标签使得能够通过多个class控制元素的外观,解除三者的耦合。

就如以上问题为例,重写300px宽,80px高的盒子,文字离边有10px间距。使用三权分立模式下的写法为:

Html代码:


1

2

3

4

5

<div class="box">

  <div class="roundBox">

    市面上我们常常会看到各种各样的设计模式书籍,Java设计模式、C#设计模式、Ruby设计模式等等。

  </div>

</div>

CSS代码:

.box{width:300px; height:80px;}
.box .roundBox{padding:10px;}

这里的宽度、高度、间距的数值同需求完全一致,无需计算。接下来遇到改版问题为Box添加1px颜色为#ccc的边框,只需这么修改:

CSS代码:

.box{width:300px; height:80px;}
.box .roundBox{padding:10px; border:1px solid #ccc;}

直接为内部标签class上添加边框,单刀直入添加边框属性即可。最后一关如需把文字与边距拉大,上下边距为10px,左右边距为15px。

CSS代码:

.box{width:300px; height:80px;}
.box .roundBox{padding:10px 15px; border:1px solid #ccc;}

注意:上例可以看到padding与border其实在“宽度占有”的性质上是一致的(从某个角度来说把border设置为透明再设置一定宽度就是变相的padding),所以完全可以让这俩个属性写在同一class里,二者性质类同,无需再分离这俩个属性。

我们可以看出使用三权分立模式书写代码的简洁与高效,而且从可读性及维护性上有质的飞跃。唯一多的就是为内部添加一个额外的标签保证padding/border不会与width产生干扰,解除二者的耦合关系,这也是获得可维护性需要付出代价。

在刚才的例子中似乎忽略了另外一个属性——Margin。这里的Margin在三权分立模式中的立场相对于上面的width与padding耦合强度下似乎并没有那么明显,但以我的个人观点上来看:Margin的分离是三权分立模式之中最为重要的一环。为什么Margin在这里如此重要?因为这里可以看出一名前端开发人员功力素养——代码可重用性。

提及代码可重用性,任何一门计算机语言都有所阐述,而CSS代码可重用性对于一名前端来说不亚于对JS重构的重要性。CSS的可重用性会直接影响HTML代码的可复用性。

再回头看如上代码,这里的盒子仅仅是一个页面的一小部分而已。纵观整个网站,不会也不可能出现只需要一个模块的页面。每写一个模块,将来就要和各式各样的页面进行整合、维护、开发。

继续上面例子,现在我们做好了这个模块,开始行进页面的整合。假设这个模块所放的位置同左边的间隔需为10px,同上方模块间隔15px,可能会这么写:

CSS代码:

.box{width:300px; height:80px; margin:15px 0 0 10px;}
.box .roundBox{padding:10px 15px; border:1px solid #ccc;}

这里的写法原本是没有大过错的,既然提出了Margin分离的重要性,当然不会那么简单的糊弄过去的。记住:你所写的每一个模块的代码将来都会有被复用到另外一个页面(项目)的可能性,甚至于我曾看到过一个模块被几个不同的页面反复重用。

说到这里,继续下去,假设这个模块需要在另外一块地方使用,而那里设计位置要求必须是同上方间隔为0px,离左边5px。内容结构完全一致,遇到这样的情况,你会如何解决?

一般遇到这种情况,第一种做法有人会对原先代码视而不见,直接重写一份新的HTML和CSS。你别说,我还真遇到过。第二种做法或许会这么修改HTML和CSS:

HTML代码:


1

2

3

4

5

<div class="box anotherPlace">

  <div class="roundBox">

    市面上我们常常会看到各种各样的设计模式书籍,Java设计模式、C#设计模式、Ruby设计模式等等。

  </div>

</div>

CSS代码:

.box{width:300px; height:80px; margin:15px 0 0 10px;}
.box.anotherPlace{margin:0 0 0 5px;}
.box .roundBox{padding:10px 15px; border:1px solid #ccc;}

添加一个结合选择器限定覆盖原先的margin属性,这一类做法是比较聪明的办法,如果这个模块多次重用则添加多个结合选择器即可,我曾今也常使用类似做法来修复各类的Bug。

或许上面的方法的确可以解决类似的问题,但作为一名喜欢没事瞎琢磨点东西的我来说总觉得有什么地方不对。在不断的思考下最终发现这个并非是真正重用,只是一种“修复”,从某个角度上来说,这不过是为这个模块打一个“补丁”。一个又一个结合选择器不就是一个个小的补丁嵌入到不同的页面中去么,依然会有那么多多余的代码会被写入,这并非是理想中的重用。

理想的重用是不添加任何代码,仅仅使用原先的代码就能完全搞定所有的模块,虽然只是理想状态,但我们可以不断的向这个目标靠近。在研究一些CSS库后,发现很多地方同自己的想法不谋而合,其中Margin分离就是其中之一,我们来看看以下代码片段:

CSS代码:

.m10{margin:10px}
.m15{margin:15px}
.m30{margin:30px}
.mt5{margin-top:5px}
.mt10{margin-top:10px}
.mt15{margin-top:15px}
.mt20{margin-top:20px}
.mt30{margin-top:30px}
.mt50{margin-top:50px}
.mt100{margin-top:100px}
.mb10{margin-bottom:10px}
.mb15{margin-bottom:15px}
.mb20{margin-bottom:20px}
.mb30{margin-bottom:30px}
.mb50{margin-bottom:50px}
.mb100{margin-bottom:100px}
.ml5{margin-left:5px}
.ml10{margin-left:10px}
.ml15{margin-left:15px}
.ml20{margin-left:20px}
.ml30{margin-left:30px}
.ml50{margin-left:50px}
.ml100{margin-left:100px}
.mr5{margin-right:5px}
.mr10{margin-right:10px}
.mr15{margin-right:15px}
.mr20{margin-right:20px}
.mr30{margin-right:30px}
.mr50{margin-right:50px}
.mr100{margin-right:100px}

以上其实就是一个CSS公用文件的一段代码摘抄,其思想引入这些公用的CSS类,单独定义Margin。通过简写命名,即使用头字母来记忆里面的属性,例如:mt15就是margin-top:15px的意思,下面来看我们如何使用它吧。

原先那个模块整合到页面中需要离上15px,离左10px,使用CSS库的做法就是这么写的:

HTML代码:


1

2

3

4

5

<div class="box mt15 ml10">

  <div class="roundBox">

    市面上我们常常会看到各种各样的设计模式书籍,Java设计模式、C#设计模式、Ruby设计模式等等。

  </div>

</div>

CSS代码:

.box{width:300px; height:80px;}
.box .roundBox{padding:10px 15px; border:1px solid #ccc;}

剔除多余的结合选择器,选择可以高度重用的CSS属性,这里你或许觉得没有多大意义,但如果需要把这个模块放入别的页面呢,就如上面又要放置在同上方间隔为0,离左边5px的地方,此效用开始发挥作用了,直接修改HTML代码,无需任何的CSS的修改,模块的高度复用:

HTML代码:


1

2

3

4

5

<div class="box ml5">

  <div class="roundBox">

    市面上我们常常会看到各种各样的设计模式书籍,Java设计模式、C#设计模式、Ruby设计模式等等。

  </div>

</div>

这样子你还会认为原先的选择器做法是正确的么。个人认为:Margin是阻碍模块重用的最大杀手,因为任何一个组件都或多或少会添加Margin这个属性来间隔开自身同他人的距离,直接拷贝原先代码,则先前适用Margin的属性反而成为了新组件位置的阻碍,及时分离Margin可以有效的解除组件同Margin的耦合,达到重复使用的效果。

这就是三权分立模式的全貌,width,margin,padding这三个属性完全的分离,大大提高的代码的可复用性,可维护性,解除三者的耦合,为将来的开发维护打下坚实的基础,也是CSS设计模式的优势所在。

当然设计模式也有他的二个弊端:

复杂性:获得可维护性往往要付出代价,那就是代码可能会变得更加复杂、更难被新手理解。三权分立模式中的导入公共CSS重用模块,书写多个class合并代替使用单一class都是所需要考虑和规范的。

性能:多数的设计模式对代码的性能会有所拖累,这种拖累可能微不足道,也可能完全不能接受,这取决于项目的具体要求。这里的三权分立模式就需要额外添加一个内部标签来分离padding属性。

实现设计模式比较容易,而懂得应该在什么时候使用什么模式则较为困难。你应该尽量保证所选用的模式就是最恰当的那种,并且不要过度牺牲性能。这对于个人开发甚至于一个团队的开发维护都具有莫大的帮助,个人认为使用三权分立模式是利远大于弊的,希望你也能够了解他的思想与作用,在团队开发中使用他,维护他,三权分立模式现实应用可以帮助你和你的团队开发出更加茁壮的代码。

写了那么多,只希望你能了解到使用合理的CSS设计模式可以帮助我们优化代码,其最终目的是为了CSS开发维护的高效性和可维护性,而其魅力也在于此。谢谢!

时间: 2024-10-14 06:56:45

CSS设计模式之三权分立模式篇的相关文章

CSS设计模式之三权分立模式篇 ( 转)

转自 海玉的博客 市面上我们常常会看到各种各样的设计模式书籍,Java设计模式.C#设计模式.Ruby设计模式等等.在众多的语言设计模式中我唯独找不到关于CSS设计模式的资料,即使在网上找到类似内容,细细一看之下才发觉是南辕北辙.经过浩瀚文章搜索发掘下依旧一无所获之后,直接导致了我萌生一股写一篇CSS设计模式的冲动,至此写下这篇文章,其中叙述如有不当之处,也恳请各位提出意见,分享出您宝贵的经验. 在写页面之中,width, margin, padding这三个CSS属性可以说是用到频率最高的几个

JavaScript设计模式之策略模式(学习笔记)

在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选择学习策略模式. 策略模式:定义了一系列家族算法,并对每一种算法单独封装起来,让算法之间可以相互替换,独立于使用算法的客户. 通常我并不会记得“牛顿第一定律”的具体内容,所以我也难保证我会对这个定义记得多久……用FE经常见到的东西来举个例子说明一下: $("div").animation(

设计模式-12 MVC模式

一 MVC设计模式 MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式,它是一个存在于服务器 表达层的模型,它将应用分开,改变应用之间的高度耦合 MVC设计模式将应用程序分离为3个主要的方面:Model,View和Controller 1 Model Model代表了描述业务路逻辑,业务模型.数据操作.数据模型的一系列类的集合.这层也定义了数据修改和操作的业务规则. 2 View View代表了UI组件,像CSS,JQuery,html等.他只负责展示从co

JS设计模式(门面模式)

<!--JS设计模式(门面模式)--> // 门面模式的概念:简化API接口 最经典的就是事件 // 做一件事情: 必须要调用2个函数分别是 a , b //案例:获得页面上多个元素并设置css样式 window.onload=function(){ setCss(["div1","div2","div3"],{ background:"blue", color:"#fff" }); } fun

设计模式之总述篇

以下是对<Head First 设计模式>中提到的OO原则和设计模式的总结. OO原则和设计模式的联系:模式可以让我们建造出具有良好OO设计质量的系统.模式被认为是历经验证的OO设计经验. OO设计原则: 1.封装变化:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起: 2.多用组合,少用继承:良好的OO设计必须具备可复用.可扩充.可维护三个特性. 3.针对接口编程,而不是针对实现编程:"针对接口编程"真正的意思是"针对超类型(sup

JAVA设计模式之代理模式

学编程吧JAVA设计模式之代理模式发布了,欢迎通过xuebiancheng8.com来访问 一.概述 给某一个对象提供一个代理,并由代理对象来完成对原对象的访问.代理模式是一种对象结构型模式. 二.适用场景 当无法直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口. 三.UML类图 四.参与者 1.接口类:Subject 它声明了真实访问者和代理访问者的共同接口,客户端通常需要针对接口角色进行编程. 2.代理类

C++设计模式之建造者模式(二)

3.省略指挥者Director的建造者模式 指挥者类Director在建造者模式中扮演非常重要的作用,简单的Director类用于指导具体建造者如何构建产品,它按一定次序调用Builder的buildPartX()方法,控制调用的先后次序,并向客户端返回一个完整的产品对象.Direcotr针对抽象的建造者进行编程,如果需要不同的建造者,只需把建造者传入指挥者类,无需修改之前的代码. 在有些情况下,为了简化系统结构,可以省略指挥者Director,指挥者不再指导产品的创建过程.而是在Builder

设计模式3——建造者模式

1解释 1.1定义 将一个复杂对象的构建与他的表示分离,使得同样的构建可以创建不同的表示. 1.2分析 首先我们看看一般的实例化对象的方法,如下面代码: Roboter roboter = new Roboter(); roboter.setmArm("arm"); roboter.setmBody("body"); roboter.setmHead("head"); roboter.setmFoot("foot"); 对于R

被遗忘的设计模式——空对象模式(Null Object Pattern)

GoF(四人帮)那本<设计模式 可复用面向对象软件的基础>可谓是设计模式方面的经典之作,其中介绍的23种设计模式, 也可谓是经典中的经典.但是,设计模式的种类绝不仅仅是这23种,除此之外还有很多巧妙可爱的设计模式值得我们学习.这些 被遗忘的设计模式,也可以堪称经典之作.今天我们来一起学习被遗忘的设计模式--空对象模式(Null Object Pattern). 一起看看这个模式会带给我们怎样的惊喜? 一.Pattern name Provide an object as a surrogate