Flexbox 布局是 CSS 3 新增的布局模式,在 display 中的值是 display: flex; display: inline-flex;
。flex 具有很好的适应性,在电脑浏览器和手机浏览器中都有很好的表现。虽然其标准仍然是“候选(CR)”,但是在各个浏览器已经得到了很广泛的支持。如图1,从图中我们可以看出,flex模块已经得到了几乎所有浏览器的支持,IE11部分支持,我们可以在实际的项目中尝试使用,如果是IE Version<=11的话,要做一定的 polyfill。
what for?
flexbox,是’flexible box’ 的缩写,声明为display: flex/inline-box
的元素可以改变子元素的高度和/或宽度,来适应不同大小的浏览器尺寸和显示设备类型,是响应式布局的一种技术。利用块级元素布局基于垂直方向,行内元素基于水平方向,flexbox 则是水平和垂直方向都能很好的适应。关于 Flexbox ,我觉得记住一点就好,声明 display: flex;
或者 display: inline-flex;
的元素的子 flex 条目会充满父元素的所有空间。
没有 flexbox 时,使用 css 布局时,我们使用 float 、display 和 position,这些技术没有问题,但是实现不是很直观。但是利用这些技术,且对于一些特殊任务实现起来仍然有困难,比如 垂直居中元素。flex 实现这些布局是相当容易的事情,我们可以总结说,Flexbox 就是一种“弹性布局”模型,能很好支持不同视口尺寸和设备。
看完整篇文章后,你会觉得这个和 table 布局十分类似啊!下面说点具体的 【严肃脸】。
内容
说明: 主轴为 flex-direction 指定的方向,侧轴是与主轴方向垂直的轴,借用 MDN 上的一张图说明。main axis 即为主轴,主轴方向开始叫做‘main start’,结束叫做‘main end’;cross axis 为侧轴,开始为 cross start,结束为 cross end。在这里指出这些知识,是因为以下的 flex 的条目对其将会涉及到相应的概念。
容器可以设置的属性:
属性 | 值及其说明 |
---|---|
flex-direction | 条目放置的方向(主坐标轴),row(默认值),水平放置;column,垂直放置 |
flex-wrap | flex条目溢出父元素时是否应该换行,nowrap(默认值),不换行显示;wrap表示换行,按照父元素的尺寸来布局,如果溢出,那么溢出的将换行显示,最终结果为显示为多行,且无论哪一行,有几个子元素,都会自适应填充满每一行;wrap-reverse,与wrap相同,但是顺序相反 |
flex-flow | flex-direction和flex-wrap的简写,和margin、padding等简写四个方向类似 |
justify-content | 规定flex条目在主轴方向的排布规则。flex-start,条目左对齐,最左边的元素的margin边框将会失效;flex-end,条目右对齐,最右边的元素的margin边框将会失效;center,居中对齐;space-between,沿主轴方向均匀分布,开始和结束margins失效;space-around,沿主轴均匀分布,与space-between不同之处在于开始和结束的margins等于相邻两个flex条目间距的一半 |
align-item | 规定flex条目在侧轴(flex-direction规定的主轴垂直方向)方向的排布规则。flex-start,垂直上对齐;flex-end,垂直下对齐;center,垂直居中对齐;baseline,stretch(默认值),在侧轴方向拉伸flex条目,以期在侧轴方向填满整个容器 |
条目可以设置的属性:
属性 | 值及其说明 |
---|---|
flex-grow | 主轴方向flex条目所占比例,值为Number类型 |
flex-shrink | 主轴方向flex条目缩放比例,值为Number类型 |
flex-basis | 主轴方向flex条目最小尺寸,px或者% |
flex | 是 flex-grow、flex-shrink 和 flex-basis 属性的简写,确立弹性项目的伸缩性 |
order | flex条目在所有flex条目中的次序 |
align-self | 同父元素的align-item,定义了单个弹性项目在侧轴上应当如何对齐,这个定义将覆盖由 align-items 所确立的默认值 |
看完这些说明,我们来看看如何利用 Flexbox 实现我们常用的布局。
各种常见布局要求的 Flexbox 实现
水平方向多列自适应布局
要求:两列布局,左侧列宽度固定,右侧列自适应,填充整个容器。
- 传统做法:浮动定位或绝对定位左侧列,右侧列margin实现与左侧列隔离。
<section>
<article class="left">
<b>left width-fixed</b>
</article>
<article class="right">
<b>right auto-fill</b>
</article>
</section>
样式:
html, body{
height: 100%;
margin: 0;
padding: 0;
}
section, article{
height: 100%;
}
.left{
float: left;
width: 300px;
background-color: rgb(255, 0, 0);
}
.right{
margin-left: 300px;
background-color: rgb(0, 255, 0);
}
效果如下:
==========附带一提(但是很重要的点)============
外边距(margin)叠加问题,简单的说,就是当两个或更多的垂直外边距相遇时,它们将形成一个外边距,这两个外边距的高度等于两个发生叠加的外边距的高度中的较大者。比如,我在上面的例子中,每一个 article 内的标题都是使用 b 标签,如果我换成 h* 标签,那么就会出现这个问题。如图,我将b 标签换成了 h2,h2 是块级元素,有垂直外边距,在chorme 中,本例的 h2 默认外边距是 19.920 像素,外边距为0的父元素叠加外边距为 19.920 像素的子元素,将会出现 19.920 像素的垂直外边距:
需要注意,如果父元素是float 定位,那么该问题不会出现,所以你会看到左侧 article 中的 h2 元素外边距在 article 元素中。
- 使用 Flexbox 实现
同样是上面的 HTML 结构,样式如下。
html, body{
height: 100%;
margin: 0;
padding: 0;
}
section, article{
height: 100%;
}
section{
display: flex;
}
.left{
width: 300px;
background-color: rgb(2,138,201);
}
.right{
flex-grow: 1;
background-color: rgb(78,55,115);
}
效果如下图,这下好了,h* 的外边距都在里边了,没有出现外边距叠加了,可见,article元素已经不是普通的定位了。但是要注意,article 高度必须大于 h2 的盒模型总的高度,否则仍然会溢出。
垂直方向多行自适应布局
要求:三行布局,第一行和第三行高度固定,第二行自适应,填充整个容器。
- 传统做法,使用 table 布局。
<section>
<header>
<h2>header</h2>
</header>
<article class="content">
<h2>content</h2>
</article>
<footer>
<h2>footer</h2>
</footer>
</section>
样式:
html, body{
height: 100%;
margin: 0;
padding: 0;
}
section{
height: 100%;
width: 100%;
display: table;
}
.content{
display: table-row;
background-color: rgb(2,138,201);
}
header, footer{
display: table-row;
background-color: rgb(72,82,94);
}
header{
height: 90px;
}
footer{
height: 80px;
}
效果和使用 Flexbox 实现的效果完全一致,这里就不贴图了,可以看 Flexbox 的实现效果图。
- Flexbox 实现
html, body{
height: 100%;
margin: 0;
padding: 0;
}
section{
height: 100%;
display: flex;
flex-direction: column;
}
.content{
flex-grow: 1;
background-color: rgb(2,138,201);
}
header, footer{
background-color: rgb(72,82,94);
}
header{
height: 90px;
}
footer{
height: 80px;
}
看完效果是不是感觉很 nice 呢。以后遇到这种布局需求,就是用 Flexbox 吧!结合水平的和垂直的布局,可以做出一些复杂的单页应用布局。
水平居中且垂直居中
使用 Flexbox 做页面居中也很容易,
<section class="container">
<div class="spacer"></div>
<section class="horizontal">
<div class="spacer"></div>
<article class="content">
居中的内容
</article>
<div class="spacer"></div>
</section>
<div class="spacer"></div>
</section>
样式:
html, body{
height: 100%;
margin: 0;
padding: 0;
}
.container{
height: 100%;
display: flex;
flex-direction: column;
background-color: rgba(0, 0, 0, 0.8);
}
.spacer{
flex: 1;
}
.horizontal{
display: flex;
flex-direction: row;
}
.content{
height: 200px;
width: 400px;
background-color: rgb(255, 255, 255);
color: rgb(0, 0, 0);
border-radius: 4px;
padding: 10px;
}
HTML 中我们使用了四个名为spacer
类的垫片,这里主要利用了 flex 条目会占据所有可用空间的特性,让它们把主要的内容挤到中间的位置 ^_^。我给内同区域添加了圆角效果和内边距,最终效果如下图。看到没,就这么简单就做出了一个弹出层,再加上一点鼠标和键盘事件,这不就是一个我们常用的 bootstrap“模态框”么 【笑】。
有一个叫做绝对居中的技术,我从其他博客作者看到的,内容较多,这里我们不再介绍,找个机会我们和 Flexbox 实现做一个对比。
大屏和小屏之间的响应性
结合 flex-direction , flex-wrap,order 和 媒体查询,做出的布局会有比较好的跨设备的特性。下面举个例子,咱一起看看它们的威力。
<section>
<nav>
<button> 测试 </button>
<button> 测试 </button>
<button> 测试</button>
</nav>
<article>
主要内容
</article>
</section>
样式:
html, body{
height: 100%;
margin: 0;
padding: 0;
}
section{
height: 100%;
display: flex;
}
nav{
width: 200px;
display: flex;
background-color: rgb(2,138,201);
}
button{
height: 30px;
flex: 1;
}
article{
flex: 1;
background-color: rgb(72,82,94);
}
@media screen and (max-width: 640px) {
section{
flex-direction: column;
}
nav{
width: 100%;
flex: 1;
order: 2;
flex-direction: row;
}
article{
flex: 3;
}
}
@media screen and (max-width: 320px) {
nav{
flex-direction: column;
}
}
效果,例子中利用媒体查询,根据浏览器宽度分了三个阶段,当然 640,320都是胡诌的,真实情况下,并不是这个界限,合适的尺寸可以参考 Bootstrap 的分段阈值或者根据实际情况制定。多余的我就不说了,你肯定能看懂。
- >640px,判断为电脑浏览器;
- 640px > width >320px,判断为平板浏览器;
- <320px,判断为手机浏览器。
总结
只要理解了 Flexbox 的设计初衷,并了解其属性和值的含义及用处,那么在实际的需求面前就可以很从容的应用这项技术了。这也是我的学习新东西的思路,首先想为什么有这个东西,为解决什么问题的,有什么 API,然后和其它技术的对比,然后在具体问题面前灵活运用。