flex-1的元素,其高度被子元素撑开的原因及解决方案

·  阅读 772

问题:

嵌套的flex容器,子flex的高度会超过父容器高度,并导致父容器高度变大。

Demo链接

效果如下,可以很明显的看到, 顶层节点App的高度是正常的,但是content却被子容器给撑开了。 截图

大概说一下这个页面布局结构

App // flex box, column
    > title
    > content // flex box, column
        > content title
        > content list // flex box, column. overflow-auto
            > list item
            > list item
            > ...
复制代码

其中App作为最外层,是个定高的flex box

titlecontent title也是定高的。

每个list item都是定高的,但是由于list是动态渲染的,导致content list的高度不定。

并且content listoverflow-auto的,预期是通过flex-1计算到的高度来约束其内部list item的滚动,即假设content list最多可以从content上分到400px的高度,那么当list item的总高度大于400时,将列表进行滚动,反之则正常渲染。

先说结论

推荐的解决方案:

  1. 设置min-height: 0,而不是设置height: 0
  2. 设置overflow: visible(只要不是auto就行)。

原因也并不是由于子元素flex-1撑开了父容器, 而是父容器本身min-height的计算值导致了其高度计算出现问题,使子元素overflow失效了。

原因分析

为什么会content list的高度会撑开其父容器?

原因: flex主轴上的min-height/widthauto。普通的元素是0pxmdn链接

the used value of a main axis automatic minimum size on a flex item that is not a scroll container is a content-based minimum size; for scroll containers the automatic minimum size is zero, as usual.

In particular, if flex sizing is being used for a major content area of a document, it is better to set an explicit font-relative minimum width such as min-width: 12em. A content-based minimum width could result in a large table or large image stretching the size of the entire content area into an overflow zone, and thereby making lines of text gratuitously long and hard to read.Note also, when content-based sizing is used on an item with large amounts of content, the layout engine must traverse all of this content before finding its minimum size, whereas if the author sets an explicit minimum, this is not necessary. (For items with small amounts of content, however, this traversal is trivial and therefore not a performance concern.)

关于min-height: auto的计算:(mdn链接

For min-width/min-height, specifies an automatic minimum size. Unless otherwise defined by the relevant layout module, however, it resolves to a used value of 0.

简而言之就是,默认解析为0,除非当前布局容器另有计算规则

由于flex容器主轴上的min-height/width用的是content-base minimun size

In general, the content-based minimum size of a flex item is the smaller of its content size suggestion and its specified size suggestion. However, if the box has an aspect ratio and no specified size, its content-based minimum size is the smaller of its content size suggestion and its transferred size suggestion. If the box has neither a specified size suggestion nor an aspect ratio, its content-based minimum size is the content size suggestion.

content-base minimun size通常情况下是content size用户设值之间的最小值,如果有长宽比例限制再另做计算

以上面的demo为例分析就是:

因为content list的高度已经溢出了,对于content而言,由于flex主轴的min-height: auto,导致contentmin-height解析为HcontentList+HcontentTitleH_{contentList} + H_{contentTitle},所以content看起来被其子容器给撑开了。

此时由于content list的高度与其本身渲染所需高度一致,所以并不会触发overflow: auto的滚动条渲染。

Height: 0为什么会生效

上面已经提到在flex itemmin-height: auto会被解析成content-based minimum size

如果设置了height: 0那么就永远是height: 0了(因为content-size的计算值不可能比0小),此时如果配合上flex: 1,就会使得该元素的computed size符合预期了。

猜想他们的生效顺序是 height: 0 -> minHeight: 0 -> flex: 1(没找到相关的文章- -)

最终渲染的结果是flex: 1的计算值,由于flex: 1的计算值是小于content的高度的,所以此时会触发content listoverflow,并且也不会使content的高度变大。

分类:
前端
标签: