页面重构“鑫三无准则” 之“无宽度”准则

一、关于“鑫三无准则”

“鑫三无准则”这个概念早在去年我写“关于Google圆角高光高宽自适应按钮及其拓展”一文时就已经提到了。这是自己在页面重构的经验中总结出来的一套约束自己CSS的准则,即“无宽度”、“无图片”和“无浮动”,目的是使CSS布局模块化以及增强可扩展性。

此准则是针对我个人的,可能没有什么适用性,也可能会对您的学习有所启发,所以这里还是简单分享下。共三个准则,每个准则内容都较多,本文就只简单讲讲“无宽度准则”。

二、为什么要“无宽度”

先说点题外话。我个人非常不喜欢“切图”一词,每次项目经理叫我:“XX,麻烦把这张图切一下”的时候,心里总是有点不畅快。“切图”一词有将设计图切割拼接之意,我们或许都经历过这类“切图”的阶段,这是个缺少创造,缺少艺术,缺少技术含量的阶段,这是个犹如搭积木般只需要幼儿园智商就能完工的阶段。

一提到“切图”一词,我脑中闪现的就是:分割图片,量体裁衣,计算宽度,页面元素无缝拼接,然后形成页面。我刚接触CSS那会儿就是这么做的,现在回首看看,当时的那种“切图”的做法真是差劲得连拜月教主都不如。

具体描述当时的做法,就是精确测量、计算每个元素的宽度,计算的时候还考虑到marginpadding以及border,总是精确到像素级,然后使用浮动进行无缝拼接,哇咔咔,当时的我还是很沾沾自喜的,因为页面上的宽度啊什么的都是精确到每一像素,每块元素都进行准确的计算,是多么的认真、工作多么的努力啊!
现在看来,当时的那些“认真”、“努力”什么的都是浮云,完全就是公公背儿媳妇过河——吃力不讨好!

当时的那种做法就称之为“切图”,是很初级和急需提高的阶段。为什么说这种“切图”式的做法很低级呢?一是开发效率低下(要计算宽度什么的);二是结构的重用性和可扩展性就是个高邮咸鸭蛋;三是页面的日后可维护性就是坨熊猫便便(错位等bug像要债的一样三天两头串门)。

打个形象的比方,这类宽度计算元素拼接的做法就好比用坚固的砖头砌房子,一块一块的摞起来。最后的页面看似紧密坚固,但是一旦地震一来,“房子”会以迅雷不及掩耳的速度垮掉,而那些横版的木制房却总能在强震中幸存下来。你有没有注意到,每当台风来的时候,最先倒掉的都是平时那些看似坚固的电线杆,但是却从未听说过柳树被风吹倒的。

使用宽度计算+横向拼接的做法不仅浪费精力、开发成本,最终实现的页面其实也是比较脆弱的。举个实际点的例子,比如新浪微博内容列表布局,见下图:
新浪微博内容布局 张鑫旭-鑫空间-鑫生活

我用firebug看了下其布局的方式,结果就是定宽的浮动布局。左边头像左浮动,宽度56像素;右侧内容484像素,右浮动。如下图所示:
新浪微博微博列表布局 张鑫旭-鑫空间-鑫生活

这是个比较简单的两栏布局,我估计不少同行会认为,这里就应该宽度限定,左右浮动,这也是目前主流布局方式。但是主流的方法并不一定是最好的方法,就此例子而言,没有左右padding/margin/border等属性,所以右侧栏的宽度(484px)确定貌似还是比较简单的(事实上还是要去量一下,这是可避免的劳力成本);但是,其扩展性和重用性则完全不及格了,首先,这里的列表不可能放在500像素宽的div中(没有了重用性),日后要是网站改版,总体宽度增加,那么显然,这里的宽度又要重新计算,这就缺少了扩展性;同时,这种浮动布局会带来一些副作用,首先是浮动本身的代码成本,其次是清除浮动所需要的成本(见下图)。

//zxx:这里的width:100%让IE6/7下li元素haslayout,可修复浮动塌陷的问题,但是个人是不推荐这种做法,要是日后此标签需要增加左右的margin/padding值,那就有活干了。

清除浮动使用的代码 张鑫旭-鑫空间-鑫生活

所以,如果以CSS模块化以及重用性为基本要求的话,这里的布局显然要“无宽度”,最大限度的利用标签本身的特性,这样,CSS代码成本又小,又利于日后的扩展与维护,何乐而不为呢?
我自己归结的这个“无宽度”准则并不是自己随便YY臆想出来的,是时刻以“模块化和重用性”作为页面布局基本要求下的必然产物。固定的宽度值限制了页面内容的重用性和扩展性,所以,要想页面布局具有较高的重用性和扩展性,我们需要遵循“无宽度”准则。

我们究竟是在“页面切图”还是在“页面重构”,或许就体现在一些小的细节与实现方式上。

三、“无宽度”准则之实践

“无宽度”准则是否真的有其价值所在,看完下面这个例子或许你就有答案了。还是上面一条徐若瑄的微博为例子:
首先,您可以狠狠地点击这里:“无宽度”准则对比demo

您会看到类似下面的效果图:
demo页面截图 张鑫旭-鑫空间-鑫生活

虽然上下两个微博列表显示的是一样的,但是其布局方法确实不一样的,一个有宽度,一个无宽度。那本文多次提到的“无宽度”准则又好在哪里呢?我们可以做个小小的test,就可以看到差别和变化了,就是修改列表外框的宽度,例如,改成500像素,见下图,然后点击确定按钮:
修改宽度为500像素 张鑫旭-鑫空间-鑫生活

结果就会如下图所示:
改变宽度后的效果 张鑫旭-鑫空间-鑫生活

可以看到,定宽布局的这个精确的宽度值限制了布局的适应性,换句话说就是定宽布局限制了内容的模块化与日后的重用性,扩展性,容错性也降低了,这也是我为什么很早就提出“无宽度”准则。

四、“无宽度”之实现

这里我想明确一点,“无宽度”具体指的是没有固定的宽度值(尤其是以px为单位的宽度值,em需看具体情况,%百分值不在其中)。使用“无宽度”实现各类布局的内容很多,为了不偏离主题,我“就事论事”,只单纯讲下上面徐若瑄微博的“无宽度”实现。

这是比较简单的也是比较基本的两栏布局,一般这种layout我们需要借助一些平时会给我们带来麻烦的,本身带刺的一些CSS属性,那就是float属性以及position:absolute声明,我在“absolute绝对定位的非绝对定位用法”一文中就多次提到我的这个观点:未设定left/top值的absolute元素和float元素就是两个混蛋近亲,同样的都是“包裹与破坏”,但是,虽然很多时候,这种破坏会给我们带来些麻烦(例如清除浮动造成的高度塌陷的问题),但是,万物皆有两面性,我们有时候可以利用这种破坏的特性来帮助我们进行更加有韧性的布局。

由于让左边的头像浮动(float:left)在IE6下会有神奇的3像素bug,所以,我个人偏好于使用position:absolute属性,只要这一个属性就可以了,然后,右边的内容就可以当这个头像不存在进行布局,我们用firebug一看CSS与HTML代码或许就知道怎么回事了:

“无宽度”布局的CSS与HTML代码 张鑫旭-鑫空间-鑫生活

相比原来的代码,我只是把头像的56像素宽度左浮动和484像素内容宽度右浮动改成position:absolutepadding-left:76px,然后,实现的效果就是一模一样了,不仅代码量少了,布局也更有扩展性。同时,也不需要什么清除浮动之类的代码了:

不需要清除浮动的代码 张鑫旭-鑫空间-鑫生活

整个布局的CSS代码就非常之清爽,没有浮动,没有计算,也没有清除浮动,而且扩展性强。

.abs{position:absolute;}
.pl76{padding-left:76px;}

之前有不少同行质疑我的CSS架构、命名等相关内容,我是可以理解的,毕竟很多人成长到一定阶段后,会陷入了自己构建的看似金玉的围墙中,难免会用墙内的眼光看待墙外的世界。上面的布局,要是在我的CSS架构下,都是直接从库(通用库和网站库)中提出来的,写页面根本就不要动CSS文件,所以,我每天都很足够的时间来写文章,关注国外最新的前端发展。

当然,实际上的无宽度布局还是有很多细节需要注意,就absolute定位而言,就有很多内容,这还是靠您自己去琢磨了,我这里就不细细讲述了。

所谓“英雄所见略同”,absolute无宽度的定位方法也是Google最大的竞争对手facebook在个人主页动态列表使用的定位方法:

facebook个人主页列表absolute无宽度定位 张鑫旭-鑫空间-鑫生活

但是,facebook这里的absolute定位属于标签内定位,外套relative属性限制,好处在于可以直接忽略我上面提到的不少需要注意的细节,且易于理解掌握,但是不足在于CSS代码量,开销,开发成本都比较大。所以,个人权衡来讲,还是直接的外标签裸absolute属性方法更好些。

还有,今天我去看facebook首页好友动态列表的代码,nnd,发现了一个很牛逼的方法,float外加table-cell方法(table-cell的宽度上千上万却依然布局良好,很神奇),我琢磨着,可能是因为国外基本上不鸟IE6浏览器的缘故,所以会果敢的使用display:table-cell属性,此方法要想在国内盛行,还需有段时日。

facebook的table-cell自适应方法 张鑫旭-鑫空间-鑫生活

此自适应布局方法方法我头一次见到,有时间得好好研究研究。

如果你不介意hack,或是你不鸟IE6,本文微博列表的position:absolute直接换成float:left也是可以的。

五、一点延伸式的结语

我觉得应准确理解本文提到的“无宽度”准则,这个准则是模块化与重用性高要求下的产物,因为固定的宽度值是限制模块重用性的最主要原因之一,所以,才提出了“无宽度”准则。

因而,我们不要去咬文嚼字,说“无宽度元素”就是指没有width属性,而是要思量,这个布局的宽度值是否影响了此布局日后的重用性与扩展性。如果这个宽度不会影响布局的重用性,例如本例的徐若瑄的头像宽度,这是个统一的固定的宽度,不影响我们实现布局的自适应,就不在“无宽度”准则的范畴内。

本文展示的“无宽度”布局方法其实是比较基本的一个布局方法,web页面的情况千差万别,还有很多其他的“无宽度”技巧,这就需要您在日后的开发中自己摸索了。

最后,很重要的,如果您重构页面更关注的是眼下效果的实现,对于一些日后潜在的改动不在意的话,那您大可不必把本文的内容放在心上,就当是隔壁王二奶奶的唠叨吧。
还有,本文又一次拿新浪微博的布局/代码举例,绝没有对任何鄙视不敬的意思,主要是因为我基本上只玩新浪微博,拿来做示例比较方便。其实,代码这东西,好坏之分不是只看表面那点东西了,团队啊,规范啊,传承啊,很多的因素,新浪微博是个优秀的产品,里面的前端代码也是值得学习的。

好吧,就说这些,毕竟资质有限,难免有叙述不准确的地方,欢迎指正,也欢迎交流。

(本篇完)

分享到:

标签: , , , , , , , , , ,

赞助商推荐(我也要赞助)

想学到点真东西? ×
如果你有1~3年前端开发经验,不妨 ×
想高薪入职阿里? ×


发表评论(目前37 条评论)

  1. 苏剑锋说道:

    刚才又再次实验了一下,终于发现position与float在例子中的表现有所不同,当页面宽度小,右列内容比较多时,两者没有区别。

    当页面宽度很大,右列内容所显示的高度比左列小时,就会发现父元素的表格不一致了。使用position时,父元素框架不会被撑开。而使用float时,父元素框架会同样被撑开,显示起来较为美观。

    结论:使用float进行宽度自适应会比较好。

    • Johnpang说道:

      言之有理,如本例中的底部虚线,在position:absolute中,虚线被撑开的高度默认只跟随右侧,而在 float:left中的表现则为跟随头像或者左侧文本的最大高度。

  2. 苏剑锋说道:

    博主你好,看了你的文章让我大受启发,对CSS有了一个全新的了解,并着手仔细去学习CSS各个规则了。
    这两天回想这无宽度准则,并去实验了各个无宽度布局。其中有一个疑问是关于position与float的,这此文章中博主举例的无宽度demo中,是使用了position的绝对值去固定左列头像,我尝试过使用float也一样可以达到这个效果,而右列没有修改,是可以自适应的。

    请问博主这两者有什么区别吗?

  3. 小强说道:

    看了你的文章,感觉自己以前会的都不入流了

  4. Vic说道:

    关于微博的例子,当把微博的图删掉,并且微博只有一行的时候,新浪的高度正常,为图片高度,lz的因为absolute了,高度变成文字的高度,而这个时候文字高度不够,新浪用float并且清除浮动还是有考虑的

  5. 刘伟说道:

    鑫哥,你是华中科大冰岩工作室的前辈吗?我是长安大学讯澜工作室的成员。是华中科大冰岩工作室的战略合作伙伴。你的文章太强大了。想拜您为师了。

  6. Tonjay说道:

    这个方法最近也再研究当中,不过我是新新新手…

  7. 御御子说道:

    表示其实用js计算一下也完全不难,现代浏览器基本上已经无需考虑性能了

  8. stephen说道:

    这个思想 给我提供了一种针对 左右横向布局 新的有效的方法

  9. Firewenda说道:

    我试了下如果用3栏布局的话,是否会不适应,请楼主指正。

  10. hackxiaozhu说道:

    张哥哥 我想问下就是关于无宽度这个,我看了你写的了,但是还是有点不明白,要是像门户行的网站,可不可一用这个无宽度啊?

  11. windy说道:

    是的,20楼的问题,确实存在,还要加个min-height

  12. on the way说道:

    左侧头像部分用绝对定位有个不好的地方,就是右侧内容很少,高度低于左侧时,由于左侧用的是绝对定位,父级的高度就由右侧内容而定,当右侧内容很少时,容器就会塌陷~

  13. gelin说道:

    我发现一个小小的问题,ie下的。
    你在右边文字div层写的是 padding-left
    如果我按这个方法布局页面,需要添加 边框和背景 并且只是右边的div,那么写padding 很显然不行,左边的div也会有边框和背景。
    这里我改成margin 我发现在ie6\7(8未测试) 是出错的,左边的div层会跑到,右边div设置的margin-left边上。
    一直很纠结····望博主能帮忙。

  14. freshlee说道:

    我想请问一下:页面随分辨率变化的问题。
    现在我是在1024*768下做的页面,但是把分辨率调到1280*1024时,页面的两边和下面就会很大的空白(我的页面的长度刚好是到768px),我想问一下,这种问题怎么解决呢?
    我尝试过设成百分比,但是这样的话,当我把窗口拉小的时候,里面的布局就会变成重叠的,苦恼…

  15. 落单的孤鸟说道:

    很不错的分析,很多时候没有人注意这些问题,不过想问一下,如果要是左边的图片不控制固定宽度呢?左右都自适应呢?

  16. Felix说道:

    博主写的文章浅显的指出了CSS在部分网页上的有限需求。思路值得嘉奖。但是请深入研究和实践后再发表文章。否则误人误己。

  17. NLF说道:

    很喜欢看你的博客

  18. diao说道:

    楼主的这篇文章看起来有独道之处,也考虑了重构的要素,我现在都是用浮动在布局,学习中…

  19. 耗子说道:

    我想要你写的那个淘宝页面 想学习学习可以吗 很是感谢…

  20. Mr.Q说道:

    哥们,你的思想跟我的基本一样,不过,你这个方法不好,还是需要判断左边的内容的宽度。
    推荐左边用float:left右边用overflow:hidden;zoom:1,这样自适应要节省很多padding-left的计算

  21. 视觉时代说道:

    好的,非常感谢!姚明进一中投!呵呵。。。你推荐的书我买了两本,《JavaScript语言精粹》配送等待中,收到的《写给大家看的设计书》符合你的CSS哲学,根本、简洁,很有收获!以后会时常过来踩踩,具体有问题时再请教。

  22. 视觉时代说道:

    你好,ZXX,国庆期间开始看你的博客。喜欢你的页面重构思想、也感谢你的分亨。我个人稍了解一点点HTML与CSS,也想更进一步。向你请教以下几个问题:1、可否推荐下你这个博客服务器空间提供商,我想上传最简单的然后边学边改。2、本机环境搭建方面,最少我应当装哪几个流览器测试,装什么工具(我只经常听你说firebug)。以上两个问题与技术关系不大,如能得到回复不胜感谢!*^_^*

    • 张 鑫旭说道:

      @视觉时代 我的空间服务商是”美橙互联”,测试浏览器的话IE6~IE8(有条件的话也可以IE9 beta),Firefox,Opera,Chrome,Safari浏览器,一般浏览器都自带测试工具的,例如IE8,Chrome,Opera,Safari等,Firefox装个firebug,IE6/7可以装IE developer。

  23. crossyou说道:

    写的不错,学习,

  24. tunpishuang说道:

    最近和display:table-cell有缘。

  25. ryanbay说道:

    LZ写的很好
    我补充一点:无宽度布局需要注意补上min-width的属性以避免过小浏览器窗口出现错乱/重叠