渐进增强式布局探讨(下)
上篇中讨论了各种已有的布局实现。仔细分析各种布局的技术实现,可以发现下面三种技术被经常使用:
- 浮动 float
- 负边距 negative margin
- 相对定位 relative position
这是实现布局的三个最基本的原子技术。只要巧妙组合,并加以灵活运用,就能“拼”出各种布局的实现方案。
尝试之路
考虑以下DOM结构:
<div id="page">
<div id="hd"></div>
<div id="bd">
<div class="main"></div>
<div class="sub"></div>
<div class="extra"></div>
</div>
<div id="ft"></div>
</div>
利用浮动元素的负边距来定位:
.main {
float: left;
width: 100%;
}
.sub {
float: left;
width: 190px;
margin-left: -100%;
}
.extra {
float: left;
width: 190px;
margin-left: -190px;
}
这样我们得到了第一个尝试页面 pe_layout_example1.html.
可以看出,通过简单的负边距,已经让sub和extra定位到正确的位置。剩下的问题是如何让main也定位到正确的位置。
一个自然的想法是,给main的容器#bd添加padding:
#bd {
padding: 0 230px 0 190px;
}
效果请看: pe_layout_example2.html.
这样能让main定位到正确的位置,但sub和extra的位置不对了。这是一个思考的关卡。既然sub和extra的位置不对,那就想办法调整到正确的位置。相对定位隆重登场:
.sub {
float: left;
width: 190px;
margin-left: -100%;
position: relative;
left: -190px;
}
.extra {
float: left;
width: 230px;
margin-left: -230px;
position: relative;
right: -230px;
}
demo页面: pe_layout_example3.html. 很明显,这就是圣杯布局!
组合这三种基本技术,我们可以继续尝试各种想法。比如伪绝对定位布局(这个布局不难想到,难的是第一个想到),类似的还有逆伪绝对定位布局(先都移动到最左边,然后再margin-right一个个移过来)等等。
在不增加任何额外标签的假设上,我尝试了各种想法,但始终都没找到完美的布局实现(圣杯布局是我觉得所有想法中最接近完美的)。
既然不添加额外标签时,完美布局的实现如此困难,那如果允许添加一个额外标签呢?在淘宝UED内部的探讨中,给main增加了一层包裹:
<div id="main" class="column">
<div id="main-content">#main</div>
</div>
里层main-content的作用就是将main定位到合适的位置,并方便设置padding等属性。想到此处,就像牛顿被苹果砸傻了一样,原来的main定位问题迎刃而解:
<div id="page">
<div id="hd"></div>
<div id="bd">
<div class="main">
<div class="main-wrap"></div>
</div>
<div class="sub"></div>
<div class="extra"></div>
</div>
<div id="ft"></div>
</div>
CSS仅需增加一行:
.main-wrap {
margin: 0 230px 0 190px;
}
demo页面: pe_layout_example4.html.
一切如此简单!除了添加了一个额外标签,其它各方面,表现都很完美(试了下IE5.5, 也没任何问题)。目前只用到了浮动和负边距,如果再引入相对定位,还可以实现三栏布局的各种组合:
.extra {
float: left;
width: 230px;
margin-left: -100%;
position: relative;
left: 190px;
}
.main-wrap {
margin-left: 430px;
}
demo页面: pe_layout_example5.html.
仔细查看example5和example4的源代码,可以发现DOM结构是完全一样的,仅仅CSS稍有不同。这意味着HTML结构和CSS布局在一定程度上解耦了,我们开发HTML代码时,从内容出发即可,无需过多的考虑布局。这正是渐进增强在前端工作流程上的体现。
如果把三栏布局比作一只大鸟,可以把main看成是鸟的身体,sub和extra则是鸟的翅膀。这个布局的实现思路是,先把最重要的身体部分放好,然后再将翅膀移动到适当的地方。因此请容许我给这个布局实现取名为双飞翼布局(Flying Swing Layout).
![]()
就如上图中的鸟有各种姿势一样,利用双飞翼布局,我们也可以实现各种布局。这里有个尝试页面,利用双飞翼,实现了一套栅格化布局系统。
优点
- 实现了内容与布局的分离,即Eric提到的Any-Order Columns.
main部分是自适应宽度的,很容易在定宽布局和流体布局中切换。- 任何一栏都可以是最高栏,不会出问题。
- 需要的hack非常少(就一个针对ie6的清除浮动hack:
_zoom: 1;) - 在浏览器上的兼容性非常好,IE5.5以上都支持。
不足
main需要添加一个额外的包裹层。- 等待你的发现与反馈。
补充
双飞翼布局的想法与实现受了圣杯布局和UED内部讨论的PPT的启发。尝试后发现一切如此简单,都有点奇怪为什么网络上一直没有文章来阐述。
前些日子主要精力都放在了阅读ALA上的文章,没怎么注意其它信息。昨天才仔细阅读Eric的Any-Order Columns和Alex的One True Layout, 发现这种思路和想法早就有人尝试过了。比如Eric原文中的例子是定宽的,但稍微修改,就可以演化为双飞翼布局。Alex的One True Layout, 给的例子被墙了,就一直没细看,今天才找代理过去瞄了一眼,一瞄不要紧,原来One True Layout就是双飞翼,不过Alex只用到了浮动和负边距,因此没有提及main - sub - extra这种排列的实现。
此外,中午还有一个非常震惊的发现:Alessandro早做了一个很详细的页面Layout Gala, 列举了40种布局,用的就是双飞翼!
巧合让人有点沮丧,但更让我高兴。因为Alex和Alessandro的工作,证明了这种布局的普适性。因此不用像采用伪绝对定位布局时一样,得担心新技术带来的风险!可以说,双飞翼布局已经是一个成熟的布局,但因为Alex的被墙,以及Alessandro的宣传力度不够,导致这个布局被我重新“发现”了一次。特撰此文,并取名为“双飞翼布局”,希望这个布局能让更多的人知道,并应用于实践中。

November 4th, 2008 on 19:22
这篇文章太棒了,我要多读几遍……
BTW: 为什么不 follow 我的 twitter 呢..
November 5th, 2008 on 22:30
补充:如果是百分比宽度,不用相对定位,只用负边距,也可以实现 sub-extra-main这种布局,比如:
... .sub { width: 30%; margin-left: -100%; } .extra { margin-left: -70%; } ...November 14th, 2008 on 23:40
很有趣的文章~
其实这种布局在WP的一个很著名的模板Sandbox里面就有……
里面默认就提供了多种分栏解决方案~
对大容器或大规模的相对定位会损耗一定浏览器速度,特别是IE……
Nice article anyway~
December 16th, 2008 on 4:19
太TM精彩了~~· 同学··不错啊
December 19th, 2008 on 11:08
我喜欢这种文章呐
December 21st, 2008 on 11:11
god 我的是天魁冥神布局。比较起来,这个栅格利用的不错哦啊
互相学习!www.fxcd.cn
December 23rd, 2008 on 17:12
这种sub-extra-main的布局,在使用了position:relative的时候再使用margin-bottom:-5000px;padding-bottom:5000px;就会出现overflow:hidden时效的情况
December 23rd, 2008 on 17:14
还有一种比较常用的布局,就是利用边框的宽度,让sub,extra等浮在边框上,这样就比较灵活实现三栏或者多栏布局
January 5th, 2009 on 20:21
请问:一般怎么处理border的问题
border不包括在width之内,添加border就会使实际width增大,如果还想让总体保持950px,就需要适当减少实际宽度,问题是有的页面有border,有的没有border,改起来就很麻烦,期待好的解决办法。
January 11th, 2009 on 20:04
main里面加div的方法我也在用,其实主要是为了兼容chrome和safari,不知道那么多好听的名字,看来看的文章还是太少。不过现在固定宽度的网页越来越多,这种高级技术发挥不出来。
January 20th, 2009 on 16:23
main固定宽度能用这种方法吗,我是新手
February 12th, 2009 on 14:27
怎么说呢, 经测试都不怎么完美. 有些时候为了兼容性,要多写很多的代码,博主也就抛砖引玉吧.
April 1st, 2009 on 16:21
IE6中在的标签之间里加两三个的注释会不正常显示。。。
May 26th, 2009 on 10:35
<div id="wrapper"><div id="header">header</div>
<div id="container">
<div id="content">content</div>
</div>
<div id="navgation">navgation</div>
<div id="footer">footer</div>
用这样的写法,用博主的css的做法,在wrapper不设定宽度时,没有问题。但是wrapper设定宽度后,navgation的位置会出现偏差。。我百思不得其解。。希望博主能够帮助我。。
May 26th, 2009 on 10:48
是在ie6的测试下
June 2nd, 2009 on 15:12
雕兄,在你的栅格化布局系统中,使用自适应宽度时,将浏览器窗口缩小到一定程度时,col-main显示就出问题了。这时应该给col-main一个最小值?
June 17th, 2009 on 16:28
不错的文章,很有帮助
September 9th, 2009 on 10:25
position:relative会让侧栏在ie6里跑位,具体现象:让页面闲置一段时间,侧栏自动偏移到右侧页面之外;删除relative属性,用padding和额外margin实现栏间隔后恢复正常,但在ie5.5里,padding也有异常.
September 26th, 2009 on 17:21
你的文章看了好几便,受益不浅
想问个问题,你这个布局为什么偏好内边据呢,为什么不用外边据,用外边据要简单的多;
你这个布局在ie下sub要丢失;还要额外加几行才行;
Alessandro的40种布局基本上用的都是外边据,但不知到有什么缺点?
September 26th, 2009 on 20:21
@phpdd66: sub 丢失,能给个例子么?
September 28th, 2009 on 1:25
又研究了一晚上,还是不行;
css如下:
#bd {
padding: 0 230px 0 190px;
}
.main {
float: left;
width: 100%;
}
.sub {
float: left;
width: 190px;
margin-left: -100%;
position: relative;
left: -190px;
}
.extra {
float: left;
width: 230px;
margin-left: -230px;
position: relative;
right: -230px;
}
sub在firefox下正常,在ie7下显示不出来,需要增加#page{overflow: hidden;}才行,又看的你的另一篇说这样也会有bug,需要在bd后增加个clear类才能解决。感觉使用内边据代码使用的太多了
September 28th, 2009 on 2:45
最后一个使用main-wrap后,外面的bd可以不要了,相对定位也可以不要,代码很少,就是dom树看上去不是很完美,但不知到在别的浏览器下是否有bug。
October 9th, 2009 on 23:03
好像你 lab 目录下的文件都没了? 文章的一些展示页面都 404 了….
December 9th, 2009 on 10:29
“双飞翼布局”应该能给很多人思考空间……
leave a reply