Flex布局原理介绍

引言

CSS3中的 Flexible Box,或者叫flexbox,是用于排列元素的一种布局模式。

顾名思义,弹性布局中的元素是有伸展和收缩自身的能力的。 相比于原来的布局方式,如float、position,根据盒子模型,就可以计算出元素的展示尺寸(长宽非百分比),除非溢出,否则不依赖于父容器的大小。

而弹性布局中元素的大小是高度依赖父容器的大小的。因为,它所具有的“伸缩性”,目标就是为了撑满父元素。当然这是在任其“野蛮生长”的情况下,你也可以通过相关css属性控制其是否撑满、撑满什么轴。

弹性布局是一种全新的思维方式,让很多实现复杂的问题有了更好的理解方式(如垂直居中)。只需要给直接父容器设置为display: flex;,duang~ 子元素就默认具有了可收缩性
Flex的语法规范也曾经有很多版本:

  • 最新版本是display: flex;
  • 中间版本是display: flexbox;
  • 最老版本display: box;

本篇文章侧重于flex难理解的点,适合于已经了解过flex的api的童鞋观看。(api其实就下图这么多,橙色是常用的)


[](https://alisecued.github.io/2017/01/03/Flex%E5%B8%83%E5%B1%80%E5%8E%9F%E7%90%86%E4%BB%8B%E7%BB%8D/#

为何要引入主轴、交叉轴、轴线的概念)为何要引入主轴、交叉轴、轴线的概念

我们首先看一下,CSS布局的发展历程:


翻开flex的入门教程,首先映入眼帘且比较难懂的就是主轴和交叉轴(对,就是下面这张图),这是前几种布局方式都没有的。



前几种布局都可以按照人类书写的方式理解:“从左到右写,写不下就往下换行”。

但是flex特点是可以重新定义这种“书写方式”,你还可以从下到上写、从右到左写(见flex-direction属性),换行也可以从两个相反的方向换行(见flex-wrap属性)。所以引入了这个几个概念方便理解。

浏览器的布局方式是:
沿着主轴的方向依次排列,如果要换行,则沿着交叉轴的方向进行换行,每行代表一条轴线。但是,我们可以使用子元素的order属性对元素进行重新排序。由此可见,flex给子元素提供了很大的灵活性。

主轴、交叉轴可以帮助我们理解这些概念:

  • 重新定义浏览器“书写方式”。
    • flex-direction 改变主轴方向;
    • flex-wrap 改变交叉轴方向

如下图,主轴和交叉轴的排列组合有4*2 =8 种。


screenshot.png

比如,可以像写对联一样,从上到下竖着书写,从右到左换行。
(2017新年快乐~)


.container {
    flex-direction: column;
    flex-wrap: wrap-reverse;
}

为了方便表达,本篇文章都使用默认的轴方向。

  • 轴上的元素的排列方式(justify-content, align-items)。

    • justify-content 定义了元素在主轴轴上如何对齐;
    • align-items 定义了元素在交叉轴上如何对齐
    • flex-start: 对齐轴起点;
    • flex-end: 对齐轴终点;
    • center:在轴线上居中;
    • space-between:两端不带间距的轴线两端对齐;
    • space-around: 两端带间距的轴线两端对齐, 且每个子元素之间的间距相同(假设为x)。两端元素离父元素间距为(x/2)。 注意这个间距既不是margin也不是padding,盒子模型来计算展示方式已经不适用了。
    • baseline:交叉轴特有,基线对齐。
    • stretch:交叉轴特有,有占满整个主轴高度的意向。当设置了子元素高度为非auto时不生效。
  • 多根轴线时,轴线之间的排列方式(align-content)。align-content的参照轴是交叉轴。其属性也和上面的justify-content、align-items大同小异:flex-start、flex-end、center、space-between、space-around、stretch。不多做解释。

元素宽度如何伸缩

能决定元素展示宽度的属性有: flex-shrink,flex-grow,flex-basis,width,min-width

flex为前三个属性的缩写方式,所以常用写法是flex-shrink,flex-grow,flex-basis统一用flex设置。

常见的flex设置:

| 序号 | 样式 | flex-grow | flex-shrink | flex-basis |
|: -------------: |:------------:| :------------:|:-----------------:|:---------------:|
| ① |flex默认值| 0 | 1 | auto |
| ② | flex: 1 | 1 | 1 | 0% |
| ③ |flex: auto | 1 | 1 | auto |
| ④ |flex: none | 0 | 0 | auto |

那么,flex-grow和flex-shrink的值会对元素造成什么影响呢?

如下图所示,当元素允许缩小时,最终展示的效果会是正好撑满主轴。

在父容器中有三个元素A1,A2,A3,他们都有一个初始宽度(比如设置了width且flex-basis不为0%)。初始宽度在下一小节会详细讲。
如果按照初始宽度放入普通父容器中,那么他们会溢出x个像素(见初始尺寸行)。

当父元素display: flex;,
且A1flex-shrink:1,A2flex-shrink:1,A3flex-shrink:1时,

A1、A2、A3都具有可收缩的特性。

flex-shrink的值表示需要收缩的宽度占总溢出宽度的比例,因此展示尺寸这么算:

  1. 将x平均分为(1+1+2) = 4份,每份宽度为i = x/4

  2. A1的展示尺寸为:A1默认宽度 - i × 1;
    A2的展示尺寸为:A1默认宽度 - i × 1;
    A3的展示尺寸为:A1默认宽度 - i × 2;

同理,当元素不够撑满父元素时,需要伸展的宽度也是按照这种方式计算的。只是比例基数变成了剩余空间的宽度。
**如果你希望元素不能伸缩,那么需要设置相应的属性为0。
如: flex-shrink: 0

flex-basis和width的关系

flex-basis 用于计算上一小节中元素的“初始宽度”。

  • flex-basis为auto时, 初始宽度为元素内容大小或者设置的宽度值(盒子模型中的占用宽度)。
  • flex-basis为像素值时,初始宽度为flex-basis的值。
  • flex-basis为百分比时,初始宽度为占父容器的比例。
  • flex-basis为0或0%时,初始宽度为0。

虽然flex-basis的优先级大于width,但是最后计算的展示尺寸受限于min-width或者max-width

比如,元素A算出来的展示宽度为100px,但是它有个css属性min-width: 200px;
, 那么最后的展示宽度仍然为200px。但是计算的初始尺寸仍然是由flex-basis决定。

兼容性

caniuse上可以查到,通过加上各种前缀,flex可以兼容到ie10以及以上。
16年年初在实际使用过程中,发现UC的支持性很不好。这次又重新试了一次,新版的UC也能很好的支持flex了。看来flex正在慢慢占领移动端。

几个案例

通过上面几小节的描述,可以发现flex用了一种全新的思路来布局。列出几个常见的案例,以下案例的代码统一在我的codepen可查看。

1.垂直居中


.container {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

2.一侧固定,一侧自适应


.container {
    display: flex;
    .sidebar {
        width: 100px;
     }
    .content {
        flex: 1;
     }
}

3.多列等高


多列等高
.container {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-content: stretch;
}

总结
flex布局是围绕父元素和轴来进行布局的。这种全新的思路巧妙地只需要简单几行代码就可以实现曾经头疼的效果,其思路的建立过程非常值得借鉴。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • H5移动端知识点总结 阅读目录 移动开发基本知识点 calc基本用法 box-sizing的理解及使用 理解dis...
    Mx勇阅读 4,392评论 0 26
  • 移动开发基本知识点 一.使用rem作为单位 html { font-size: 100px; } @media(m...
    横冲直撞666阅读 3,452评论 0 6
  • 前言 温馨提示:本文较长,图片较多,本来是想写一篇 CSS 布局方式的,但是奈何 CSS 布局方式种类太多并且实现...
    sunshine小小倩阅读 3,116评论 0 59
  • 传统的网页布局基于盒装模型,使用display,position,float属性来达成各种布局。对于一些特殊的布局...
    exialym阅读 2,624评论 0 11
  • 前言 FlexBox是css3的一种新的布局方式,天生为解决布局问题而存在的它,比起传统的布局方式,我们使用Fle...
    zevei阅读 1,408评论 23 3