flexbox弹性盒子,真正意义上的布局样式

前段时间接手了一个基于cef1的项目,由于其特别限定的场景,在查询了对html5的支持后,整站都采用了flexbox布局,也从头熟悉了一遍该布局的使用方法。故分享出来,供参考。

背景

Flexbox Layout,俗称Flexible box模型,由W3C于2009年开始起草的css3布局样式。它旨在提供一种更加有效的布局方式,控制父容器中子元素的布局,排列以及分布,甚至在它们的尺寸未知或动态变化的情况下,都能够做到正确的展现(弹性盒子中的flex也由此而得名)。

弹性盒子的核心概念是父容器拥有能够改变其子元素的的宽度/高度和排列顺序,使得子元素能够以最佳的尺寸填充整个父容器的可用空间。简单来说,一个弹性盒子能够充分扩展它的子元素尺寸使其填满自身的可用空间,或者收缩子元素来防止溢出。

最重要的一点是,相对于传统的块布局block以及行布局inline来说,弹性盒子模型是方向不可知的(direction-agnostic)。尽管块布局以及行布局能够很好的满足页面布局,但是它们缺乏弹性,不能很好地支持大型或者是复杂的应用(特别在屏幕进行横竖屏切换,改变视图尺寸,延伸,收缩等等复杂情景下)。

注意:弹性盒子布局适合作用在一个应用的组件和小范围的布局,例如,一个歌曲列表,一个导航条,等等。相对的,Grid layout,即栅格布局则倾向于进行大规模的界面布局,例如,整体界面的分栏布局,左右结构,上下结构,等等。

基本原理

由于弹性盒子是一整套模型而不是单独的一个css属性,它包含了一个属性集合,其中的一些属性作用于父容器(flex container),另一些则作用于子元素(flex items),所以特别需要区分这些属性的作用对象

如果说常规布局是建立在块级和行级方向(block and inline flow directions)上的,那么弹性盒子布局则是建立弹性流方向(flex-flow directions)上的。

弹性盒子模型

如上图所示,假设主轴是横向的,那么子元素将会沿着主轴从左至右依次排列,或者是沿着与主轴垂直的交叉轴由上至下依次排列。下面我们一一进行剖析:

main axis(主轴)

父容器的主轴是子元素排列的基本轴,但这并不意味着基本轴必须是横向的,这取决于父容器的flex-direction属性(后边会介绍到)。例如,如果子元素是竖向排列的,那么主轴则是竖向的那条轴。

main-start | main-end

子元素会沿着main-start从左至右排列,直到main-end。值得注意的是,默认情况下,子元素只会排列在一排上,就算已经到达了父容器的右边缘,也不会进行换行,除非设置了flex-wrap属性(后边会介绍到)。

main size

在父容器中主轴上的子元素的主尺寸(不论宽度或者高度)之和,构成了弹性盒子的主尺寸。例如,如果子元素是横向排列的,则宽度则是主尺寸,相对的,如果子元素是竖向排列的,则高度则是主尺寸。

cross axis

垂直于主轴的轴,称之为交叉轴。显然,交叉轴的方向取决于主轴的方向。

cross-start | cross-end

当父容器中的子元素换行时,子元素的行排列的方向则是沿着交叉轴进行的,从cross-start开始,直到cross-end。

cross size

和main size同理,只是方向与之垂直。


下面进行弹性盒子属性详解,分为两类,分别是父容器属性和子元素属性。


父容器属性(flex-container)

父容器

display

用于定义弹性盒子的显示方式。

.flex-container {
  display: flex; // 实际相当于block-flex,块级容器,宽度同其外层容器
  display: inline-flex; // 顾名思义,行级容器,宽度取决于其子元素
}

flex-direction

用于定义主轴方向,同时也决定了子元素的排列方向。

flex-direction
.flex-container {
  flex-direction: row; // 子元素由左至右排列(默认值)
  flex-direction: row-reverse; // 子元素由右向左排列
  flex-direction: column; // 子元素由上至下排列
  flex-direction: column-reverse; // 子元素由下至上排列
}

flex-wrap

默认情况下,所有的子元素都会尝试沿着主轴在排列在同一行(列)上,这个属性用来对子元素进行换行排列,即当子元素排列到main-end的时候,会自动进行换行。

flex-wrap
.flex-container {
  flex-wrap: nowrap; // 子元素都在排列在同一行(默认值)
  flex-wrap: wrap; // 子元素将沿着交叉轴正向排列在多行中
  flex-wrap: wrap-reverse; // 子元素将沿着交叉轴反向排列在多行中
}

flex-flow

flex-direction和flex-wrap的属性缩写。

.flex-container {
  flex-flow: <'flex-direction'> || <'flex-wrap'>;
  flex-flow: row nowrap; // 横向排列 不换行(默认值)
}

justify-content

定义子元素在主轴上的对其方式。主要用在当所有的子元素在同一行,且为非弹性元素时,分配剩下的额外空间;或者是弹性元素但是并没有撑满整个父容器的主尺寸。该属性也能够对溢出的子元素起到一定的控制作用,例如,当子元素溢出时,对其进行居中,则左右溢出的宽度将是相等的。

justify-content
.flex-container {
  justify-content: flex-start; // 子元素向主轴起点看齐排列(默认值)
  justify-content: flex-end; // 子元素向主轴终点看齐排列
  justify-content: center; // 子元素居中排列
  justify-content: space-between; // 子元素以相同的间距从主轴的起点和终点开始平均排列
  justify-content: space-around; // 子元素以相同的边距延主轴平均排列
}

小贴士:justify-centent: center;还可以配合align-self: center;进行内容的居中垂直布局

align-items

用于定义排列在同一主轴的子元素在交叉轴方向上的排列方式(可以想象成是justify-content属性的交叉轴版)。

align-items
.flex-container {
  align-items: flex-start; // 子元素向交叉轴起点看齐排列
  align-items: flex-end; // 子元素向交叉轴终点看齐排列
  align-items: flex-center; // 子元素在交叉轴居中排列
  align-items: flex-stretch; // 子元素沿交叉轴拉伸排列(撑满整个交叉轴的长度)(默认值)
  align-items: flex-baseline; // 子元素在交叉轴上沿其文本的基线对其排列
}

align-content

用于定义父容器中的多行/列在交叉轴上的排列方式(有点类似于多个子元素在主轴上的justify-content排列)。

align-content
.flex-container {
  align-content: flex-start; // 多排子元素从交叉轴起点进行排列
  align-content: flex-end; // 多排子元素从交叉轴终点进行排列
  align-content: center; // 多排子元素在交叉轴居中排列
  align-content: stretch; // 多排子元素沿交叉轴拉伸排列(撑满整个交叉轴的长度)(默认值)
  align-content: space-between; // 多排子元素以相同的间距从交叉轴的起点和终点开始平均排列
  align-around: // 多排子元素以相同的边距延交叉轴平均排列
}

小贴士:当只有一排子元素时,align-content属性并没有什么卵用。


子元素属性(flex-items)

子元素

order

默认情况下,子元素按照它们在源码中出现的位置进行排列。幸运的是,通过order属性,则能够控制子元素在父容器中的排列顺序,这大大增加了布局的灵活性。

order

上图中的数字,代表了元素的顺序值(整型,且接受负值),且order: 0;无order属性等效。

.flex-item: {
  order: <integer>;
  order: -1|1|2...n;
}

flex-grow

用于定义子元素能否伸展的能力。它接受一个数字来作为比例值,这使得子元素能够自动检测父容器中的可用空间,并将其进行填充。

如果所有的子元素都有flex-grow: 1,那么所有子元素都将均分主轴的长度;如果其中有一个子元素有flex-grow: 2,那么这个子元素将占据其他flex-grow: 1的子元素占据主轴长度的两倍(至少会尽量这样做)。

flex-grow
.flex-item {
  flex-grow: <number>; // 非负自然数(包括0)
  flex-grow: 0; // 默认值
  flex-grow: 1|2...n;
}

小贴士1:如果子元素的内容超过了其flex-grow所分配的空间,则会继续伸展,直到满足子元素内容的长度。
小贴士2:如果父容器设置了flex-wrap: wrap;,那么挤到第二排的子元素将按照第二排的主轴长度进行flex-grow比例的重新计算。

flex-shrink

用于定义了子元素收缩的能力。

flex-shrink

上图中,父容器宽度固定为500px,子元素设置了flex-basis: 120px; flex-shrink: 1;,此时,D和E设置了flex-shrink: 2。这样,D和E将会收缩自身的长度,尽量将所有的元素都排在父容器的主轴上且尽量不超过父容器的宽度500px

flex-basis

用于在空间被分配前,定义子元素的默认长度。这个值可以是长度(百分比,rem等等)或者是关键字(如auto等)。

.flex-item {
  flex-basis: <length> | auto(默认值); 
}

需要注意的是,如果flex-basis: 0;,那么子元素内容旁边的额外空间是不计算在flex-basis内的。如果设置为auto,那么额外的空间将基于子元素的flex-grow进行计算。计算方式如下图所示。

https://www.w3.org/TR/css-flexbox-1/images/rel-vs-abs-flex.svg

在上图中,子元素的flex-grow1:1:2。当flex-basis: 0;时,子元素内容旁边的额外空间不计数;flex-basis: auto;时,子元素内容旁边的额外空间计数,且比例由其flex-grow决定,这里则是1:1:2。故而,虽然我们的flex-grow设置为了1:1:2,但是由于flex-basis的影响,产生了不同的显示结果。

flex

flex-grow,flex-shrink,flex-basis的属性缩写。其中,flex-shrink和flex-basis是可选项,如不填写这两个值,则默认值为flex-shrink: 1,flex-basis: 0%。如果整个flex属性都不填写,则整个属性默认值为0 1 auto。

.flex-item {
  flex: none | [ <'flex-grow'> <'flex-shrink'> || <'flex-basis'> ];
  flex: 0 1 auto; // 不伸展 收缩度为1 自动基础长度
}

小贴士:强烈建议采用属性缩写的方式来定义子元素的弹性属性,因为它能帮助我们自动地设置许多默认值。

align-self

允许单个子元素覆写父容器的align-items属性(故两者拥有同样的属性值)。

align-self
.flex-item {
  align-seft: auto | flex-start | flex-end | center | baseline | stretch;
}

小贴士:floatclearvertical-align这些属性对一个弹性盒子布局的元素将失去作用。

欢迎交流,完。

TODO:Grid layout 栅格布局


参考文献

https://css-tricks.com/snippets/css/a-guide-to-flexbox/
https://www.w3.org/TR/css-flexbox-1/

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

推荐阅读更多精彩内容

  • H5移动端知识点总结 阅读目录 移动开发基本知识点 calc基本用法 box-sizing的理解及使用 理解dis...
    Mx勇阅读 4,389评论 0 26
  • CSS 3中弹性盒布局的最新版概述 在CSS 3中,CSS Flexible Box模块为一个非常重要的模块,该模...
    吾名无双阅读 1,221评论 0 5
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,725评论 1 92
  • 移动开发基本知识点 一.使用rem作为单位 html { font-size: 100px; } @media(m...
    横冲直撞666阅读 3,452评论 0 6
  • 事实上它是一种新类型的盒子模型,也有书上称作弹性伸缩盒布局。比较新的布局方式:旨在提供一个更加有效的方式来布置,对...
    zh_yang阅读 11,312评论 3 14