假设我们有这样的布局:
<div class="flex flex-col w-[400px] h-[400px]">
<div>div 1</div>
<div>div 2</div>
<div>div 3</div>
</div>
我们希望实现这样的效果:三个 div 的高度固定按照 1:2:3 的比例分配。
<div class="flex flex-col w-[400px] h-[400px]">
<div class="flex-1 min-h-0 overflow-clip">div 1</div>
<div class="flex-[2_0_0] min-h-0 overflow-clip">div 2</div>
<div class="flex-[3_0_0] min-h-0 overflow-clip">div 3</div>
</div>
在 Tailwind CSS 中,class flex-1
表示 CSS 中的属性 flex: 1 1 0%
,flex-[2_0_0]
表示 flex: 2 0 0
,flex-[3_0_0]
表示 flex: 3 0 0
。而 CSS 中flex: X Y Z
是一个缩写,相当于:
flex-grow: X;
flex-shrink: Y;
flex-basis: Z;
其中,flex-grow
表示元素的放大比例,flex-shrink
表示元素的缩小比例,flex-basis
表示元素的基础大小。
下面举个例子来说明flex-grow
和flex-basis
的作用,flex-shrink
的道理是类似的。
考虑下面的布局:
<div class="flex flex-col h-[400px]">
<div class="flex-[2_0_100px]">div 1</div>
<div class="flex-[1_0_0]">div 2</div>
</div>
父元素的高度是 400px,而 div 1 的 basis 是 100px,div 2 的 basis 是 0。因此,减去基础高度之后,父元素还剩下 300px 的高度可以分配,这些空间按照 2:1 的比例分配给 div 1 和 div 2,所以 div 1 的分配到的高度是 200px,div 2 是 100px。最终的效果是 div 1 的高度是 100 + 200px = 300px,div 2 的高度是 0 + 100px = 100px。
在解决方案中,我们还设置了min-h-0
,也就是min-height: 0
。这是因为在 flex 布局中,如果子元素的内容超出了子元素原本的高度,子元素会被强制拉伸,从而破坏比例分配。因此,我们需要设置min-height: 0
来让溢出的内容不会影响到父元素的高度。
经过上面的设置,现在 div block 的高度已经没问题了,但是 div 里面的内容还是可能会溢出。因为在 HTML 中,并没有规定元素的内容(比如文本)不能超出元素的边界。因此,我们需要设置overflow-clip
来截断溢出的内容,也可以设置overflow-auto
来显示一个滚动条。
这里有一个细节,就是 padding 和 border 也会影响元素的基础宽度或高度,从而破坏比例分配。StackOverflow 上有一个专门讨论这个问题的帖子:Why is padding expanding a flex item?。
简单来说,问题出在flex-basis
的计算上。最终生效的flex-basis
的值是按照下面的公式计算的:
real_flex_basis = max(flex_basis, padding + border)
下面是一些解决办法:
flex-basis
设置成一个符合比例的同时又略微大于 padding + border 的值。