之前在做项目时,就曾碰到过一个问题:flex子元素宽度过大时,flex-shrink 并不能限制子元素宽度,导致子元素宽度超出了父元素的宽度。
而最近刚好又碰到这个问题了,就简单记录下,以防遗忘。
1. 问题表现
表现就是子元素宽度不受 flex-shrink 影响,未按照预期进行收缩,比如下面情况:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flex-shrink</title>
<style>
.wrapper {
display: flex;
width: 400px;
border: 1px solid black;
}
.left {
flex-grow: 0;
flex-shrink: 0;
width: 100px;
background: green;
}
.right {
flex-grow: 1;
flex-shrink: 1;
background: teal;
}
.content {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="left"></div>
<div class="right">
<div class="content">
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</div>
</div>
</div>
</body>
</html>
2. 问题分析
从现象上看,子元素根本没有进行预期的收缩,即使我们设置了 flex-shrink。
现在我们换一种思考方式,我想要某个元素 width 在收缩时,不允许小于某个值,你会怎么做?当然是设置 min-width。一旦设置了 min-width,元素的宽度变化就不会小于这个值了。
到了这里,我们其实大概能知道为什么元素没有收缩了,因为元素的 min-width 不允许它收缩。这里也就得出了结论,其实 flex-shrink 仍然受元素自身的尺寸影响,即如果我设置了 min-width,那无论如何,flex-shrink 也不会收缩到比 min-width 还小的尺寸。
比如下面的例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flex-shrink</title>
<style>
.wrapper {
display: flex;
width: 400px;
border: 1px solid black;
}
.left {
flex-grow: 0;
flex-shrink: 0;
width: 390px;
background: green;
}
.right {
flex-grow: 1;
flex-shrink: 1;
min-width: 20px;
height: 20px;
background: teal;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>
所以,flex-shrink 是受元素 min-width 影响,且不能比其更小。回到上面的问题,子元素没有按照预期收缩也是能理解的了,默认的 min-width 的值是 auto,即为 width 的尺寸,而 width 的尺寸则为元素的默认大小,就是文字全部展开的大小,所以导致 flex-shrink 无法生效。
3. 解决方案
知道上面的原因后,解决方案也很简单,设置 min-width: 0 即可。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flex-shrink</title>
<style>
.wrapper {
display: flex;
width: 400px;
border: 1px solid black;
}
.left {
flex-grow: 0;
flex-shrink: 0;
width: 100px;
background: green;
}
.right {
flex-grow: 1;
flex-shrink: 1;
min-width: 0;
background: teal;
}
.content {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="left"></div>
<div class="right">
<div class="content">
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</div>
</div>
</div>
</body>
</html>