简单来说Html Dom元素就2类:行内元素和块级元素,前者在行内显示(span等),后者换行显示(div等)。所谓布局,比如早期的4大布局:块布局、行内布局、表格布局、定位布局,多半解决的是块级元素行内显示问题。我们可以看下块级元素行内显示的常见方式:
- float,浮动显示,float-left或float-right;
- display: inline-block,块级元素转为行内块显示,大名鼎鼎的前端框架bootstrap深谙此道,btn-group|form-group|input-group等都是基于此实现;
- 表格布局:将块元素放到td里,“任凭你块元素多?,也只能在我的td里猫着”;
- position:流氓布局,可以想哪显示就哪显示,设z-index:9999基本上就可以遮挡所有元素在最前显示啦
基于此,基本上早期的页面都是表格布局,后来逐渐被div+css替代,现在呢?
- 以bootstrap为例,依然还是float布局,经典的col-*栅格系统就是基于此实现;
- 以微信小程序为例,则是flex布局;
除此之外,display:table-cell也有很多粉丝,其表现基本上同td,俗称不是表格的表格。早期块级元素行内显示有2个难点:
- 垂直居中显示问题;
- 剩余宽度(高度)100%填充问题;
随着CSS3引入多列column-count和flex布局,块级元素行内显示问题,我们有了更多地选择,同时也可以比较优雅地解决垂直居中和宽度、高度自适应问题。接下来,本文将先简单介绍下display:table-cell的使用,然后重点讲解多列column-count和flex布局。
一、display: table-cell
CSS display属性与表格相关的值有下述几种:
值 | 描述 |
---|---|
table | 此元素会作为块级表格来显示(类似 < table >),表格前后带有换行符。 |
inline-table | 此元素会作为内联表格来显示(类似 < table>),表格前后没有换行符。 |
table-row-group | 此元素会作为一个或多个行的分组来显示(类似 < tbody>)。 |
table-header-group | 此元素会作为一个或多个行的分组来显示(类似 < thead>)。 |
table-footer-group | 此元素会作为一个或多个行的分组来显示(类似 < tfoot>)。 |
table-row | 此元素会作为一个表格行显示(类似 < tr>)。 |
table-column-group | 此元素会作为一个或多个列的分组来显示(类似 < colgroup>)。 |
table-column | 此元素会作为一个单元格列显示(类似 < col>) |
table-cell | 此元素会作为一个表格单元格显示(类似 < td> 和 < th>) |
table-caption | 此元素会作为一个表格标题显示(类似 < caption>) |
比较常用的有:display: table; display: table-row; display: table-cell; 一个经典的table-cell布局为:table -> table-row -> table-cell,对应表格的table->tr->td,看个案例:
.table {display: table; border-collapse: collapse;}
.table-cell{display: table-cell; border: 1px solid #e2e2e2; height: 60px; vertical-align: middle; min-width: 200px; padding: 8px}
<div class="table">
<div class="table-row">
<div class="table-cell cell1" style="width: 200px;">table-cell: cell1</div>
<div class="table-cell cell2" style="width: 100%;">table-cell: cell2</div>
<div class="table-cell cell3" style="width: 200px;">table-cell: cell3</div>
</div>
</div>
<div class="table">
<div class="table-cell cell1" style="width: 200px;">table-cell: cell1</div>
<div class="table-cell cell2" style="width: 100%;">table-cell: cell2, 没有table-row元素</div>
<div class="table-cell cell3" style="width: 200px;">table-cell: cell3</div>
</div>
从上述案例可以看出,有无< div class=“table-row”>元素,效果一样,原因是:浏览器会自动创建一个表格匿名行,另外:
- 轻松实现文字(换成图片也一样,某宝很多店铺的宝贝图片就是采用此法实现图片垂直居中显示)垂直居中;
- 轻松实现剩余宽度100%填充,这里有个技巧:cell1,cell3需要设置width、min-width,cell2的width: 100%才有意义;
- 将cell2变成一个只是占宽度,没有意义的空div,则可实现cell1,cell3两端对齐。
除此之外,display: table-cell还有一个妙用:元素等高对齐或者说高度跟随
.table {display: table; border-collapse: collapse;}
.table-cell{display: table-cell; border: 1px solid #e2e2e2; height: 60px; vertical-align: middle; min-width: 200px; padding: 8px}
.table-height .cell1{background: rgba(255,0,0,0.6);}
.table-height .cell3{background: rgba(0,0,255,0.6); height: 80px;}
<div class="table table-height">
<div class="table-cell cell1" style="width: 200px;">table-cell: cell1</div>
<div class="table-cell cell2" style="width: 100%;">table-cell: cell2, 把cell3的高度设置成80px,cell1和cell2的高度也变成了80px</div>
<div class="table-cell cell3" style="width: 200px;">table-cell: cell3</div>
</div>
说明: cell3设置了高度80px,cell1和cell2高度跟随cell3变成了80px
二、多列columns、column-count
css3引入了多列文本布局:columns, column-count, column-gap等相关属性设置,其本意是实现如报纸一样的多栏显示,因此我们看到很多案例的class都命名为报纸(newspaper)。多列本质是将容器内的文本元素或div等块级元素按column-count或column-width进行等分,因此多列布局也可用于块级元素行内显示,很多瀑布流就是基于多列布局来实现的。下面我们先看下与多列布局有关的几个关键属性:
- column-count: number|auto,默认值auto,列数设置;
如设置了column-width则可以不设置column-count,浏览器会按容器宽度、column-width、column-gap计算列数;- column-gap: length|normal,默认值normal(通常是1em,如果没有设置font-size,则常见浏览器1em = 16px),列间隙设置;
- column-rule: column-rule-width column-rule-style column-rule-color;
设置列之间分割线的宽度、样式、颜色,column-rule:3px outset #ff00ff,类似border:1px solid #ff00ff,也可宽度、样式和颜色单独设置:
- column-rule-width: thin|medium|thick|length;
设置分割线宽度,其值有:纤细|中等|宽厚|指定宽度,默认值为medium- column-rule-style: none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset;
设置分割线样式,默认值为none;groove,ridge,inset和outset效果取决于宽度和颜色;- column-rule-color: color; 设置分割线颜色,默认为black
看个案例:
.columns {column-count: 3; column-gap: 20px; column-rule:2px outset #ff00ff; column-width: 100px; margin-bottom: 20px}
.columns-width {column-count: auto; column-width: 100px;}
.columns .col {border: 1px solid #e2e2e2; padding: 10px; height: 100px;}
.columns-width .col{height: 50px}
<div class="columns">
<div class="col col1">col1</div>
<div class="col col2">column-count: 3;<br>column-gap: 20px;<br>column-rule: 2px outset #ff00ff;</div>
<div class="col col3">col3<br>column-width=(1140 - 20 *2)/3</div>
</div>
<div class="columns columns-width" style="column-width:200px;">
<div class="col col1">col1</div>
<div class="col col2">column-width:200px</div>
<div class="col col3">col3</div>
</div>
<div class="columns columns-width" style="column-width:300px;">
<div class="col col1">col1</div>
<div class="col col2">column-width:300px</div>
<div class="col col3">col3</div>
</div>
说明:
- 同时设置了column-count、column-width,则column-width无效;
- 设置column-width需谨慎,根据column-width计算列数不太好计算,假设column-width: 200px,容器宽度1140px,则具体步骤如下:
1)先确定列数n,200*n + (n-1)*20<=1140,求得n最大值 = 5;
2)根据列数,重新计算列宽 = (1140 - (5 -1)*20)/5 = 212;
三、flex布局
CSS3 弹性盒子( Flexible Box 或 flexbox),是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的布局方式,并且x轴和y轴(或flex主轴、辅轴)都适用,flex布局是微信小程序页面布局首选。flex布局规范、语法说明,大家参考下述2篇,讲解的比较透彻、形象。
- CSS Flexible Box Layout,https://www.w3.org/TR/css-flexbox-1/
- Flex 布局教程:语法篇,http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
本文以flex实际案例为主,于案例间讲解flex相关属性使用说明及注意事项。
1、justify-content和align-items
.table .box {
width: 92px; height: 92px; border: 1px solid #e2e2e2; border-radius: 5px;
box-shadow: 0px 0px 10px rgba(0,0,0,0.8);
display: flex;
}
.table .point {
width: 20px; height: 20px; margin: 5px; border-radius: 50%; background: #000;
display:block; color:#fff; font-size:12px; text-align:center; line-height: 20px;
}
<table class='table table-bordered'>
<tr>
<td><div class='box'><span class='point'>1</span></div></td>
<td><div class='box' style="justify-content:center"><span class='point'>2</span></div></td>
<td><div class='box' style="justify-content:flex-end"><span class='point'>3</span></div></td>
<td><div class='box' style="align-items:center"><span class='point'>4</span></div></td>
<td><div class='box' style="justify-content:center;align-items:center"><span class='point'>5</span></div></td>
<td><div class='box' style="justify-content:center;align-items:flex-end"><span class='point'>8</span></div></td>
<td><div class='box' style="justify-content:flex-end;align-items:flex-end"><span class='point'>9</span></div></td>
</tr>
<tr>
<td></td>
<td>justify-content:center</td>
<td>justify-content:flex-end</td>
<td>align-items:center</td>
<td>justify-content:center;<br>align-items:center</td>
<td>justify-content:center;<br>align-items:flex-end</td>
<td>justify-content:flex-end;<br>align-items:flex-end</td>
</tr>
</table>
1)justify-content,元素在主轴上的对齐方式
语法: -content: flex-start | flex-end | center | space-between | space-around
说明: flex-direction = row|row-reverse的话,主轴为x轴,默认值flex-start,各个值说明如下:
- flex-start:元素从行开始处开始摆放;
- flex-end:元素靠着行结尾摆放;
- center:元素居中摆放;
- space-between:元素均匀分布在该行上,元素之间间隙一致;
- space-around:元素均匀分布在该行上,元素之间间隙一致,首尾元素距离行首、行尾为元素间隙一半;
2)align-items,元素在辅轴上的对齐方式
语法: align-items: flex-start | flex-end | center | baseline | stretch
说明: flex-direction = row|row-reverse的话,辅轴为y轴,默认值stretch;以y轴为辅轴为例,各个值说明如下:
- flex-start:元素顶部对齐
- flex-end:元素底部对齐
- center:元素垂直居中;
- baseline:与基线对齐,基本上同flex-start,受元素line-height影响;
- stretch:默认值,如果元素高度没设置或auto,则高度拉伸为容器的高度,但同时会遵照’min/max-width/height’属性的限制;
3)案例说明
- 元素设置了display: flex, 启用flex布局
- 没有设置flex-direction,默认值为row,主轴为x轴,辅轴为y轴;
2、一个完整的骰子?案例
上个案例主要说明在flex-direction:row的情况下,align-items和justify-content属性的运用,本案例将绘制骰子的6个面,涉及align-self、flex布局嵌套等更多flex布局应用。
.flex-row {display: flex; flex-direction: row;}
.flex-col {display: flex; flex-direction: column;}
.flex-dice .box {
width: 92px; height: 92px; border: 1px solid #e2e2e2; border-radius: 8px;
box-shadow: 0px 0px 8px rgba(0,0,0,0.8);
}
.flex-dice .point {
width: 20px; height: 20px; margin: 5px; border-radius: 50%; background: blue;
display:block; color:#fff; font-size:12px; text-align:center; line-height: 20px;
}
.box-dice4 .point {background: red}
<table class='table table-bordered flex-dice'>
<tr>
<td><div class='box flex-row' style="justify-content:center;align-items:center"><span class='point point1' style="background:red;"></span></div></td>
<td><div class='box flex-col' style="justify-content:space-between; align-items:center">
<span class='point'></span><span class='point'></span>
</div></td>
<td><div class='box flex-row'>
<span class='point'></span>
<span class='point' style="align-self:center"></span>
<span class='point' style="align-self:flex-end"></span>
</div></td>
<td><div class='box flex-col box-dice4' style="justify-content: space-between;">
<div class='flex-row' style="justify-content: space-between;">
<span class='point'></span><span class='point'></span>
</div>
<div class='flex-row' style="justify-content: space-between;">
<span class='point'></span><span class='point'></span>
</div>
</div></td>
<td><div class='box flex-col'>
<div class='flex-row' style="justify-content: space-between;">
<span class='point'></span><span class='point'></span>
</div>
<div class='flex-row' style="justify-content: center;">
<span class='point'></span>
</div>
<div class='flex-row' style="justify-content: space-between;">
<span class='point'></span><span class='point'></span>
</div>
</div></td>
<td><div class='box flex-col'>
<div class='flex-row' style="justify-content: center;">
<span class='point'></span><span class='point'></span>
</div>
<div class='flex-row' style="justify-content: center;">
<span class='point'></span><span class='point'></span>
</div>
<div class='flex-row' style="justify-content: center;">
<span class='point'></span><span class='point'></span>
</div>
</div></td>
</tr>
<tr>
<td>flex-row<br>justify-content:center<br>align-items:center</td>
<td>flex-col<br>justify-content:space-between;<br>align-items:center</td>
<td>flex-row<br>p2 align-self:center<br>p3 align-self:flex-end</td>
<td>flex-col<br>justify-content:space-between;<br>flex-col<br>justify-content:space-between;</td>
<td>flex-col<br>flex-row<br>justify-content:space-between;<br>justify-content:center;<br>justify-content:space-between;</td>
<td>flex-col<br>flex-row<br>justify-content:center</td>
</tr>
</table>
案例说明:
1)align-self 属性解析
align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
语法: align-self: auto | flex-start | flex-end | center | baseline | stretch
说明: 除auto值外,其它值同align-items参数值。
2)flex布局嵌套
案例中,骰子4点,5点,6点使用了flex嵌套,先是flex-direction: column布局,然后每行又是flex-direction: row布局;
3)代码结构
通过class统一设置flex布局,flex-col class,flex布局,主轴为y轴;flex-row class,flex布局,主轴为x轴。flex布局里的item元素,用内敛style具体实现。
3、剩余高度、宽度填充
剩余高度、宽度填充需要使用到flex布局的另外3个关键属性:flex-grow、flex-shrink、flex-basis和flex(前三者的简写),具体说明如下:
- flex-grow 属性用于设置或检索弹性盒子的扩展比率,默认 0
语法: flex-grow: number|initial|inherit;- flex-shrink 属性指定了 flex 元素的收缩规则。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值,默认值为1,即同比例收缩。
语法: flex-shrink: number|initial|inherit;- flex-basis 属性用于设置或检索弹性盒伸缩基准值,默认值auto
语法: flex-basis: number|auto|initial|inherit;- flex 属性用于设置或检索弹性盒模型对象的子元素如何分配空间,是 flex-grow、flex-shrink 和 flex-basis 属性的简写属性。
语法: flex: flex-grow flex-shrink flex-basis|auto|initial|inherit; 默认值flex: 0 1 auto,flex:auto = flex: 1 1 auto,flex:1 = flex:1 1 auto;
1)剩余高度填充
剩余高度填充常见处理方式:
- 固定元素:定义其高度,或设置flex-basis属性,如hd-4
- 填充元素:设置flex:1
- 需要解决内容溢出问题,如hd-4,bd-5,需要overflow:hidden;
2)剩余宽度填充
最常见恐怕莫过是form表单里的label+input框啦,前者固定宽度,后者填充剩余宽度,看个案例:
剩余宽度填充常见处理方式:
- 固定元素:定义其宽度,或设置flex-basis属性,如label width统一设置为60px
- 填充元素:设置flex:1,若flex:1的显示结果不是期望值,请在flex:1元素上添加overflow:hidden试试。
- 可以铜鼓align-items,设置label垂直方向对齐方式,如“意见”垂直居中显示。
CSS3新特性详解(五):多列columns column-count和flex布局
- Author -
老马历写记声明:登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。
Reply on: @reply_date@
@reply_contents@