用flexbox

简介

Flexbox是一种CSS3中新的布局模式以解决现代web应用中日趋负责的需求。这篇问题希望给你一个全面的了解Flexbox。

为什么要用Flexbox?

Flexbox给了我们一个过去没有的控制布局的方式,以往是hack我们的float,clearfixed,解决inline-block中空白,添加display:table,甚至使用position:absalute拉伸content。而这些是如此的复杂,为什么不以一种更简单的方式来处理这些呢,恩,是时候了,flexbox就是致力于改变这些,是事情变得简单。
flexbox的强大之一就是计算空间的能力,在遇到不知道需要处置多少项目时这将变成一个利器。

特殊点和浏览器支持

flexbox规范已经经历了三年的发展。不同的浏览器有者不同的实现方式。12年9月三大主要的版本齐聚W3C确定一致的方案,这意味这浏览器实现的统一。
Flexbox规范时间线:
July 2009 Working Draft (display: box;) March 2011 Working Draft (display: flexbox;)
November 2011 Working Draft (display: flexbox;) March 2012 Working Draft (display: flexbox;)
June 2012 Working Draft (display: flex;) September 2012 Candidate Recommendation (display: flex;)

概念和术语

Flexbox包括Flex容器和Flex items。Flex容器使用display属性声明一个元素是flex或者inline-flex,使用flex的容器被渲染成block,使用inline-flex的渲染成inline的。如下是实例:

1
2
3
4
.flex-container {
display: -webkit-flex;
display: flex;
}

盒子模型

不像block和inline布局,他们的布局计算是基于块和文本流(block and inline flow direction),flex布局是基于flex directions,为了便于讨论flex布局,这里定义了一系列的flex flow相关的术语。’flex-flow’的值决定了如何将这些术语映射到物理方位(顶/右/底/左),轴(纵向/横向),大小(宽/高)。
sss
main axis
main 维度
main 轴是flex容器的主轴,flex items沿着他分布,并延伸。
main-start
main-end
cross axis
cross 维度
cross start
cross end

Flex容器的属性

flex-direction

flex-direction用来更改flex容器的轴。默认值是row,该值下,flex元素以writing-mode方式排列,从左到右,从上到下。
row-reverse: The Main Start 和 Main End 对换.如果 writing-mode 是从左到右, Flex Items 将从右到左排列。 column: The Main Axis 和 the Cross Axis 对换。
*column-reverse:同

justify-content

justify-content调整flex元素在main轴上的位置, 可能取值:
flex-start (default) flex-end
center space-between
*space-around
sss

align-items

align-items是相对justify-content的,调整flex元素在cross轴上的位置,可能的取值:
flex-start (default) flex-end
center baseline
*stretch
sss

align-content

align-content是修饰flex-wrap的行为的。他类似与align-item,但是不是调整Flex Item,而是调整Flex Lines的。可能的取值:
stretch (default) flex-start
flex-end center
space-between space-around

flex-flow

flex-flow是flex-direction和flex-wrap的缩写
flex-flow:[flex-direction][flex-wrap]

Flex Items的属性

Flex Item是任何Flex容器的直接子元素,Flex容器的文本也被认为是一个Flex Item

order

order用来设置Flex Items在渲染时的排列顺序。

align-self

align-self将覆盖Flex容器的align-items对单个Flex Item的影响。可能的取值:
stretch (default) flex-start
flex-end center
*baseline

flex

flex指定了各个Flex Item占用空余空间的优先级。
恩,对的,这里对于flex属性需要在详细说说,我们在查看使用flexbox布局时,常常可以看到这样子的
Flex:1 0 auto。他是三个flexbox属性的缩写,他们依次是:flex-grow,flex-shrink和flex-basis

Flex-basis和Flex-grow

Flex-basis决定了其他两个属性如何起作用,将是伸长还是缩短。他是Flex item的初始尺寸。

关于伸长

  • 2 / 0 / 100px
  • 0 / 0 / 150px
  • 2 / 0 / 50px


在上例可以看到,中间的元素没有允许伸长和缩短所以保持150px,剩余的450px的空间由其他的flexitem填充,他们同时有相同的值2,所以各分配225px。那么他是如何计算的呢?

计算空间

究竟有多少的空间分配给各个的flex item,他们的计算公式如下:

1
2
Availabel space =(container size - flex-basis siblings total)
可用空间=容器的空间大小 - 所有flex-basis的和

可用空间将用来分配为用于伸长的量。带入公式,上例中容器大小是600px,所有的单个元素的和是300px,
于是有:容器大小(600px)- 所有的元素和(300px)。

1
2
Grow unit = (Availabel space / Sum Grow siblings total).
伸长单位 = 可用空间/所有同级元素的增长和

我们的增长数字就是所有同级元素相加的结果(2 + 0 + 2 = 4).可用空间300/4 = 75。一个伸长单位是75px大小。

1
Flex item size = (Flex basis +_(Grow Unit * num))

于是最后的计算结果是item1(flex:2 0 100px)等于100px + (75 2)结果是250px,item2(flex:0 0 150px)等于150px,item3(flex:2 0 50px)等于50px + (75 2)结果是200px。我们可以将公式简化一点:

1
2
Availabel space = (Contianer size - Flex-basis siblings total).
Flex Item size = Basis + ((Availabel space / Total Grow nums) * Individual grow num).

一个四舍五入的bug

我注意到在firefox32中会以一种奇怪的方式四舍五入数字,firefox会将我的flex计算为1px而不是他应该的大小.

关于收缩

关于浮动的一些事情

关于浮动的一些事情

浮动元素

浮动元素会脱离文档的正常流,一个元素浮动时,其他的内容会“环绕”该元素。 浮动元素周围的外边距不会合并,即其他元素和浮动元素彼此相邻,而且这些元素也有外边距,那么这些外边距不会和浮动元素的外边距合并。

水平居中又一方法

对应内容水平居中,有这好多方法,这里我们介绍另外一种奇妙的方法。

先看需要居中的HTML文档

1
2
3
4
5
6
7
8
<div class="centeredmenu">
<ul>
<li><a href="#">Tab one</a></li>
<li><a href="#">Tab two</a></li>
<li><a href="#">Tab three</a></li>
<li><a href="#">Tab four</a></li>
</ul>
</div>

内容居中的CSS代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#centeredmenu{
float:left;
width:100%;
background:#fff;
border-bottom:4px solid #000;
overflow:hidden;
position:relation;
}
#centeredmenu ul {
clear:left;
float:left;
list-style:none;
margin:0;
padding:0;
position:relation;
left:50%;
text-align:center;
}
#centeredmenu ul li {
display:block;
float:left;
list-style:none;
margin:0;
padding:0;
position:relation;
right:50%;
}
#centeredmenu ul li a {
display:block;
margin:0 0 0 1px;
padding:3px 10px;
background:#ddd;
color:#000;
text-decoration:none;
line-height:1.3em;
}
#centeredmenu ul li a:hover {
background:#369;
color:#fff;
}
#centeredmenu ul li a.active,
#centeredmenu ul li a.active:hover{
color:#fff;
background:#000;
font-weight:bold;
}

居中方法是如何工作的

此处居中方法的实现原理是浮动元素彼此相对定位,为了正确解释这里先让我们看下元素浮动时是如何改变自己的尺寸的

无浮动的DIV

sss
这是一个无浮动的DIV,可以看到它扩展到了整个父元素宽度,也就是整个页面.

左浮动的DIV

sss
现在该DIV左浮动,它会自动收缩到内部内容的宽度,也就是文字”DIV”的宽度.这里的收缩是居中过程的关键,他会帮助我们使菜单适当进入中间.

标准的左置菜单

我们现将菜单左浮动再一步步移动TABS至中间.这里将各个元素以不同的色框标示,从而容易区分他们的结构.
sss
注意一下的步骤。
将centeredmenu DIV左浮动但是给于100%的width,这样他就仍然可以扩展到整个页面。 将centeredmenu DIV中的ul元素左浮动。这样意味着ul会收缩到自己内容的宽度,同时所有TABS的宽度也会收缩。
ul中的所有li左浮动。这会造成他们围绕着自己内部的link标签收缩从而排列成水平的一行。 在tab中的每个link文本显示是;Tab1,Tab2,等等

移动无序列表的位置

sss
接下来我们使用position:relative将ul元素右移50%。当使用百分比的方式将元素移向一旁的时候特别需要注意他移动的是父元素的百分比宽度而不是自己的宽度。所以在这个例子中ul元素按centeredmenu DIV宽度的50%右移-即浏览器窗口的50%。结果是我们的菜单从屏幕的中间开始同时部分超出了右页面,不必担心,接下来我们会使他在中间。

移动行列的位置

ss
最后的步骤是将所有的li元素按50%重回左侧。这里是以ul元素宽度的50%同时会使所有的tabs精确的位于窗口的中间。

注意点

这个置中菜单的方法是固定滚动但是有一些事情需要注意
因为ul元素部分溢出浏览器窗口会横向滚动除非你使用了overflow:hidden规则到centeredmenu DIV上。这将会隐藏溢出的部分, ul元素和tabs没有对齐所以他不能使用任何的可见式样。ul元素不能使用背景颜色和边框这样它可以完全的不可见。将所有的tab式样只应用在li和a元素上。
*如果需要第一个和最后一个tab区别与其他的,添加类到第一个和最后一个li元素上使他们可以独立对位。

主要特征

没有CSS hacks

对XHTML 严格标签可用

可以重置文本大小

没有js

支持所有的浏览器

参考url:http://matthewjamestaylor.com/blog/beautiful-css-centered-menus-no-hacks-full-cross-browser-support#