这边文章主要整理了一些经常被问到的布局问题 ~
水平垂直居中
<div class="wrapper">
<div class="box size">123123</div>
</div>
居中元素定宽高
-
absolute+负 margin.wrapper { border: 1px solid red; width: 300px; height: 300px; position: relative; } .box { background: green; width: 100px; height: 100px; position: absolute; top: 50%; left: 50%; margin-left: -50px; margin-top: -50px; } -
absolute+margin auto.wrapper { border: 1px solid red; width: 300px; height: 300px; position: relative; } .box { background: green; width: 100px; height: 100px; position: absolute; top: 0; left: 0; bottom: 0; right: 0; margin: auto; } -
absolute+calc.wrapper { border: 1px solid red; width: 300px; height: 300px; position: relative; } .box { background: green; width: 100px; height: 100px; position: absolute; top: calc(50% - 50px); left: calc(50% - 50px); }
居中元素不定宽高
-
absolute+transform(此方法同样适用上面居中元素定宽高).wrapper { border: 1px solid red; width: 300px; height: 300px; position: relative; } .box { background: green; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } -
line-height+height.wrapper { border: 1px solid red; width: 300px; height: 300px; line-height: 300px; /* 行高的值与 height 相等 */ text-align: center; font-size: 0; /* 消除幽灵空白节点、近似居中的 bug */ } .box { background: green; display: inline-block; /* 若是块级元素需改为行内或行内块级才生效 */ vertical-align: middle; font-size: 16px; line-height: initial; /* 默认值 */ text-align: left; /* 修正文字 */ } -
inline-block+伪元素.wrapper { border: 1px solid red; width: 300px; height: 300px; position: relative; display: inline-block; white-space: nowrap; text-align: center; } .wrapper::after { content:''; display: inline-block; vertical-align: middle; height: 100%; } .box { background: green; display: inline-block; /* 若是块级元素需改为行内或行内块级才生效 */ vertical-align: middle; } -
table:tabel 单元格中的内容天然就是垂直居中的,需添加一个水平居中属性即可,该方法代码太冗余<table> <tbody> <tr> <td class="wrapper"> <div class="box">123123</div> </td> </tr> </tbody> </table> // css .wrapper { border: 1px solid red; width: 300px; height: 300px; text-align: center; } .box { background: green; display: inline-block; } -
table-cell:CSS 新增的table属性,可把普通元素变为table元素的现实效果,该方法和table一样原理,但没有那么多冗余代码,兼容性也还不错.wrapper { display: table-cell; vertical-align: middle; text-align: center; border: 1px solid red; width: 300px; height: 300px; } .box { background: green; display: inline-block; } -
flex:注意兼容性.wrapper { display: flex; justify-content: center; align-items: center; border: 1px solid red; width: 300px; height: 300px; } .box { background: green; } -
grid:网格布局,代码量也很少,但兼容性不如flex.wrapper { display: grid; border: 1px solid red; width: 300px; height: 300px; } .box { background: green; align-self: center; justify-self: center; } -
writing-mode:可以改变文字的显示方向,如可通过writing-mode让文字的显示变为垂直方向,结合text-align可实现<div class="wrapper"> <div class="wrapper-inner"> <div class="box">123123</div> </div> </div> .wrapper { writing-mode: vertical-lr; text-align: center; border: 1px solid red; width: 300px; height: 300px; } .wrapper-inner { writing-mode: horizontal-tb; display: inline-block; width: 100%; } .box { background: green; display: inline-block; }
PC 端无兼容性要求,推荐
flex;移动端推荐使用flex;关于flex的兼容性决方案,请看这里《移动端flex布局实战》
两列布局
左列定宽,右列自适应
-
float+margin<div class="left">左列定宽</div> <div class="right">右列自适应</div> .left { background-color: red; float: left; width: 100px; height: 500px; } .right { background-color: yellow; height: 500px; margin-left: 100px; /* 大于等于 left 的宽度 */ } -
float+margin(fix)<div class="left">左列定宽</div> <div class="right-fix"> <div class="right">右列自适应</div> </div> .left { background-color: red; float: left; width: 100px; height: 500px; } .right-fix { float: right; width: 100%; margin-left: -100px; /* 正值大于或等于 left 的宽度,才能显示在同一行 */ } .right { background-color: yellow; height: 500px; margin-left: 100px; /* 大于等于 left 的宽度 */ } -
float+overflow- 优点:代码简单,容易理解,无需关注定宽的宽度,利用
BFC达到自适应效果 - 缺点:浮动脱离文档流,需要手动清除浮动,否则容易产生高度塌陷;不支持 IE6
<div class="left">左列定宽</div> <div class="right">右列自适应</div> .left { background-color: red; float: left; width: 100px; height: 500px; } .right { background-color: yellow; height: 500px; overflow: hidden; /*触发 BFC 达到自适应*/ } - 优点:代码简单,容易理解,无需关注定宽的宽度,利用
-
absolute<div class="parent"> <div class="left">左列定宽</div> <div class="right">右列自适应</div> </div> .parent { position: relative; /*子绝父相*/ } .left { background-color: red; position: absolute; top: 0; left: 0; width: 100px; height: 500px; } .right { background-color: yellow; height: 500px; position: absolute; top: 0; left: 100px; /*值大于等于 left 的宽度*/ right: 0; } -
flex<div class="parent"> <div class="left">左列定宽</div> <div class="right">右列自适应</div> </div> .parent { width: 100%; height: 500px; display: flex; } .left { width: 100px; background-color: red; } .right { background-color: yellow; flex: 1; /*均分了父元素剩余空间*/ } -
table- 优点:代码简单,容易理解,无需关注定宽的宽度,利用单元格自动分配达到自适应效果
- 缺点:margin 失效;设置间隔比较麻烦;不支持 ie8-
<div class="parent"> <div class="left">左列定宽</div> <div class="right">右列自适应</div> </div> .parent { width: 100%; height: 500px; display: table; } .left, .right { display: table-cell; /*利用单元格自动分配宽度*/ } .left { width: 100px; background-color: red; } .right { background-color: yellow; } -
Grid<div class="parent"> <div class="left">左列定宽</div> <div class="right">右列自适应</div> </div> .parent { width: 100%; height: 500px; display: grid; grid-template-columns: 100px auto; /*设定 2 列就 ok 了,auto 换成 1fr 也行*/ } .left { background-color: red; } .right { background-color: yellow; }
左列自适应,右列定宽
-
float+margin<div class="parent"> <div class="left">左列自适应</div> <div class="right">右列定宽</div> </div> .parent { padding-left: 100px; /* 抵消 left 的 margin-left 以达到 parent 水平居中 */ } .left { width: 100%; height: 500px; float: left; margin-left: -100px; /* 正值等于 right 的宽度 */ background-color: #f00; } .right { width: 100px; height: 500px; float: right; background-color: #0f0; } -
float+overflow<div class="parent"> <div class="right">右列定宽</div> <div class="left">左列自适应</div> <!--顺序要换一下--> </div> .left { background-color: #f00; overflow: hidden; /* 触发bfc */ height: 500px; } .right { height: 500px; width: 100px; float: right; background-color: #0f0; }
其他的方法如
absolute、flex、table、grid与上文【左列定宽右列自适应】相反
一列不定宽,一列自适应(盒子宽度随着内容增加或减少发生变化,另一个盒子自适应)
改变前
改变后
-
float+overflow<div class="parent"> <div class="left">左列不定宽</div> <div class="right">右列自适应</div> </div> .left { margin-right: 10px; float: left; /* 只设置浮动,不设宽度 */ height: 500px; background-color: #f00; } .right { overflow: hidden; /* 触发 bfc */ height: 500px; background-color: #0f0; } -
flex<div class="parent"> <div class="left">左列不定宽</div> <div class="right">右列自适应</div> </div> .parent { display: flex; } .left { /*不设宽度*/ margin-right: 10px; height: 500px; background-color: #f00; } .right { height: 500px; background-color: #0f0; flex: 1; /* 均分 parent 剩余的部分 */ } -
Grid<div class="parent"> <div class="left">左列不定宽</div> <div class="right">右列自适应</div> </div> .parent { display: grid; grid-template-columns: auto 1fr; /* auto 和 1fr 换一下顺序就是左列自适应,右列不定宽了*/ } .left { margin-right: 10px; height: 500px; background-color: red; } .right { height: 500px; background-color: yellow; }
三列布局
两列定宽,一列自适应
-
float+margin<div class="parent"> <div class="left">左列定宽</div> <div class="center">中间定宽</div> <div class="right">右列自适应</div> </div> .parent { min-width: 310px; /* 100 + 10 + 200,防止宽度不够,子元素换行 */ } .left { margin-right: 10px; /* left 和 center 间隔 */ float: left; width: 100px; height: 500px; background-color: red; } .center { float: left; width: 200px; height: 500px; background-color: green; } .right { margin-left: 320px; /*等于 left 和 center 的宽度之和加上间隔,多出来的是 right 和 center 的间隔 */ height: 500px; background-color: #0f0; } -
float+overflow<div class="parent"> <div class="left">左列定宽</div> <div class="center">中间定宽</div> <div class="right">右列自适应</div> </div> .parent { min-width: 320px; /* 100+10+200+10,防止宽度不够,子元素换行*/ } .left { margin-right: 10px; /* left 和 center 间隔*/ float: left; width: 100px; height: 500px; background-color: red; } .center { float: left; width: 200px; height: 500px; background-color: green; margin-right: 10px; /* 在此定义和 right 的间隔 */ } .right { overflow: hidden; /* 触发 bfc */ height: 500px; background-color: yellow; } -
flex<div class="parent"> <div class="left">左列定宽</div> <div class="center">中间定宽</div> <div class="right">右列自适应</div> </div> .parent { height: 500px; display: flex; } .left { margin-right: 10px; /* left 和 center 间隔*/ width: 100px; background-color: red; } .center { width: 200px; background-color: green; margin-right: 10px; /* 在此定义和 right 的间隔 */ } .right { flex: 1; /* 均分 parent 剩余的部分达到自适应 */ background-color: yellow; } -
table<div class="parent"> <div class="left">左列定宽</div> <div class="center">中间定宽</div> <div class="right">右列自适应</div> </div> .parent { width: 100%; display: table; height: 520px; /* 抵消上下间距 10*2 的高度影响 */ margin: -10px 0; /* 抵消上下间距 10 的位置影响 */ /* 左右两边间距大了一点,子元素改用 padding 设置盒子间距就没有这个问题 */ border-spacing: 10px; /* 以下子元素 margin 设置间距失效,关键!!!设置间距 */ } .left { display: table-cell; width: 100px; background-color: red; } .center { width: 200px; background-color: green; display: table-cell; } .right { display: table-cell; background-color: yellow; } -
Grid<div class="parent"> <div class="left">左列定宽</div> <div class="center">中间定宽</div> <div class="right">右列自适应</div> </div> .parent { height: 500px; display: grid; grid-template-columns: 100px 200px auto; /*设置 3 列,固定第一第二列的宽度,第三列 auto 或者 1fr*/ } .left { margin-right: 10px; /*间距*/ background-color: red; } .center { margin-right: 10px; /*间距*/ background-color: green; } .right { background-color: yellow; }
两侧定宽,中间自适应
-
圣杯布局- 利用
浮动和相对定位实现 - 缺点:圣杯布局会有个问题,当将浏览器宽度缩短到一定程度时会使得中间子元素的宽度比左右子元素宽度小,这时布局就会出现问题,所以在使用圣杯布局时一定要设置整个容器的最小宽度
<div class="header">header</div> <div class="parent"> <!--#center需要放在前面--> <div class="center">中间自适应 <hr> <!--方便观察原理--> </div> <div class="left">左列定宽</div> <div class="right">右列定宽</div> </div> <div class="footer">footer</div> .header, .footer { height: 60px; background-color: #ccc; } .parent { height: 300px; padding: 0 215px 0 115px; /* 为了使 center 摆正,左右 padding 分别等于左右盒子的宽,可以结合左右盒子相对定位的 left 调整间距 */ } .parent div { height: 300px } .left, .center, .right { position: relative; float: left; } .left { margin-left: -100%; /* 使 left 上去一行 */ left: -115px; /* 相对定位调整 left 的位置,正值大于或等于自身宽度 */ background-color: red; width: 100px; } .center { width: 100%; /* 由于 parent 的 padding,达到自适应的目的 */ box-sizing: border-box; border: 1px solid #000; background-color: yellow; } .right { left: 215px; /* 相对定位调整 right 的位置,大于或等于自身宽度 */ width: 200px; margin-left: -200px; /* 使 right 上去一行 */ background-color: green; } - 利用
-
双飞翼布局为了解决圣杯布局的弊端,实现中间部分自适应时多嵌套了一个 div 且不再使用相对定位
<div class="header">header</div> <div class="parent"> <!--#center需要放在前面--> <div class="center"> <div class="center_inner">中间自适应</div> <hr> <!--方便观察原理--> </div> <div class="left">左列定宽</div> <div class="right">右列定宽</div> </div> <div class="footer">footer</div> .header, .footer { height: 60px; background-color: #ccc; } .parent, .parent div { height: 300px } .left, .center, .right { float: left; } .left { margin-left: -100%; /* 使 left 上去一行 */ background-color: red; width: 100px; } .center { width: 100%; border: 1px solid #000; background-color: yellow; } .center_inner { height: 280px; border: 1px solid #000; margin: 0 220px 0 120px; /* 关键!!!左右边界等于左右盒子的宽度,多出来的为盒子间隔 */ } .right { width: 200px; margin-left: -200px; /* 使 right 上去一行 */ background-color: green; } -
flexflex: flex-grow | flex-shrink | flex-basis;分别为:空间充足放大比,空间不足缩小比以及计算剩余空间之前的宽度值<div class="parent"> <div class="left">左列定宽</div> <div class="center">中间自适应</div> <div class="right">右列定宽</div> </div> .parent { display: flex; } .parent div { height: 300px; } .left, .right { width: 200px; /* flex: 0 0 200px; */ } .left { background-color: red; } .center { flex: 1; background-color: yellow; } .right { background-color: green; } -
absolute- 优点:容易理解,兼容性比较好
- 缺点:需手动计算宽度确定边距;脱离文档流;代码繁多
<div class="parent"> <div class="left">左列定宽</div> <div class="center">中间自适应</div> <div class="right">右列定宽</div> </div> .parent { position: relative; /* 子绝父相 */ } .parent div { height: 300px; } .left, .right { width: 200px; /* flex: 0 0 200px; */ } .left { position: absolute; top: 0; left: 0; background-color: red; } .center { margin-left: 200px; /*大于等于 left 的宽度或者给 parent 添加同样大小的 padding-left*/ margin-right: 200px; /*大于等于 right 的宽度或者给 parent 添加同样大小的 padding-right*/ background-color: yellow; } .right { position: absolute; top: 0; right: 0; background-color: green; } -
table- 优点:代码简洁,容易理解;
- 缺点:margin 失效,采用 border-spacing 表格两边的间隔无法消除;不支持 ie8-
<div class="parent"> <div class="left">左列定宽</div> <div class="center">中间自适应</div> <div class="right">右列定宽</div> </div> .parent { width: 100%; height: 500px; display: table; } .left, .right { width: 200px; /* flex: 0 0 200px; */ } .left { display: table-cell; background-color: red; } .center { display: table-cell; background-color: yellow; } .right { display: table-cell; background-color: green; } -
Grid- Grid 是微软提出的网页布局解决方案,最新的
Safari、Chrome、Firefox都已经进行了支持。个人感觉Grid布局比flex布局更强大一些,宽高两个方向上都可以得到控制且Grid也更容易理解(但Grid在移动端的支持应该没有flex强)
<div class="parent"> <div class="left">左列定宽</div> <div class="center">中间自适应</div> <div class="right">右列定宽</div> </div> .parent { display: grid; grid-template-columns: 200px auto 200px; grid-template-rows: 100px } .left { background-color: red; } .center { background-color: yellow; } .right { background-color: green; }<div class="parent"> <div class="header"></div> <div class="left">左列定宽</div> <div class="center"> 中间自适应 <hr /> </div> <div class="right">右列定宽</div> <div class="footer"></div> </div> .parent { height: 500px; display: grid; grid-template-columns: 100px auto 200px; /*设定3列*/ grid-template-rows: 60px auto 60px; /*设定3行*/ /*设置网格区域分布*/ grid-template-areas: "header header header" "leftside main rightside" "footer footer footer"; } .header,.footer { background-color: #ccc; } .header { grid-area: header; /*指定在哪个网格区域*/ } .left { grid-area: leftside; background-color: red; } .center { grid-area: main; /*指定在哪个网格区域*/ margin: 0 15px; /*设置间隔*/ border: 1px solid #000; background-color: yellow; } .right { grid-area: rightside; /*指定在哪个网格区域*/ background-color: green; } .footer { grid-area: footer; /*指定在哪个网格区域*/ } - Grid 是微软提出的网页布局解决方案,最新的
-
CSS3的calcCSS3提供的calc功能能够实现给宽高等设置动态的值,支持+ - * /四则运算,注意运算符两边要个留一个空格否则设置无效- 同样需要设置
浮动将三个元素并排显示
<div class="parent"> <div class="left">左列定宽</div> <div class="center">中间自适应</div> <div class="right">右列定宽</div> </div> .parent div { float: left; height: 300px; } .left, .right { width: 200px; background-color: red; } .center { width: calc(100% - 400px); background-color: green; }
多列布局
多列等宽布局
-
float- 优点:代码简单,容易理解;兼容性较好
- 缺点:需要手动清除浮动,否则会容易产生高度塌陷
<div class="parent"> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> </div> .column { width: 25%; float: left; box-sizing: border-box; border: 1px solid #000; background-clip: content-box; /* 背景色从内容开始绘制,方便观察 */ height: 500px; } .column:nth-child(odd) { background-color: red; } .column:nth-child(even) { background-color: green; } -
flex<div class="parent"> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽 </div> </div> .parent { margin-left: -15px; /* 使内容看起来居中 */ height: 500px; display: flex; } .column { flex: 1; /* 一起平分 parent */ margin-left: 15px; /* 设置间距 */ } .column:nth-child(odd) { background-color: red; } .column:nth-child(even) { background-color: green; } -
table<div class="parent"> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> </div> .parent { height: 500px; display: table; margin: -20px 0; /* 抵消上下边 20*2 间距的位置影响 */ /* 两边离页面间距较大,改用子元素设置 padding 来当成间隔就不会有这样的问题 */ border-spacing: 20px; /*设置间距*/ } .column { display: table-cell; } .column:nth-child(odd) { background-color: red; } .column:nth-child(even) { background-color: green; } -
Grid<div class="parent"> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> <div class="column">等宽等宽等宽等宽等宽等宽等宽等宽等宽等宽</div> </div> .parent { height: 500px; display: grid; grid-template-columns: repeat(4, 1fr); /* 4 就是列数 */ } .column:nth-child(odd) { background-color: red; } .column:nth-child(even) { background-color: green; }
九宫格布局
-
table<div class="parent"> <div class="row"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> <div class="row"> <div class="item">4</div> <div class="item">5</div> <div class="item">6</div> </div> <div class="row"> <div class="item">7</div> <div class="item">8</div> <div class="item">9</div> </div> </div> .parent { width: 1200px; height: 500px; margin: 0 auto; display: table; } .row { display: table-row; } .item { border: 1px solid #000; display: table-cell; } -
flex<div class="parent"> <div class="row"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> <div class="row"> <div class="item">4</div> <div class="item">5</div> <div class="item">6</div> </div> <div class="row"> <div class="item">7</div> <div class="item">8</div> <div class="item">9</div> </div> </div> .parent { width: 1200px; height: 500px; margin: 0 auto; display: flex; flex-direction: column; } .row { display: flex; flex: 1; } .item { flex: 1; border: 1px solid #000; } -
Grid- CSS Grid 非常强大,可以实现各种各样的三维布局
<div class="parent"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> <div class="item">5</div> <div class="item">6</div> <div class="item">7</div> <div class="item">8</div> <div class="item">9</div> </div> .parent { width: 1200px; height: 500px; margin: 0 auto; display: grid; grid-template-columns: repeat(3, 1fr); /* 等同于1fr 1fr 1fr,此为重复的合并写法 */ grid-template-rows: repeat(3, 1fr); /* 等同于1fr 1fr 1fr,此为重复的合并写法 */ } .item { border: 1px solid #000; }
栅格系统
优点:代码简洁,容易理解;提高页面内容的流动性,能适应多种设备
Less编译后的 CSS 代码/*生成栅格系统*/ @media screen and (max-width: 768px){ .generate-columns(12); /*此处设置生成列数*/ .generate-columns(@n, @i: 1) when (@i <= @n) { .column-xs-@{i} { width: (@i * 100% / @n); } .generate-columns(@n, (@i+1)); } } @media screen and (min-width: 768px){ .generate-columns(12); /*此处设置生成列数*/ .generate-columns(@n, @i: 1) when (@i <= @n) { .column-sm-@{i} { width: (@i * 100% / @n); } .generate-columns(@n, (@i+1)); } } div[class^="column-xs-"]{ float: left; } div[class^="column-sm-"]{ float: left; }@media screen and (max-width: 768px) { .column-xs-1 { width: 8.33333333%; } .column-xs-2 { width: 16.66666667%; } .column-xs-3 { width: 25%; } .column-xs-4 { width: 33.33333333%; } .column-xs-5 { width: 41.66666667%; } .column-xs-6 { width: 50%; } .column-xs-7 { width: 58.33333333%; } .column-xs-8 { width: 66.66666667%; } .column-xs-9 { width: 75%; } .column-xs-10 { width: 83.33333333%; } .column-xs-11 { width: 91.66666667%; } .column-xs-12 { width: 100%; } } @media screen and (min-width: 768px) { .column-sm-1 { width: 8.33333333%; } .column-sm-2 { width: 16.66666667%; } .column-sm-3 { width: 25%; } .column-sm-4 { width: 33.33333333%; } .column-sm-5 { width: 41.66666667%; } .column-sm-6 { width: 50%; } .column-sm-7 { width: 58.33333333%; } .column-sm-8 { width: 66.66666667%; } .column-sm-9 { width: 75%; } .column-sm-10 { width: 83.33333333%; } .column-sm-11 { width: 91.66666667%; } .column-sm-12 { width: 100%; } } div[class^="column-xs-"]{ float: left; } div[class^="column-sm-"]{ float: left; }