好久没写CSS了,总结归纳一下css的布局方案,尽可能详细,也能让自己再温习一遍。PS:吐血整理,这也许是史上最全的布局方案了。
前戏:居中方案
水平居中
要求:如下图。子容器和父容器的宽度都未知,子容器相对父容器水平居中。
1 2 3 4 5 6
| /* * 由于右侧目录 * 占用宽度较大 * 建议使用桌面浏览器 * 以获得最佳的浏览体验 */
|

inline-block + text- align
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12
| <div class="parent"> <div class="child">Demo</div> </div>
<style> .child { display: inline-block; } .parent { text-align: center; } </style>
|
详解:text-align只对inline的子元素起作用,因此把子元素设置为了inline-block。
优点:兼容性很好,原生支持到IE8;更低版本的IE也可通过hack手段实现兼容。
缺点:子容器会继承到父容器的text-align: center属性。
table + margin
代码示例:
1 2 3 4 5 6 7 8 9 10
| <div class="parent"> <div class="child">Demo</div> </div>
<style> .child { display: table; margin: 0 auto; } </style>
|
详解:table在表现上类似于block元素,但是有区别,因为block宽度是撑满整行的,而table的宽度是随内容宽度自适应的。再利用block元素常用的margin: 0 auto;,即可实现居中。
优点:无需设置父元素,也可以兼容到IE8。
缺点:兼容IE6,7时需把整体结构调整为table。
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <div class="parent"> <div class="child">Demo</div> </div>
<style> .parent { position: relative; } .child { position: absolute; left: 50%; transform: translateX(-50%); } </style>
|
详解:子元素设为absolute可确定其宽度,然后根据父元素定位,此时子元素的最左边是父元素正中间,再根据子元素自身宽度进行位移。
优点:脱离文档流,因此居中的元素不会对其它元素造成影响。
缺点:用到了CSS3,因此最低只能兼容到IE9。
flex + justify-content
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <div class="parent"> <div class="child">Demo</div> </div>
<style> .parent { display: flex; justify-content: center; } .parent { display: flex; } .child { justify-content; } </style>
|
详解:flex容器的子项的默认宽度是auto,然后利用flex提供的justify-content实现水平居中,或使用传统的justify-content也可以。
优点:只需设置父节点属性,无需设置子元素
缺点:最高只兼容到IE9
垂直居中
要求:如下图。子容器和父容器的高度都未知,子容器相对父容器垂直居中。

table-cell + vertical-align
代码示例:
1 2 3 4 5 6 7 8 9 10
| <div class="parent"> <div class="child">Demo</div> </div>
<style> .parent { display: table-cell; vertical-align: middle; } </style>
|
详解:vertical-align可作用到inline元素以及table-cell元素上面。
优点:只需设置父元素即可,能兼容到IE8
缺点:兼容IE6,7时需把整体结构调整为table。
详解:和上文中absolute + transform实现水平居中的方式一样,因此优缺点也一样,不再赘述。
flex + align-items
详解:和上文flex + justify-content解决水平居中方式一样,把justify-content替换为align-items即可。优缺点也一样,不再赘述。
水平 + 垂直居中
要求:如下图。子容器和父容器的宽高都未知,子容器相对父容器水平垂直居中。

inline-block + text-align + table-cell + vertical-align
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <div class="parent"> <div class="child">Demo</div> </div>
<style> .parent { text-align: center; display: table-cell; vertical-align: middle; } .child { display: inline-block; } </style>
|
详解:综合了上文的两种方法,text-align: center;和display: inline-block;实现了水平居中,display: table-cell;和vertical-align: middle;实现了垂直居中
优点:兼容性好,最低兼容到IE8。
缺点:兼容IE6,7时需把整体结构调整为table。
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div class="parent"> <div class="child">Demo</div> </div>
<style> .parent { position: relative; } .child { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } </style>
|
详解:和上文中absolute + transform实现水平居中方案一样,加入了垂直居中的代码(原理一样)。
优点:脱离文档流,因此居中的元素不会对其它元素造成影响。
缺点:用到了CSS3,因此最低只能兼容到IE9。
flex + justify-content + align-items
代码示例:
1 2 3 4 5 6 7 8 9 10 11
| <div class="parent"> <div class="child">Demo</div> </div>
<style> .parent { display: flex; justify-content: center; align-items: center; } </style>
|
详解:和上文flex容器实现水平居中一样,新加入了垂直居中代码。
优点:只需设置父节点属性,无需设置子元素
缺点:最高只兼容到IE9
总结
文章所列方案不一定是全的,可能还有其他方案。做解决方案,有一个大致的思路,我们可以这样来总结一下。
首先,我们需要了解css里面很多属性的值,以及它的一些特性,比如说flex,vertical-align等,要熟练掌握这些特性。然后,我们需要去分解问题。最后,把这些问题和css特性做一些联系,去解决问题。
多列布局
一列定宽,一列自适应布局
要求:如下图。子容器和父容器的宽高都未知,子容器相对父容器水平垂直居中。

float + margin
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <div class="parent"> <div class="left"> <p>left</p> </div> <div class="right"> <p>right</p> <p>right</p> </div> </div>
<style> .left { float: left; width: 100px; } .right { margin-left: 100px } </style>
|
详解:非常基础的浮动布局,不解释。
优点: 1.兼容性非常好,2.简单
缺点: 1.耦合度较高 2.有一个‘bug’,右边第一个p元素清除浮动时会掉下去。这一般不是我们希望看到的效果。
float + margin (fix)
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <div class="parent"> <div class="left"> <p>left</p> </div> <div class="right-fix"> <div class="right"> <p>right</p> <p>right</p> </div> </div> </div>
<style> .left { float: left; width: 100px; position: relative; } .right-fix { float: right; width: 100%; margin-left: -100px; } .right { margin-left: 100px } </style>
|
详解:相较原生的浮动布局,右边新增了一层空的标签,通过设置margin-left: -100px;,防止容器掉下去。
优点: 兼容性非常好
缺点: 1.耦合度较高;2.新增了一层结构
float + overflow
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <div class="parent"> <div class="left"> <p>left</p> </div> <div class="right"> <p>right</p> <p>right</p> </div> </div>
<style> .left { float: left; width: 100px; } .right { overflow: hidden; } </style>
|
详解:设置 overflow: hidden 会触发 BFC 模式(Block Formatting Context)块级格式化文本。 BFC 中的内容与外界的元素是隔离的。
优点:简单
缺点:不兼容IE6
table布局
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <div class="parent"> <div class="left"> <p>left</p> </div> <div class="right"> <p>right</p> <p>right</p> </div> </div>
<style> .parent { display: table; width: 100%; table-layout: fixed; } .left { display: table-cell; width: 100px; } .right { display: table-cell; } </style>
|
详解:table布局的一个特点是,两列每一列的宽度之和一定是等于整个表格的,所以仅需设置一边宽度即可。 table-layout: fixed; 可加速渲染,更重要的作用是设定布局优先。
优点:兼容性高
缺点: 1.table与普通布局不同,有些细节需要注意,比如不能设置margin,只能设置padding来控制间距。2.代码量较多。
flex布局
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <div class="parent"> <div class="left"> <p>left</p> </div> <div class="right"> <p>right</p> <p>right</p> </div> </div>
<style> .parent { display: flex; } .left { width: 100px; margin-left: 20px; } .right { flex: 1; } </style>
|
详解:上文说过,flex的子项宽度默认是auto,因此需设置flex: 1;来自动撑满剩余宽度
优点:写法非常简单,理解起来也很简单。
缺点: 1.低版本浏览器不兼容。2.性能问题导致不能应用为大范围布局。
两列定宽,一列自适应
常用方案:float,flex等
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <div class="parent"> <div class="left"> <p>left</p> </div> <div class="center"> <p>center<p> </div> <div class="right"> <p>right</p> <p>right</p> </div> </div>
<style> .left, .center { float: left; width: 100px; margin-right: 20px; } .right { overflow: hidden; } </style>
|
效果:

一列不定宽加一列自适应
要求:如下图。

难点剖析:左侧的宽度由其内容宽度决定,右侧自适应。因此,需要依赖某一项元素宽度的布局是肯定不适合的,如float + margin布局。
float + overflow
详解:如一列定宽,一列自适应布局所示,左侧宽度可设置为任意值,右侧宽度会随其变化。
table布局
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <div class="parent"> <div class="left"> <p>left</p> </div> <div class="right"> <p>right</p> <p>right</p> </div> </div>
<style> .parent { display: table; width: 100%; } .left,.right { display: table-cell; } .left { width: 0.1%; } </style>
|
详解:删掉table-layout: fixed;改为内容优先,把左侧宽度设为足够小,然后用内容把宽度撑开。
优点:兼容性较好,支持IE8及以上。
缺点:无法兼容IE6,7。
flex布局
详解:详见上文中一列定宽,一列自适应布局中的flex方案。无需更改,flex天生就有这种特性。
多列不定宽加一列自适应
详解:其实和两列不定宽加一列自适应是一样的,解决方案也是上述方案。
多列等分布局
要求:如下图。每一列的宽度和间距都是一样的

难点剖析
如果没有间距,在n列中,可轻松得出每一列的宽度是1 / n;而一旦加上间距,那么最后一列一定是会出问题的,因为超出了父容器,如图:

所以如果使用浮动布局,可能存在这样的问题。那么怎么解决呢?

如上图,可以得出公式:总宽度C = W * N + G * ( n - 1) => C = W * N + G * N - G;转化可得:C + G = (W + G) * N;
float
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <div class="parent"> <div class="column"> <p>1</p> </div> <div class="column"> <p>2</p> </div> <div class="column"> <p>3</p> </div> <div class="column"> <p>4</p> </div> </div> <style media="screen"> .parent { margin-left: -20px; } .column { float: left; width: 25%; padding-left: 20px; box-sizing: border-box; } </style>
|
详解:如下图,通过margin-left: -20px使整个容器向左增加了20px,通过设置padding-left: 20px;和box-sizing: border-box;使每列宽度包含了padding值。

优点:兼容性较好,至少兼容到IE8( IE6,7对百分比的浮点数计算有问题,所以并不能算完美兼容 )
缺点:结构样式耦合度较高。
table布局
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <div class='parent-fix'> <div class="parent"> <div class="column"> <p>1</p> </div> <div class="column"> <p>2</p> </div> <div class="column"> <p>3</p> </div> <div class="column"> <p>4</p> </div> </div> </div>
<style media="screen"> .parent-fix { margin-left: -20px; } .parent { display: table; width: 100%; table-layout: fixed; } .column { display: table-cell; padding-left: 20px; } </style>
|
详解:table布局的特性决定了它的每一列天然都是平分的,因此不需要设置宽度。由于不支持margin,因此需在最外边再嵌套一层div,设置margin-left: -20px;。
优点:零耦合,可随意调整列数。
缺点:写法较繁琐,需额外嵌套div。
flex布局
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <div class="parent"> <div class="column"> <p>1</p> </div> <div class="column"> <p>2</p> </div> <div class="column"> <p>3</p> </div> <div class="column"> <p>4</p> </div> </div>
<style media="screen"> .parent { display: flex; } .column { flex: 1; } .column+.column { margin-left: 20px; } </style>
|
详解:利用flex: 1;平均分配剩余空间,.column+.column在这里指除了第一个.column的所有.column。
优点:代码量很少;零耦合,可随意调整列数
缺点:低版本浏览器不兼容。
多列等高,其中一列宽度自适应
要求:如下图,右侧自适应,两侧的高度需随时保持一致

table布局
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <div class="parent"> <div class="left"> <p>left</p> </div> <div class="right"> <p>right</p> <p>right</p> </div> </div>
<style> .parent{ display: table; width: 100%; table-layout: fixed; } .left,.right{display: table-cell;} .left{ width: 100px; border-right: 10px solid transparent; background-color: #83B600; background-clip: padding-box; } .right{ background-color: #F48A56; } </style>
|
详解:table的特性天生适合这种需求,但设置背景色时需注意:使用padding-right的方案来处理间距会存在部分兼容问题,为了解决这个兼容性问题,我们可以去掉padding-right的设置,变成border-right:20px solid transparent,然后把background-clilp改成padding-box,问题就解决了。
优点:原生支持的等高。
缺点:写法较繁琐。
flex布局
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <div class="parent"> <div class="left"> <p>left</p> </div> <div class="right"> <p>right</p> <p>right</p> </div> </div>
<style> .parent { display: flex; } .left { width: 100px; margin-left: 20px; } .right { flex: 1; } </style>
|
详解:flex 默认的 align-items 的值为 stretch。所以无需多做设置,天然就是等高的。
优点:写法非常简单。
缺点:低版本浏览器不兼容。
float
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <div class="parent"> <div class="left"> <p>left</p> </div> <div class="right"> <p>right</p> <p>right</p> </div> </div>
<style> .parent { overflow: hidden; } .left, .right { padding-bottom: 9999px; margin-bottom: -9999px; } .left { float: left; width: 100px; margin-right: 20px; } .right { overflow: hidden; } </style>
|
详解:通过margin-bottom把padding-bottom抵消掉,给父容器加上overflow: hidden;,这样的话,设置背景色时会把多余的padding-bottom截掉,高度取最高一列的高度,下边看不见的地方全都是它们的padding-box区域。所以其实这是一种伪等高,只是看上去一样高了而已。
优点:兼容性很好。
缺点:伪等高,且新手较难理解。
全屏布局
示例:

适用类型:
示例图稿:

Position解决方案
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <div class="parent"> <div class="header"></div> <div class="lside"></div> <div class="content"> <div class="inner"> 主内容区 </div> </div> <div class="footer"></div> </div> <style> html,body,.parent{margin: 0;padding: 0;height: 100%;overflow: hidden;} .header{ position: absolute; top: 0;left: 0;right: 0; height: 100px; background: #EB4C54; } .lside{ position: absolute; top: 100px;left: 0;bottom: 50px; width: 200px; background: #2D313D; } .content{ position: absolute; top: 100px;right: 0;bottom: 50px;left: 200px; background: #F0F0F0; overflow: auto; } .footer{ position: absolute; bottom: 0;left: 0;right: 0; height: 50px; background: #EB4C54; } .content .inner{ min-width: 500px; min-height: 1000px; } </style>
|
详解:全局设置overflow: hidden;用来ban掉滚动条。主内容区设置overflow: auto;用来内容超出时在内容区显示滚动条。
兼容性:绝大多数浏览器都是兼容的,IE6对position的支持度不是很好,不过可以使用hack来解决。
flex解决方案
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <div class="parent"> <div class="header">header</div> <div class="center"> <div class="lside">lside</div> <div class="content"> <div class="inner"> 主内容区 </div> </div> </div> <div class="footer">footer</div> </div> <style> html,body,.parent{margin: 0;padding: 0;height: 100%;overflow: hidden;} .parent{display: flex;flex-flow: column;} .header{ height:100px; background: #EB4C54; } .center{ flex: 1; display: flex; } .center .lside{ width: 200px; background: #2d3131;color: white; } .center .content{ flex: 1; background: #f0f0f0; overflow: auto; } .center .content .inner{ min-width: 700px; min-height: 1000px; } .footer{ height: 50px; background: #EB4C54; } </style>
|
详解:flex非常适合自适应布局,其实可以把定宽定高的设置全部删掉,或者百分比,整体布局也完全不会有问题。
兼容性:最低只能兼容到IE10。
gird解决方案
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <div class="parent"> <div class="header">header</div> <div class="lside">lsidelsidelside</div> <div class="content"> <div class="inner"> 主内容区 </div> </div> <div class="footer">footer</div> </div> <style> html,body,.parent{margin: 0;padding: 0;height: 100%;} .parent{ display: grid; grid-gap: 2px; grid-template-columns: 20% auto; grid-template-rows: 10% auto 5%; overflow: hidden; } .parent div{background: lightsalmon;} .header,.footer{grid-column: 1/4;} .lside{ grid-column: 1; word-wrap: break-word; } .content{ grid-column: 2/4; overflow: auto; } .content .inner{ min-width: 500px; min-height: 1000px; } </style>
|
详解:上述代码实现了一个栅格的全屏布局。关于gird布局的用法,详见本博客文章CSS Gird布局入门
兼容性:很差,IE完全不支持。
总结对比
| 方案 |
兼容 |
性能 |
自适应 |
| Position |
好 |
好 |
部分自适应 |
| Flex |
较差 |
差 |
可自适应 |
| Grid |
差 |
较好 |
可自适应 |
其它布局
全等四宫格布局

两侧定宽,中间自适应布局

水平列表的底部对齐

学习资料