CSS flex-basis属性的用法详解
在 Flex 布局中,一个 Flex 子项的宽度是由元素自身尺寸,flex-basis设置的基础尺寸,以及外部填充(flex-grow)或收缩(flex-shrink)规则 3 者共同决定的。
flex-basis 与盒模型
flex-basis的尺寸是作用在 content-box 上的,这个和 width 属性是一样的。例如:
.flex-basis { padding: 1em; border: 1em solid deepskyblue; color: deepskyblue; flex-basis: 100px; }
和
.width { padding: 1em; border: 1em solid deepskyblue; color: deepskyblue; width: 100px; }
在外部尺寸够大,内容尺寸够小的情况下,两者的表现是一样的。
如下图示意:
我们可以通过设置 box-sizing 属性改变元素的盒模型,例如:
.flex-basis { padding: 1em; border: 1em solid deepskyblue; color: deepskyblue; flex-basis: 100px; box-sizing: border-box; word-break: break-all; }
此时就可以看到内容展示宽度变小了,外部尺寸表现为 100px:
但是,在 IE11 浏览器下,box-sizing:border-box 是没有任何效果的。
这个细节知识点还是有点用的,在开发内部系统的 PC 项目上,兼容 Chrome 和 Firefox 是没问题的,但顶不住老板用 IE 浏览器,因此,需要兼容到 window 7 Edge,也就是 IE 11,这个时候,就要避免改变 Flex 子项的 box-sizing 属性值,当然,移动端项目可以不用想那么多。
flex-basic 与盒模型样式表现 demo
代码:
CSS 代码: by-mybj{ display: flex; } item-mybj{ padding: 1em; border: 1em solid deepskyblue; color: deepskyblue; outline: 1px dashed #fff; } item-mybj:nth-child(1) { width: 100px; } item-mybj:nth-child(2) { width: 100px; box-sizing: border-box; } item-mybj:nth-child(3) { flex-basis: 100px; } item-mybj:nth-child(4) { flex-basis: 100px; box-sizing: border-box; } HTML 代码: <by-mybj> <item-mybj>我设置了 width:100px</item-mybj> <item-mybj>我设置了 width:100px,同时 box-sizing: border-box</item-mybj> <item-mybj>我设置了 flex-basis:100px</item-mybj> <item-mybj>我设置了 flex-basis:100px,同时 box-sizing: border-box</item-mybj> </by-mybj>
深入理解 flex-basis 和 width 的关系
在 Flex 布局中,子项设置 width 是没有直接效果的。
此时一定会有人反驳,我明明设置了 width:100px 就有效果啊!
对是有效果,但并不是 width 直接生效的,而是 flex-basis 的作用。
深入理解 flex-basis:auto
flex-basis 的默认值是 auto,表示自动,也就是完全根据子列表项自身尺寸渲染。
自身尺寸渲染优先级如下:
min-width > || max-width > width > Content Size
同时,在 Flex 布局中,flex-basis 优先级是比 width 高的(可以理解为覆盖)。
所以,flex-basis 和 width 同时设置了具体的数值,则 width 属性值直接被打入冷宫,在样式表现上完全被忽略。
例如:
<by-mybj> <item-basis-width>项目 1</item-basis-width> <item-basis-width>项目 2</item-basis-width> <item-basis-width>项目 3</item-basis-width> <item-basis-width>项目 4</item-basis-width> </by-mybj>
CSS 代码如下:
by-mybj{ display: flex; } item-basis-width { padding: 1em; border: 1px solid deepskyblue; color: deepskyblue; box-sizing: border-box; width: 200px; flex-basis: 100px; }
结果 width:200px 完全是一个盒饭角色,所谓盒饭角色,就是明明参与了这部电视剧,也吃了剧组的盒饭,但是观众完全就没有意识到他的存在。这里的 width 属性就是这种性质,代码中确实出现过,但是样式渲染却完全体现不出来。
如下图所示,宽度表现为 100px。width:200px 完全被忽视。
回到主线这里,实际上,flex-basis 值是 auto 的时候,width 属性值也是被打入冷宫的,只是,这个时候,由于后宫放权,所以,冷宫也是有影响力的。什么意思呢?
flex-basis:auto 的含义是,子项的基本尺寸根据其自身的尺寸决定。而这个自身尺寸与下面这几个方面有关:
- box-sizing 盒模型(这个已经介绍过了);
- width/min-width/max-width 等 CSS 属性设置;
- content 内容(min-content 最小宽度);
所以下面两段 Flex 布局中的 CSS 就不难理解了:
item-width { width: 100px; }
最终尺寸 = 自身尺寸 mix basis 尺寸。
此时,自身尺寸为 100px,basis 尺寸按照自身尺寸来算(因为此时属性值是 auto),因此最终尺寸是 100px。
最终尺寸 = 自身尺寸 mix basis 尺寸。
此时,自身尺寸为 content 内容最小宽度,basis 尺寸 100px,因此最终尺寸是:如果 content 内容最小宽度不超过 100px,则最终尺寸是 100px,否则就是内容最小宽度。
记住上面的解释,我们再看下面几个例子,就会豁然开朗了。
案例 1:相同表现
一个元素最小宽度超过 100 像素场景并不多,因此大部分场景下,flex-basis 和 width 表现是一致的。
例如下面这个对比案例:
<h4>1. flex-basis:100px</h4> <by-mybj> <item-basis>项目 1</item-basis> <item-basis>项目 2</item-basis> <item-basis>项目 3</item-basis> <item-basis>项目 4</item-basis> </by-mybj> <h4>2. width:100px</h4> <by-mybj> <item-width>项目 1</item-width> <item-width>项目 2</item-width> <item-width>项目 3</item-width> <item-width>项目 4</item-width> </by-mybj>
一个设置 width:100px,一个设置 flex-basis:100px:
item-width { width: 100px; } item-basis { flex-basis: 100px; }
默认都是 100px 的展示,例如我的 PC 电脑显示器下:
由于默认 flex-shrink 属性值是 1,因此,容器宽度不足时候的弹性收缩效果也是一样的,如下 GIF 示意:
案例 2:不同表现
什么时候 width:100px 和 flex-basis:100px 表现不一样呢?就是最小内容宽度较大的时候,例如出现连续英文单词 demo_by_mybj。
还是上面那个 demo 页面,点击任意某个子项,会改变元素里面的文字内容为 demo_by_mybj。
此时就可以看到两者的差异了
因为此时 content 内容最小宽度超过了 100px,于是 flex-basis:100px 按照了最小内容宽度显示了;但是 width:100px 把元素的尺寸限制得死死的,字符直接溢出容器之外。
要想两者表现一致,可以使用 word-break:break-all 使单词断开。
其实,本文一开始的“flex-basic 与盒模型样式表现”这个 demo 就已经展现了 flex-basis 和 width 属性的区别了。例如第 4 项设置的 flex-basis 值是 100px,同时 box-sizing 是 border-box,但是最终表现出来的尺寸却不是 100px,却是个更大的宽度值,如下图所示:
主要是因为这一项里面的内容,’basis:100px’会当做一个独立的单词,并作为此时 flex-basis 默认就有的最小宽度,这个宽度值等同于 min-content 的计算尺寸。
我们可以对比一下隔壁 width:100px 的效果,可以看到文字内容’width:100px’直接溢出到了容器之外。
更深入的案例:最小内容宽度、width 和 flex-basis 同时满足
根据上面的分析(不考虑容器尺寸不足或溢出),我们可以得到结论:
- width:100px + flex-basis:auto = 元素自身 100px
- content + flex-basis:100px = max(content, flex-basis) = 大于等于 100px
再加上flex-basis 优先级是比 width 高的结论,我们就可以得到:
- content + width:100px + flex-basis:100px = content + flex-basis:100px = max(content, flex-basis) = 大于等于 100px
事实究竟是不是这样呢?我们看一个实际的例子。
CSS 和 HTML 代码分别如下
by-mybj{ display: flex; } item-mybj { padding: 1em; border: 1em solid deepskyblue; color: deepskyblue; box-sizing: border-box; } item-mybj:nth-child(1) { width: 100px; } item-mybj:nth-child(2) { flex-basis:100px; } item-mybj:nth-child(3) { width: 100px; flex-basis: 100px; } <by-mybj> <item-mybj>我仅设置了 width:100px,没有设置了 flex-basis:100px。</item-mybj> <item-mybj>我没有设置 width:100px,但是设置了 flex-basis:100px。</item-mybj> <item-mybj>我设置了 width:100px,同时设置了 flex-basis:100px</item-mybj> </by-mybj>
如果 flex-basis 优先级是比 width 高,则第 3 个子项的 width:100px 应该是忽略的,也就是项目 2 和项目 3 的渲染表现是一样的。
我们把上面的代码在各个浏览器下跑一下,结果发现出现了尴尬的事情:
在 Chrome 浏览器下,项目 3 和项目 1 表现是一样的,也就是 width:100px 依然起到了一些作用。
但是,在 Firefox 浏览器以及 IE Edge 浏览器下都是符合预期的项目 3 和项目 2 表现一样。
如果想亲自确认一下,可以看一下 flex-basic 与 width 关系深入研究 demo 代码
CSS 代码: by-mybj{ display: flex; } item-mybj { padding: 1em; border: 1em solid deepskyblue; color: deepskyblue; outline: 1px dashed #fff; box-sizing: border-box; } item-mybj:nth-child(1) { width: 100px; } item-mybj:nth-child(2) { flex-basis:100px; } item-mybj:nth-child(3) { width: 100px; flex-basis: 100px; } HTML 代码: <by-mybj> <item-mybj>我仅设置了 width:100px,没有设置了 flex-basis:100px。</item-mybj> <item-mybj>我没有设置 width:100px,但是设置了 flex-basis:100px。</item-mybj> <item-mybj>我设置了 width:100px,同时设置了 flex-basis:100px</item-mybj> </by-mybj>
下面问题来了,到底哪个正确哪个错误呢?
按照历史的经验,大概率 Chrome 浏览器会在 N 年之后的什么时候修改这个表现,和 Firefox 等浏览器一致。
至于谁对谁错啊,这个是没有定论的,规范中估计没有对这个细节进行特别详细的描述。
那给我们的启示是什么东西呢?那很简单,flex-basis 数值属性值和 width 数值属性值不要同时使用,就不会遇到浏览器发现差异的问题。说的更极端一点,在 Flex 布局中,除非万不得已,否则没有使用 width 属性的理由,请使用 flex-basis 代替。
flex-basis 还支持关键字属性值
以前以为 flex-basis 只支持数值,最近才发现,flex-basis 还支持一大波关键字属性值,包括:
/* 根据 flex 子项的内容自动调整大小 */ flex-basis: content; /* 内部尺寸关键字 */ flex-basis: fill; flex-basis: max-content; flex-basis: min-content; flex-basis: fit-content;
但是我要提前先泼一波冷水,目前,在 Chrome 浏览器下,上面任何一个关键字属性值都不支持。这是很罕见的场景。
其中,flex-basis:content 是 Edge 12 以及 Firefox 浏览器支持:
max-content/min-content 关键字目前仅 Firefox 浏览器支持。
fill 和 fit-content 还没有任何浏览器支持。
由于最重要的 Chrome 浏览器不支持,因此上面几个关键字案例就不 demo 演示了,直接文字描述下他们的作用吧。
content 尺寸根据内容决定,跟我自己测试,表现和 max-content 接近。
max-content 最大内容宽度。
min-content 最小内容宽度。
fill 不详
fit-content 不详
flex-basis 与 min-width/max-width
很多前端在 Flex 布局的时候会使用 min-width 或者 max-width 限制列表上的最大尺寸和最小尺寸。
实际上很多时候都是没有必要的,活用 flex-basis 属性和 flex 属性,可以实现类似的效果。
例如我希望一个列表中的每一项最小宽度是 100 像素,尽可能填满整个容器,请问该如何实现?
无需使用 min-width 属性,可以试试下面的 CSS 代码:
.container { display: flex; flex-wrap: wrap; } .item { flex-basis: 100px; flex-grow: 1; }
flex-basic 代替 min/max-width 效果实现 demo 完整代码
CSS 代码: by-mybj{ display: flex; flex-wrap: wrap; } item-mybj{ padding: 1em; border: 1em solid deepskyblue; color: deepskyblue; outline: 1px dashed #fff; box-sizing: border-box; flex-basis: 100px; flex-grow: 1; } HTML 代码: <by-mybj> <item-mybj>最小 100px,总是填满容器。</item-mybj> <item-mybj>最小 100px,总是填满容器。</item-mybj> <item-mybj>最小 100px,总是填满容器。</item-mybj> <item-mybj>最小 100px,总是填满容器。</item-mybj> </by-mybj>
实现效果如下 GIF 示意:
如果希望换行的列表也是等宽的,则需要复制 N 多空标签即可。
总结
本文内容最后的总结一下:
- flex-basis 默认作用在 content box 上,IE11 会忽略 box-sizing;
- width 只是 flex-basis 为 auto 时候间接生效,其余时候使用优先级更高的 flex-basis 属性值;
- flex 子项元素尺寸还与元素内容自身尺寸有关,即使设置了 flex-basis 属性值;
- flex-basis 数值属性值和 width 数值属性值不要同时使用;
- flex-basis 还支持很多关键字属性,只不过目前兼容性不太好;
- flex-basis 使用得当可以实现类似 min-width/max-width 的效果。
关于 Flex 子项最终的尺寸也总结一下:是盒模型,元素自身尺寸特性,以及 flex 属性共同作用的结果。
想要彻底搞清楚啊,需要掌握一个体系的知识点,不是一件简单的事情。
结语
行文匆忙,表达可能有些乱,有一些错误也在所难免,欢迎指正!文中很多理解都属于个人理解,不一定准确,如果有不同意见,非常欢迎交流。
原文链接跳转:《CSS flex-basis 原来有这么多细节》
码云笔记 » CSS flex-basis属性的用法详解