flex_0">CSS3 之 弹性布局 flex
布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。
2009年,W3C提出伸缩盒模型草案,该草案主要用于优化UI布局,可以简单地使一个元素居中(包括水平和垂直居中),可以扩大或收缩元素来填充容器的可用空间,可以改变布局顺序等。伸缩盒模型分为旧版本、新版本以及混合过渡版本3种不同的语法规则。其中混合过渡版本主要是针对IE10做了兼容。
旧版模型
知识点
在旧版本中启动伸缩盒模型,只需设置容器的 display 的属性值为 box(或 inline-box)。其基本用法如下:
css">display: box;
display: inline-box;
伸缩盒模型包括父容器和子容器。
父容器通过 display: box; 或者 display: inline-box; 启动伸缩盒布局功能;子容器通过 box-flex 属性定义布局宽度,以及定义如何对父容器的宽度进行分配。
父容器又通过如下属性定义包含容器的显示属性,各属性简单说明如下:
- box-orient:定义父容器里子容器的排列方式,是水平还是垂直;
- box-direction:定义父容器里的子容器排列顺序;
- box-align:定义子容器的垂直对齐方式;
- box-pack:定义子容器的水平对齐方式;
使用 box-ordinal-group 属性可以改变子元素的显示顺序,使用 box-flex 属性可以定义弹性宽度。如果 box-flex 的属性值为1,则元素会变得富有弹性,其大小将按如下方式计算:
- 声明的大小(width、height、min-width、min-height、max-width、max-height);
- 父容器的大小和所有余下的可利用的内部空间;
注意:使用旧版本伸缩盒模型,需要用到各浏览器的私有属性,Webkit引擎支持-webkit-前缀的私有属性,Mozilla Gecko引擎支持-moz-前缀的私有属性,Presto引擎(包括Opera浏览器等)支持标准属性,IE暂不支持旧版本伸缩盒模型;
-webkit- | chrome和safari |
---|---|
-moz- | Firefox |
-ms- | IE |
-o- | opera |
运行实例
本例设计左侧边栏的宽度为240px,右侧边栏的宽度为200px,中间内容板块的宽度将由 box-flex 属性确定。当调整窗口宽度时,中间列的宽度会自适应显示,使整个页面总是满窗口显示。
第一步,新建HTML5文档,设计栏目结构。
<div id="container">
<div id="left-sidebar"></div>
<div id="contents"></div>
<div id="right-sidebar"></div>
</div>
第二步,在样式表中设计样式组。
css">#container {
display: box; /*启动弹性盒布局*/
}
#contents {
flex: 1; /*定义中间列宽度为自适应*/
}
#left-sidebar,
#contents,
#right-sidebar {
box-sizing: border-box; /*定义盒样式*/
}
完整代码:
<div id="container">
<div id="left-sidebar">
<h2>宋词精选</h2>
<ul>
<li><a href="">卜算子·咏梅</a></li>
<li><a href=""> 声声慢·寻寻觅觅</a></li>
<li><a href=""> 雨霖铃·寒蝉凄切</a></li>
<li><a href="">卜算子·咏梅</a></li>
<li><a href="">更多</a></li>
</ul>
</div>
<div id="contents">
<h1>水调歌头·明月几时有</h1>
<h2>苏轼</h2>
<p>丙辰中秋,欢饮达旦,大醉,作此篇,兼怀子由。</p>
<p>明月几时有?把酒问青天。不知天上宫阙,今夕是何年。我欲乘风归去,又恐琼楼玉宇,高处不胜寒。起舞弄清影,何似在人间?</p>
<p>转朱阁,低绮户,照无眠。不应有恨,何事长向别时圆?人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟。</p>
</div>
<div id="right-sidebar">
<h2>词人列表</h2>
<ul>
<li><a href="">陆游</a></li>
<li><a href="">李清照</a></li>
<li><a href="">苏轼</a></li>
<li><a href="">柳永</a></li>
</ul>
</div>
</div>
css">#container {
/*定义弹性盒布局样式*/
display: -moz-box;
display: -webkit-box;
display: box;
}
#left-sidebar {
width: 240px;
padding: 20px;
background-color: orange;
}
#contents {
/*定义中间列宽度为自适应显示*/
-moz-box-flex: 1;
-webkit-box-flex: 1;
flex: 1;
padding: 20px;
background-color: yellow;
}
#right-sidebar {
width: 200px;
padding: 20px;
background-color: limegreen;
}
#left-sidebar, #contents, #right-sidebar {
/*定义盒样式*/
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
演示效果:
新版模型
知识点
通过设置 display 属性为 flex 或 inline-flex 可以启动新版伸缩模型。基本用法如下:
css">display: flex | inline-flex;
其中,flex 定义容器为块级元素;inline-flex 定义容器为行内元素。
提示:CSS3 的 columns 属性在伸缩容器上没有效果,同时 float、clear 和 vertical-align 属性在伸缩项目上也没有效果。
伸缩容器包含的属性如下:
- flex-direction: row (默认) | row-reverse | column | column-reverse;
[ 定义主轴方向,取值包括 row(横向从左到右排列)、row-reverse(与 row相反)、column(纵向从上往下排列)、column-reverse(与 column 相反);] - flex-wrap: nowrap (默认) | wrap | wrap-reverse;
[ 定义伸缩容器是不换行 | 换行且第一行在上方 | 换行且第一行在下方显示伸缩项目;] - flex-flow: < flex-direction> < flex-wrap>;
[ flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap;] - justify-content: flex-start (默认) | flex-end | center | space-between | space-around;
[ 定义伸缩项目沿着主轴线的对齐方式:左对齐 | 右对齐 | 居中 | 两端对齐且项目之间的间隔都相等 | 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。] - align-items: flex-start | flex-end | center | baseline | stretch (默认);
[ 定义伸缩项目在侧轴(交叉轴)上的对齐方式:交叉轴的起点对齐 | 交叉轴的终点对齐 | 交叉轴的中点对齐 | 项目的第一行文字的基线对齐 | 如果项目未设置高度或设为auto,将占满整个容器的高度 ] - align-content: flex-start | flex-end | center | space-between | space-around | stretch (默认);
[ 定义伸缩行在伸缩容器里的对齐方式(如果项目只有一根轴线,该属性不起作用):与交叉轴的起点对齐 | 与交叉轴的终点对齐 | 与交叉轴的中点对齐 | 与交叉轴两端对齐,轴线之间的间隔平均分布 | 每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍 | 轴线占满整个交叉轴]
伸缩项目包含的属性如下:
- order:控制伸缩项目在伸缩容器中的显示顺序,数值越小,排列越靠前,默认为0;
- flex-grow:定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大;(如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。)
- flex-shrink:定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小;(如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。 负值对该属性无效。)
- flex-basis:定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小;(它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间)
- flex:是 flex-grow、flex-shrink 和 flex-basis 3个属性的复合属性;(默认值为0 1 auto,后两个属性可选;该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto),建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值)
- align-self: auto | flex-start | flex-end | center | baseline | stretch;
[ 允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch;]
基本概念
采用Flex布局的元素,称为Flex容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为Flex项目(flex item),简称”项目”。
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。
运行实例
本例以旧版模型的示例结构为基础,使用新版语法设计一个兼容不同设备和浏览器的弹性页面。
第一步,复制示例的文档结构。整个页面被包裹在<div class=“page-wrap” 容器中,容器包含3个子模块。现在将容器定义为伸缩容器,此时每个子模块自动变成了伸缩项目。
<div class="page-wrap">
<section class="main-content"></section>
<nav class="main-nav"></nav>
<aside class="main-sidebar"></aside>
</div>
本示例设计各列在一个伸缩容器中显示上下文,只有这样这些元素才能直接成为伸缩项目,它们之前是什么没有关系,只要现在是伸缩项目即可。
第二步,启动伸缩布局模型。本示例把 Flexbox 旧的语法、中间混合语法和最新的语法混在一起使用,它们的顺序很重要。display 属性本身并不添加任何浏览器前缀,但用户需要确保老语法不要覆盖新语法,让浏览器同时支持。
css">.page-wrap {
display: -webkit-box; /*2009版 - iOS 6-, Safari 3.1-6*/
display: -moz-box; /*2009版 - Firefox 10- (存在缺陷)*/
display: -ms-box; /*2011版 - IE10*/
display: -webkit-flex; /*最新版 - Chrome*/
display: flex; /*最新版 - Opera 12.1, Firefox 20+*/
}
第三步,设计每个伸缩项目。整个页面包含3列,设计一个20%、60%、20%的网格布局。首先,设置主内容区域宽度为60%;其次,设置侧边栏来填补剩余的空间。这里同样把新、旧语法混在一起使用。
css">.main-content{
-webkit-box-ordinal-group: 2; /* 2009版 - iOS 6-, Safari 3.1-6 */
-moz-box-ordinal-group: 2; /* 2009版 - Firefox 19- */
-ms-flex-order: 2; /* 2011版 - IE 10 */
-webkit-order: 2; /* 最新版 - Chrome */
order: 2; /* 最新版 - Opera 12.1, Firefox 20+ */
width: 60%; /* 不会自动伸缩,其他列将占据空间 */
-moz-box-flex: 1; /* 如果没有该声明,主内容(60%)会伸展到和最宽的段落,就像是段落设置了white-space:nowrap */
background: white;
}
在新语法中,没有必要给边栏设置宽度,因为它们同样会使用20%的比例填充剩余的40%的空间,但是,如果不显式设置宽度,在旧语法环境中会直接崩溃。
第四步,完成初步布局后,需要重新排列顺序。这里把主内容排列在中间,但在HTML结构之中,它是排列在第一的位置。使用 Flexbox 可以很容易实现,但用户需要把 Flexbox 中几个不同的语法混在一起使用。
css">.main-content {
-webkit-box-ordinal-group: 2;
-moz-box-ordinal-group: 2;
-ms-flex-order: 2;
-webkit-order: 2;
order: 2;
}
.main-nav {
-webkit-box-ordinal-group: 1;
-moz-box-ordinal-group: 1;
-ms-flex-order: 1;
-webkit-order: 1;
order: 1;
}
.main-sidebar {
-webkit-box-ordinal-group: 3;
-moz-box-ordinal-group: 3;
-ms-flex-order: 3;
-webkit-order: 3;
order: 3;
}
完整代码:
<div class="page-wrap">
<section class="main-content">
<h1>水调歌头·明月几时有</h1>
<h2>苏轼</h2>
<p>丙辰中秋,欢饮达旦,大醉,作此篇,兼怀子由。</p>
<p>明月几时有?把酒问青天。不知天上宫阙,今夕是何年。我欲乘风归去,又恐琼楼玉宇,高处不胜寒。起舞弄清影,何似在人间?</p>
<p>转朱阁,低绮户,照无眠。不应有恨,何事长向别时圆?人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟。</p>
</section>
<nav class="main-nav">
<h2>宋词精选</h2>
<ul>
<li><a href="">卜算子·咏梅</a></li>
<li><a href=""> 声声慢·寻寻觅觅</a></li>
<li><a href=""> 雨霖铃·寒蝉凄切</a></li>
<li><a href="">卜算子·咏梅</a></li>
<li><a href="">更多</a></li>
</ul>
</nav>
<aside class="main-sidebar">
<h2>词人列表</h2>
<ul>
<li><a href="">陆游</a></li>
<li><a href="">李清照</a></li>
<li><a href="">苏轼</a></li>
<li><a href="">柳永</a></li>
</ul>
</aside>
</div>
css">.page-wrap {
display: -webkit-box; /* 2009版 - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* 2009版 - Firefox 19- (存在缺陷) */
display: -ms-flexbox; /* 2011版 - IE 10 */
display: -webkit-flex; /* 最新版 - Chrome */
display: flex; /* 最新版 - Opera 12.1, Firefox 20+ */
}
.main-content {
-webkit-box-ordinal-group: 2; /* 2009版 - iOS 6-, Safari 3.1-6 */
-moz-box-ordinal-group: 2; /* 2009版 - Firefox 19- */
-ms-flex-order: 2; /* 2011版 - IE 10 */
-webkit-order: 2; /* 最新版 - Chrome */
order: 2; /* 最新版 - Opera 12.1, Firefox 20+ */
width: 60%; /* 不会自动伸缩,其他列将占据空间 */
-moz-box-flex: 1; /* 如果没有该声明,主内容(60%)会伸展到和最宽的段落,就像是段落设置了white-space:nowrap */
background: white;
}
.main-nav {
-webkit-box-ordinal-group: 1; /* 2009版 - iOS 6-, Safari 3.1-6 */
-moz-box-ordinal-group: 1; /* 2009版 - Firefox 19- */
-ms-flex-order: 1; /* 2011版 - IE 10 */
-webkit-order: 1; /* 最新版 - Chrome */
order: 1; /* 最新版 - Opera 12.1, Firefox 20+ */
-webkit-box-flex: 1; /* 2009版 - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1; /* 2009版 - Firefox 19- */
width: 20%; /* 2009版语法, 否则将崩溃 */
-webkit-flex: 1; /* Chrome */
-ms-flex: 1; /* IE 10 */
flex: 1; /* 最新版 - Opera 12.1, Firefox 20+ */
background: #ccc;
}
.main-sidebar {
-webkit-box-ordinal-group: 3; /* 2009版 - iOS 6-, Safari 3.1-6 */
-moz-box-ordinal-group: 3; /* 2009版 - Firefox 19- */
-ms-flex-order: 3; /* 2011版 - IE 10 */
-webkit-order: 3; /* 最新版 - Chrome */
order: 3; /* 最新版, Spec - Opera 12.1, Firefox 20+ */
-webkit-box-flex: 1; /* 2009版 - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1; /* Firefox 19- */
width: 20%; /* 2009版,否则将崩溃 */
-ms-flex: 1; /* 2011版 - IE 10 */
-webkit-flex: 1; /* 最新版 - Chrome */
flex: 1; /* 最新版 - Opera 12.1, Firefox 20+ */
background: #ccc;
}
.main-content, .main-sidebar, .main-nav { padding: 1em; }
body {
padding: 2em;
background: #79a693;
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h1, h2 {
font: bold 2em Sans-Serif;
margin: 0 0 1em 0;
}
h2 { font-size: 1.5em; }
p { margin: 0 0 1em 0; }
演示效果: