Flex布局
在介绍Flex布局之前,先简述一下display属性。因为涉及到了 display: flex。
display
属性是使用关键字值指定的。关键字值分为六个值类别:
.container {
display: [ <display-outside> || <display-inside> ] | <display-listitem> | <display- internal> | <display-box> | <display-legacy> ;
}
-
display-outside:这些关键字指定元素的外部显示类型,本质上是元素在流布局中的作用。
-
block:该元素生成一个块元素框,在正常流动中时在元素之前和之后都产生换行符。
-
inline:元素会生成一个或多个内联元素框,这些框不会在自身之前或之后产生换行符。在正常流动中,如果有空间,则下一个元素将在同一行上。
-
run-in:元素生成一个插入框。如果定义为
display: run-in
box 的元素的相邻同级 是一个block box,则该run-in
box成为其后的block box的第一个内联框。
-
-
display-inside:这些关键字指定元素的内部显示类型。
-
flow、flow-root、table、
flex
、grid、ruby
-
因此display属性值不仅有 block、inline、inline-block,还有flex。
Flex 布局
布局的传统解决方案,基于盒状模型,依赖 display
属性 + position
属性 + float
属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。2009年,W3C 提出了一种新的方案----Flex 布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。详细介绍参考阮一峰老师的教程。 http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
1. Flex布局是什么
Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。
两个重要的概念:
(1)开启 flex 布局的元素叫做 flex container(容器)
(2)flex container 里面的直接子元素叫做 flex items(项目)
设置 display 属性为 flex 或者 inline-flex 都可以成为 flex container:
(1)flex:flex container 以 block-level 形式存在
(2)inline-flex:flex container 以 inline-level 形式存在
// html: <div class="box"> <div></div> <div></div> <div></div> </div> <strong>strong是行内元素</strong> // css: <style> .box { width: 300px; height: 300px; background-color: pink; /* display: flex; */ display: inline-flex } </style>
Webkit 内核的浏览器,必须加上-webkit
前缀。
.box{
display: -webkit-flex; /* Safari */
display: flex;
}
2. 基本概念
采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)
主轴的开始位置(与边框的交叉点)叫做 main start
,结束位置叫做 main end
交叉轴的开始位置叫做 cross start
,结束位置叫做 cross end
项目默认沿主轴排列。单个项目占据的主轴空间叫做 main size
,占据的交叉轴空间叫做 cross size
。
3. 容器的属性
所有的flex布局必须把父元素的display设置成flex,才能够使用flex布局。
以下6个属性设置在容器上。
-
flex-direction
-
该属性决定主轴的方向(即项目的排列方向)。有如下属性值:
-
row
(默认值):主轴为水平方向,起点在左端。 -
row-reverse
:主轴为水平方向,起点在右端。 -
column
:主轴为垂直方向,起点在上沿。 -
column-reverse
:主轴为垂直方向,起点在下沿。
-
-
flex-wrap
-
默认情况下,项目都排在一条线("轴线")上。
flex-wrap
属性定义,如果一条轴线排不下,如何换行。
-
nowrap
(默认):不换行。 -
wrap
:换行,第一行在上方。 -
wrap-reverse
:换行,第一行在下方。
-
-
flex-flow
-
该属性是
flex-direction
属性和flex-wrap
属性的简写形式,默认值为row nowrap
。
-
-
justify-content
-
定义了项目在主轴上的对齐方式。有如下属性值:
-
flex-start
(默认值):左对齐
-
flex-end
:右对齐
-
center
: 居中
-
space-between
:两端对齐(对准边线),项目之间的间隔都相等。
-
space-around
:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。 space-evenly
:均匀排列每个元素,每个元素之间的间隔相等。
-
-
align-items
-
定义项目在交叉轴上如何对齐。有如下属性值:
stretch
(默认值):如果项目未设置高度或设为auto,则项目将占满整个容器的高度。-
flex-start
:交叉轴的起点对齐。 -
flex-end
:交叉轴的终点对齐。 -
center
:交叉轴的中点对齐。 -
baseline
: 项目的第一行文字的基线对齐。
-
align-content
-
定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
-
flex-start
:与交叉轴的起点对齐。 -
flex-end
:与交叉轴的终点对齐。 -
center
:与交叉轴的中点对齐。 -
space-between
:与交叉轴两端对齐,轴线之间的间隔平均分布。 -
space-around
:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。 -
stretch
(默认值):轴线占满整个交叉轴。
-
4. 项目的属性
以下6个属性设置在项目上。
-
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
的简写,默认值为0 1 auto
。后两个属性可选。建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。 -
该属性有两个快捷值:
auto
(1 1 auto
) 和 none (0 0 auto
)。
-
-
align-self
-
允许单个项目有与其他项目不一样的对齐方式,可覆盖
align-items
属性。默认值为auto
,表示继承父元素的align-items
属性,如果没有父元素,则等同于stretch
。 -
align-self: auto | flex-start | flex-end | center | baseline | stretch;
-
该属性可能取6个值,除了auto,其他都与align-items属性完全一致。
-
5. 骰子的布局(详细介绍参考上述提供网站)
6. 网格的布局
(1) 基本网格布局
最简单的网格布局,就是平均分布。在容器里面平均分配空间,跟骰子布局很像,但是需要设置项目的自动缩放。
关于 flex: 1 的相关说明:(参考https://www.cnblogs.com/zhus/p/7161702.html)
flex
是 flex-grow
、flex-shrink
、flex-basis
的缩写。故其取值可以考虑以下情况:
-
flex
的默认值是 0 1 auto。由于这里flex-grow是0,所以即使存在剩余空间,也不放大。
<div class="parent">
<div class="item-1"></div>
<div class="item-2"></div>
<div class="item-3"></div>
</div>
<style type="text/css">
.parent {
display: flex;
width: 600px;
}
.parent > div {
height: 100px;
}
.item-1 {
width: 140px;
flex: 2 1 0%;
background: blue;
}
.item-2 {
width: 100px;
flex: 2 1 auto;
background: darkblue;
}
.item-3 {
flex: 1 1 200px;
background: lightblue;
}
</style>
-
主轴上父容器总尺寸为 600px
-
子元素的总基准值是:0% + auto + 200px = 300px,其中
- 0% 即 0 宽度
- auto 对应取主尺寸即 100px -
故剩余空间为 600px - 300px = 300px
-
伸缩放大系数之和为: 2 + 2 + 1 = 5
-
剩余空间分配如下:
- item-1 和 item-2 各分配 2/5,各得 120px
- item-3 分配 1/5,得 60px -
各项目最终宽度为:
- item-1 = 0% + 120px = 120px
- item-2 = auto + 120px = 220px
- item-3 = 200px + 60px = 260px -
当 item-1 基准值取 0% 的时候,是把该项目视为零尺寸的,故即便声明其尺寸为 140px,也并没有什么用,形同虚设
-
而 item-2 基准值取
auto
的时候,根据规则基准值使用值是主尺寸值即100px, 故这100px不会纳入剩余空间
(2) 百分比布局
<style> .Grid { display: flex; background-color: pink;
width: 800px;
} .Grid-cell { flex: 1; } .Grid-cell:nth-child(1) { flex: 0 0 50%; } .Grid-cell:nth-child(2) { flex: 0 0 30%; background-color: purple; } .Grid-cell:nth-child(3) { flex: 0 0 10%; background-color: blue; } </style> </head> <body> <div class="Grid"> <div class="Grid-cell">盒子1</div> <div class="Grid-cell">盒子2</div> <div class="Grid-cell">盒子3</div> </div> </body>
这里主要讨论以下 flex-basis
的取值情况:
-
auto
:首先检索该子元素的主尺寸,如果主尺寸不为auto
,则使用值采取主尺寸之值;如果也是auto
,则使用值为content
。 -
content
:指根据该子元素的内容自动布局。有的用户代理没有实现取content
值,等效的替代方案是flex-basis
和主尺寸都取auto
。 -
百分比:根据其包含块(即伸缩父容器)的主尺寸计算。如果包含块的主尺寸未定义(即父容器的主尺寸取决于子元素),则计算结果和设为
auto
一样。
(3)圣杯布局
<style> .HolyGrail { display: flex; /* min-height: 100vh; */ flex-direction: column; width: 500px; height: 500px; background-color: pink; } header, footer { flex: 1; background-color: purple; } .HolyGrail-body { display: flex; flex: 2; } .HolyGrail-content { flex: 1; background-color: blue; } .HolyGrail-nav, .HolyGrail-ads { /* 两个边栏的宽度设为 30% 空余部分会由 HolyGrail-content补齐*/ flex: 0 0 30%; } .HolyGrail-nav { /* 导航放到最左边 */ order: -1; } </style> <body> <div class="HolyGrail"> <header>header</header> <div class="HolyGrail-body"> <nav class="HolyGrail-nav">left</nav> <main class="HolyGrail-content">center</main> <aside class="HolyGrail-ads">right</aside> </div> <footer>footer</footer> </div> </body>
(4)输入框的布局
我们常常需要在输入框的前方添加提示,后方添加按钮。如下图效果:
<style> .InputAddOn { display: flex; } .InputAddOn-field { flex: 1; } </style> <body> <div class="InputAddOn"> <span class="InputAddOn-item">...</span> <input class="InputAddOn-field"> <button class="InputAddOn-item">...</button> </div> </body>
(5)悬挂式布局
有时,主栏的左侧或右侧,需要添加一个图片栏。如下图效果:
HTML代码如下: <div class="Media"> <img class="Media-figure" src="" alt=""> <p class="Media-body">...</p> </div>
CSS代码如下:
.Media {
display: flex;
align-items: flex-start; /* 定义代码在交叉轴的起点对齐 */
}
.Media-figure {
margin-right: 1em;
}
.Media-body {
flex: 1;
}
(6)固定的底栏
有时,页面内容太少,无法占满一屏的高度,底栏就会抬高到页面的中间。这时可以采用Flex布局,让底栏总是出现在页面的底部。
HTML代码如下: <body class="Site"> <header>...</header> <main class="Site-content">...</main> <footer>...</footer> </body> CSS代码如下: .Site { display: flex; min-height: 100vh; flex-direction: column; } .Site-content { flex: 1; /* 由于flex-grow默认为0,将中间部分设置为1,若存在剩余空间会放大 */ }
(7)流式布局
每行的项目数固定,会自动分行。
CSS的写法如下:
.parent {
width: 200px;
height: 150px;
background-color: black;
display: flex;
flex-flow: row wrap;
align-content: flex-start;
}
.child {
box-sizing: border-box;
background-color: white;
flex: 0 0 25%;
height: 50px;
border: 1px solid red;
}