需求与问题描述
需求简介
在前端开发中,我们经常会遇到这样的布局:在一个容器中,排布有两个元素,A元素宽度固定,B元素宽度自适应,如下图:
我们的CSS也能随手捏来
js
<div class="card-content-wrap">
<div class="left">左边元素固定宽度308px------------------</div>
<div class="right">
右边元素flex:1
</div>
</div>
<style lang="less" scoped>
.card-content-wrap {
width: 1000px;
border: 1px solid blue;
display: flex;
justify-content: space-between;
.left {
width: 308px;
margin-right: 16px;
}
.right {
flex: 1;
}
}
</style>
上述代码中,我们使用flex: 1
的属性让右边的元素占满了剩余空间
问题描述
在一些普通场景中,上述用法是完全没有问题的,但是,当这个自适应元素(父元素)内部有子元素且子元素宽度大于父元素时,问题就出现了。
子元素较宽,导致左侧固定元素被挤压:
js
<div class="card-content-wrap">
<div class="left">左边元素固定宽度308px------------------</div>
<div class="right">
右边元素flex:1
<div style="width: 920px; border: 1px #ff2d2d solid">
子元素较大,导致左侧固定元素被挤压
</div>
</div>
</div>
子元素非常宽,导致左侧元素被挤压,右侧元素超出安全区域:
js
<div class="card-content-wrap">
<div class="left">左边元素固定宽度308px------------------</div>
<div class="right">
右边元素flex:1
<div style="width: 1220px; border: 1px #ff2d2d solid">
子元素宽度过大,导致父元素被挤出屏幕
</div>
</div>
</div>
显然,上述的样式问题和我们期望的行为不一致,那么我们该如何优雅的解决这个问题呢?
解决方案
我们先说解决方案,在具体分析原因
使用overflow: hidden
给flex: 1
的父元素设置overflow: hidden可以解决上述问题。但是如果需要父元素出现滚动条的情况,这种方式显然不合适。
js
<style lang="less" scoped>
.card-content-wrap {
width: 1000px;
border: 1px solid blue;
display: flex;
justify-content: space-between;
.left {
width: 308px;
margin-right: 16px;
}
.right {
flex: 1;
overflow: hidden;
}
}
</style>
使用width:0
这是最佳的解决方案。
js
<div class="card-content-wrap">
<style lang="less" scoped>
.card-content-wrap {
width: 1000px;
border: 1px solid blue;
display: flex;
justify-content: space-between;
.left {
width: 308px;
margin-right: 16px;
}
.right {
flex: 1;
width: 0;
}
}
</style>
且这种方式可以完美解决父元素需要出现滚动条的情况。
js
.right {
flex: 1;
width: 0;
overflow: auto;
}
使用min-width:0
min-width:0 的效果和width:0效果完全一致。
js
.right {
flex: 1;
min-width: 0;
overflow: auto;
}
竖直方向的布局如何解决
对于竖直方向其实也存在相同的问题
解决方案其实和水平方向完全一致
设置overflow: hidden
js
.bottom{
flex: 1;
overflow: hidden;
}
或者设置height: 0
js
.bottom{
flex: 1;
height: 0;
}
或者设置min-height: 0
js
.bottom{
flex: 1;
min-height: 0;
}
问题原因
flex: 1 是 CSS 中用于弹性布局(Flexbox)的一个简写属性,用于在容器内分配多余空间或者收缩元素以适应容器大小。它综合了 flex-grow 、flex-shrink 和 flex-basis 三个属性的值。
当使用 flex: 1 时,你实际上是在设置:
flex-grow
: 1:元素会尝试占据多余的空间。flex-shrink
: 1:元素在必要时会缩小。flex-basis: 0%
:元素的默认大小是 0,这意味着它会完全依赖 flex-grow 来分配空间。
基于上述基础知识,简单来说问题的原因就在于flex属性只是对父元素的多余空间按什么比例去分配,并不是按我们的理解意思为固定分配的方式,不会对子元素原本实际内容宽度进行处理!
浏览器默认为flex容器的子元素设置了 "min-width: auto;min-height: auto",这意味着子元素的最小宽度和高度不能小于其内容的宽度和高度。
我们设置为min-width: 0,覆盖掉了其默认行为,即使其内容为空或者宽度很小,也可以使得flex子元素在flex容器中正确地布局。