flex布局杂谈
好几个月没写文章了,主要是工作之外还要挤出时间做技术分享实属不易。其实flex布局应该算是所有程序员的CSS入门第一课了,实现一些简单的行列布局无脑好用。但其实flex还是有一些东西可以讲的,可以帮助我们实现一些进阶一点的布局效果
理解最小内容宽度
最小内容宽度是CSS里绕不开的一个概念,CSS中有一个关键字min-content, 可以设置将宽度设置为这个关键字:
width: min-content
那么这个关键字代表什么呢?简单来说,对于中文而言吗,最小内容宽度就是一个汉字的宽度:
<div class="food">啤酒烧烤小龙虾</div>
<style>
.food {
width: min-content;
}
</style>
如果是英语的话,那么就是句子中最长的单词的长度:
<div class="food">this is a very looooooong sentence</div>
<style>
.food {
width: min-content;
background-color: aqua;
}
</style>
可以看到这时候div的宽度变成looooooong的宽度了,理解了最小内容宽度,就能理解一些flex布局
然后是第三种情况,如果div中是一个图片,那么最小内容宽度就是图片的原始尺寸: 这里那我的头像举例:
<div class="food">
<img src="./avatar.awebp" alt="">
</div>
<style>
.food {
width: min-content;
background-color: aqua;
}
</style>
可以看到div的宽度为230px
min-width变化导致flex子项溢出
默认情况下,如果我们在div上不设置min-width,那么min-width默认就是0,可以用JS来证明这一点,还是以food这个div为例:
<script>
const div = document.querySelector('.food');
const style = window.getComputedStyle(div);
const width = style.getPropertyValue('min-width');
console.log(width);
</script>
但是如果将food作为flex的一个子项,那么他的min-width就会变成auto,下面我们就验证这一点:
<div class="flex-container">
<div class="food">
<img src="./avatar.awebp" alt="">
</div>
</div>
<style>
.flex-container {
display: flex;
}
.food {
width: min-content;
background-color: aqua;
}
</style>
<script>
const div = document.querySelector('.food');
const style = window.getComputedStyle(div);
const minWidth = style.getPropertyValue('min-width');
console.log(minWidth);
</script>
这时计算出来的min-width就会变成当前flex子项的最小内容宽度,可以通过写一个demo来证明这一点:
<div class="box">
<div class="innerbox">
loooooooooooooooogword
</div>
</div>
<style>
.box {
width: 100px;
height: 100px;
background-color: aqua;
display: flex;
}
.innerbox {
flex-shrink: 1;
}
</style>
如上图代码,box设置了flex布局,同时子元素显式设置了felx-shrink为1,当然也可以不设置,因为felx子项不设置任何属性的情况下felx-shrink默认就是为1,表现为当容器空间不够时自动收缩。这段代码中子项的内容为一个长单词,他的宽度超过100px。但是父元素被我设置为了宽度为100px,如果是按照我们理解的逻辑,子项的felx-shrink为1,那么子项应该收缩到100px才对,然而此时的情况是这样的:
可以看到浅蓝色的父元素盒子确实是100 * 100px
但是子元素的宽度依然是长单词的宽度:
可能有的朋友会觉得,这是因为我没有设置字符换行,但这和字符不换行不同,字符不换行只是因为字符的宽度超过了容器的宽度,字符跑到了容器外面:
还是相同的DOM结构,只是这次把flex去掉了,可以看到innerbox的宽度是正常的
此时设置overflow-wrap: break-word;可以实现换行:
其本质还是刚才说的,正常状态下min-width计算值为0,所以将尽管字符是溢出的,但是innerbox的大小可以正常缩放。所以设overflow-wrap: break-word正常换行。
但是在flex布局中,子项的min-width为auto,此时浏览器计算出的min-width变成了最小内容宽度。所以不管怎么缩小,最小内容宽度就是他的min-width,导致了子项溢出到容器外。
那么解决办法其实也很简单,直接将min-width设置为0就好了:
.innerbox {
flex-shrink: 1;
min-width:0;
overflow-wrap: break-word;
}
此时子项不再溢出,也能正确换行了。
补更: 其实这个地方还有一种处理方式,一般文字溢出时,除了换行之外,还可以设置打点显示,这个也是很常见的;
.innerbox {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
当flex子项设置overflow为非visible时,也可以破解上述min-width问题。配合打点显示也是一种好的解决方案
各种不同的flex简写:
flex:1
这应该是最最常见的flex布局简写了,以往面试还被问到过。代表了flex:1 1 0%,也就是既能扩展,也能收缩,但是flex-basis是0。当空间足够时,flex子项会等比例扩长。如果空间不够的情况下,flex子项倾向于收缩到最小内容宽度,分别对应了下面两种情况(汉字的最小内容宽度是一个字):
初始值flex:initial
当我们什么都不设置的时候就是flex:initial,也就是flex:0 1 auto。也就是说会收缩,但不会扩展,初始宽度是flex-basis为auto,意味着计算值为内容宽度。收缩时因为flex-basis各不相同,所以收缩的比例按照内容宽度的比例进行收缩:
上图比例为1 : 1 : 2 : 3,因为不会扩张,可以根据汉字的数量观察。
依然是按照内容尺寸的比例进行收缩,收缩后依然维持了1:1:2:3
flex: auto
与flex1有所不同,他是flex:1 1 auto的缩写,可以扩长和收缩,但是初始尺寸flex-basis为内容宽度,这就导致了无论扩张还是收缩都会按照flex-basis来等比例进行,我就不放图了,感兴趣的话可以自己试一下
其余的一些缩写
那么文章写到这,聪明的朋友应该已经看出规律了。flex-basis不仅决定了内容的初始宽度,当元素收缩和扩张时(这里指的是子项的flex-shrink或flex-grow都取相同的值),也会影响内容收缩和扩展的宽度,比如flex:0 为flex:0 1 0%, flex-basis为0,倾向于收缩到最小内容宽度,flex-grow为0说明不扩张,那么他的flex子项默认情况下的宽度就是为最小内容宽度,感性的来看就是一列文字竖着排;flex:none为felx:0 0 auto: 不扩张也不收缩,初始值为内容宽度。尺寸永远保持内容宽度不变。
尾声
flex布局需要一定的理解成本。对于flex-shrink和grow的理解是比较容易的,无非设置收缩和扩张的比例。对于flex-basis来说,无非是0和auto这两个特殊情况,一个是对应了最小内容宽度,一个是对应了内容宽度。
还有就是开头所讲的min-width变化,有可能会导致子项的溢出问题,有时候写代码需要比较谨慎的关注这一点
转载自:https://juejin.cn/post/7369052013151125556