圣杯和双飞翼布局是最为经典和基础的两个布局方式了,两者的目的都是为了实现一个三栏的布局,其共同点如下:
- 两侧的宽度固定,中间的宽度能够自适应调整;
- 中间部分在DOM结构上优先,以便先行渲染
- 允许任意列的高度最高
圣杯布局
DOM结构
1 | <body> |
基本的DOM结构如上,主体的三列被包括在container中,注意center在最前面。
CSS布局
我们首先给设定如下布局,先给每一栏设定不同的高度和背景颜色:
1 | *{ |
得到以下结果:
然后增加如下代码:
1 | /*为左右两列预留出空间*/ |
此时结果如下:
不难理解,因为center元素的宽度为100%(此处的百分比是指子元素内容区域相对于父元素内容区域,因此,保留了父元素中之前预留的两侧padding),所以left和right都在其下面。接下来再添加如下代码:
1 | #left{ |
上述代码通过设置负外边距将left元素上移并覆盖住了center,可以看到如下图所示的结果。个人的理解是:当我们设置负外边距时,元素就会按照文档流反方向偏移(此处的三个浮动可以看作存在浮动流),当我们对于浮动元素设定margin-left: -100%,这里的100%相对的是上一个浮动元素的宽度,所以此时将左外边距设为-100%,就使得left元素产生了整体上移的效果。
最后添加如下代码,使用相对定位并向左偏移使left元素来到正确的位置,对于right元素,同样使用负外边距,:
1 | #left{ |
最后,为了保证布局效果正常显示,需要给页面添加一个最小宽度,但不是200 + 150 = 350,由于之前的left元素使用了position:relative; right: 200px,所以,最小宽度应为350 + 200 = 550。添加如下代码就大功告成了:
1 | body { |
双飞翼布局
DOM结构
双飞翼布局的DOM结构如下,与圣杯布局有一点不同:container仅包含center元素,column也从center元素移动到了container上。
1 | <body> |
CSS布局
首先完成基本的颜色、宽度、浮动设定。此时不再通过padding预留空间(由于DOM结构的改变),而是通过margin实现:
1 | *{ |
得到结果如下,宽度为100%container占据了最上面一行,所以left和right元素都排在下面。注意center并没有设置宽度和浮动。
增加以下代码:
1 | #left{ |
完成布局,得到和圣杯布局一样的效果:
对于双飞翼布局,由于没有用到相对定位,页面宽度最小可以为350px, 但是当页面宽度缩小到350px附近时,会挤占中间栏的宽度,使得其内容被右侧栏覆盖, 所以在设置最小页面宽度时,可以适当增加一些宽度以供中间栏使用。
比较
- 圣杯布局的DOM结构更加自然常见,只需要三个
div即可。 - 双飞翼布局通过在
center外增加一个div的方式,改padding为margin,并使得不需要使用相对定位,更加简单; - 由于没有了相对定位,页面的最小宽度也有没有了上文所述的限制。
我们注意到在圣杯布局中,对于right元素,最后使用了margin-right: -150px;,而在双飞翼中则是margin-left: -150px;来实现。个人的观点是,由于在圣杯布局中,我们的方式是通过padding内边距预留空间,如果我们此时使用margin-left就会导致如下结果:
原因就是元素会紧挨着其在“元素流”(文档流或者浮动流)中的前一个元素,在圣杯布局中right的前一个浮动元素center,是在container的内容区里面,所以设置了负外边距后,不会按照预期的来到预留的位置,而是相对于center进入了内容区中。而在双飞翼中,它的前一个浮动元素是就是container,而container的宽度充满了整个屏幕,因此会得到正确结果。
PS:其实在圣杯布局中,对于右栏使用margin-left也是可以的,然后再用一下相对定位的,和左栏一样(实际上大多数网上的圣杯实现左右栏都是使用了相对定位)。至于为何使用margin-right会直接有这样的效果,目前我也还不是很清楚,还望看到本博客的人不吝赐教。
进阶:Flex布局
在CSS3引入Flex(弹性盒子)布局后,要实现这种分栏布局就变得更加简单了:
DOM结构
1 | <body> |
CSS布局
1 | #container{ |
对上述代码做一个简单解释:要使用flex布局,首先将父容器的display属性设为flex,然后其下的所有子元素自动变成容器成员—我们称为项目。对于容器,我们可以设置属性规定容器中的项目的排列方式,而上述代码中,我们直接通过设定项目的属性:
order属性定义排列的属性,默认为0,我们将left的该属性设为-1,达到在最左边的目的。flex属性是flex-grow,flex-shrink和flex-basis的简写,默认值为0 1 auto。后两个属性可选。flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。这里在center元素中将该值设为1,以实现自适应。flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。这里在left和right元素中将该值设为0,保持宽度不变。flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。默认值为auto,即项目的本来大小。主轴默认为横轴,这里即用来设定固定宽度大小。
此处对于Flex布局只做相关的简单介绍,因为自己也是不太明白其原理,希望然后可以了解的更加深入。
感想
CSS的世界真是千奇百怪,博大精深,作为刚开始学习的初学者,需要走的路还很多。