首页 > 代码库 > 负边距实现圣杯布局以及列等高
负边距实现圣杯布局以及列等高
圣杯布局如下图所示,
图一
两边的内容宽度固定,中间栏宽度自适应。html代码如下,
<div class="container"> <div class=‘main‘> <p>main</p> <p>主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容主干内容</p> </div> <div class=‘sub‘> <p>sub</p> <p>sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容sub内容</p> </div> <div class=‘extra‘> <p>extra</p> <p>extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容extra内容</p> </div>
在写html是应尽量先不考虑布局(当然,这比较难做到),这样才能比较好的保证语义化。注意到,虽然main的内容是显示在中间的,但是在html中把它放到了sub和extra的前面,主要是出于几个方面考虑:
- 更符合语义,主体内容应放在前面
- 当网速比较慢时,能够先加载主要内容,比如css文件加载失败时,主体内容能够在更靠前的位置显示
- 主要内容放前面,有助于SEO(未考证)
为了布局,为main,sub,extra三个模块都加上了相应的css类。下面来考虑一下布局,sub和extra宽度固定,分别为190px和230px。首先,main模块需要自适应,说俗一点,也就是能占的地方它就占,那咱就让它霸道一点,width设为100%(后来仔细想想此设置为多余)。让sub,main,extra都在一行上,相信大家都想到了float,但是三个都设置为float:left之后,因为html结构中main放在sub和extra之前,而且main的宽度设为100%,所以效果如下,
图二
要怎么样才能让sub和extra都上去呢,这时候就需要使用神奇的负边距了。设置sub的margin-left:-100%,extra的margin-left:-230px;/*230px是extra的宽度*/
图三
此时的css代码
.main{ width:100%; float:left; background: #D6D6D6;}.sub{ float:left; background:red; width:190px; margin-left:-100%;}.extra{ float:left; width:230px; background:blue; margin-left:-230px;}
欣喜的发现,显示到一行了。为什么呢,自己动手实验一下就会明白,从0开始一直减小sub的margin-left会发现,sub块的内容在向左移,左移的那部分内容相移出了可视范围,然后一直减小到-189px(sub的宽度是190px)时,只能看到sub的一像素的边,此时它还是处在main的下方,并没有上去。但是当减到-190px(和自己宽度相同)时,突然发现它上移了,和main处在一行。如下图所示
图四
因此要想要达到最开始说的效果,sub和extra分别在main的左右,那sub要左移一个容器的宽度(上移一行,margin-left:-100%),而extra需左移自身宽度,margin-left:-230px,就达到了图三的效果。
做到这儿以为大功告成,就是通过但是仔细观察后发现,main的内容显示不全,现在效果其实是sub和extra把原本main原本显示的文字给覆盖住了,不是我们想要的自适应的效果。这时候需要考虑把main的势力收缩一下,这时候只能请sub的‘老子’container出来管管它了,设置container的左右padding,来让main的内容不能伸展到左右两边,设置完之后,效果如下
图五
为了方便大家看出问题,我给外层container设置了宽高,并加上1px的外边框,可以看出,此时main的内容是对的,但是sub,和extra的内容不对,container的padding把它们也往中间压了,并且通过extra现在所处的位置我们队之前设置的负边距能有个更深的理解,设置边距为-width并不意味着就一定是从下行的行首到上一行的行末,而是到上一行能够到达的最靠后的位置。
接下来需要对sub和extra的位置进行调整,使用position:relative,对它们分别作相应的偏移即可,效果如下,
总算对了,调整浏览器宽度,发现main的宽度能够自适应。呼,终于可以洗洗睡了。等一下!三列不等高也太难看了,怎么让他们高度一致呢?还是用之前用到的负边距,同时结合padding来实现。思路就是通过设置padding,把三列的高度都撑高,然后设置与之对应的负边距,这样这几列下方的元素不会被顶下去,然后给容器设置适当的高度,然后设置overflow:hidden,效果如下,
css代码如下
.container{ padding:0 230px 0 190px; height: 292px; overflow: hidden;
}.main{ width:100%; float:left; background: #D6D6D6;}.sub{ float:left; background:red; width:190px; margin-left:-100%; position:relative; left:-190px;*/}.extra{ float:left; width:230px; background:blue; margin-left:-230px; position:relative; right:-230px;}.container div{ padding-bottom: 5000px; margin-bottom: -5000px;}
总算搞定了。总结一下思路:
- 通过设置负的margin-left让原本在下方的sub和extra上移到与main在同一行
- 设置外部container的左右padding来使main的内容收缩到中间
- 因为外部的container的padding,sub和extra的位置也发生了相应偏移,通过position:relative,在分别设置偏移,使sub和extra到正确的位置
- main,sub,extra的高度都是被其内部的内容高度撑起来的,高度各不一样,设置padding和和负的边距,再给外部容器设定高度,并做overflow:hidden处理,来使各列的高度一致。注意padding和负边距的值要取的比较大,防止有某列加上了padding还没有超过外部容器的高度,导致没有触发外部容器的overflow,进还是不能实现等高效果