关于CSS:Chrome / Safari无法填充Flex父级的100%高度

Chrome / Safari not filling 100% height of flex parent

我想要一个具有特定高度的垂直菜单。

每个孩子都必须填充父母的身高,并且中间对齐文本。

孩子的数量是随机的,因此我必须使用动态值。

Div .container包含随机数量的子级(.item),这些子级始终必须填充父级的高度。 为此,我使用了flexbox。

为了使文本中间对齐,我使用了display: table-cell技术。 但是使用表格显示需要使用高度100%。

我的问题是.item-inner { height: 100% }在webkit(Chrome)中不起作用。

  • 有解决此问题的方法吗?
  • 还是有一种不同的技术可以使所有.item垂直于中间对齐,从而使父级的高度全部填充?
  • 此处的示例jsFiddle,应在Firefox和Chrome中查看

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    .container {
      height: 20em;
      display: flex;
      flex-direction: column;
      border: 5px solid black
    }
    .item {
      flex: 1;
      border-bottom: 1px solid white;
    }
    .item-inner {
      height: 100%;
      width: 100%;
      display: table;
    }
    a {
      background: orange;
      display: table-cell;
      vertical-align: middle;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
          Button
       
     

     
       
          Button
       
     

     
       
          Button


    使用嵌套的伸缩容器。

    摆脱百分比高度。摆脱表属性。摆脱vertical-align。避免绝对定位。一直坚持使用flexbox。

    display: flex应用于弹性项目(.item),使其成为弹性容器。这会自动设置align-items: stretch,这告诉子级(.item-inner)扩展父级的整个高度。

    重要提示:从弹性项目中删除指定的高度,此方法才能起作用。如果孩子有指定的身高(例如height: 100%),则它将忽略来自父母的align-items: stretch。为了使stretch默认值起作用,孩子的身高必须计算为auto(完整说明)。

    试试看(HTML不变):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    .container {
        display: flex;
        flex-direction: column;
        height: 20em;
        border: 5px solid black
    }

    .item {
        display: flex;                      /* new; nested flex container */
        flex: 1;
        border-bottom: 1px solid white;
    }

    .item-inner {
        display: flex;                      /* new; nested flex container */
        flex: 1;                            /* new */

        /* height: 100%;                    <-- remove; unnecessary */
        /* width: 100%;                     <-- remove; unnecessary */
        /* display: table;                  <-- remove; unnecessary */  
    }

    a {
        display: flex;                      /* new; nested flex container */
        flex: 1;                            /* new */
        align-items: center;                /* new; vertically center text */
        background: orange;

        /* display: table-cell;             <-- remove; unnecessary */
        /* vertical-align: middle;          <-- remove; unnecessary */
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
          Button
       
     

     
       
          Button
       
     

     
       
          Button

    jsFiddle演示

    说明

    My problem is that .item-inner { height: 100% } is not working in
    webkit (Chrome).

    它不起作用,因为您使用的百分比高度与规范的传统实现方式不一致。

    10.5 Content height: the height property

    percentage Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's
    containing block. If the height of the containing block is not
    specified explicitly and this element is not absolutely positioned, the value computes to auto.

    auto The height depends on the values of other properties.

    换句话说,要使百分比高度适用于流入儿童,父级必须具有设定的高度。

    在您的代码中,顶级容器具有定义的高度:.container { height: 20em; }

    第三级容器具有定义的高度:.item-inner { height: 100%; }

    但是在它们之间,第二级容器.item没有定义的高度。 Webkit将其视为缺少的链接。

    .item-inner告诉Chrome:给我height: 100%。 Chrome会寻找父级(.item)供参考并作出响应:100%是什么?我什么也没看到(忽略那里的flex: 1规则)。结果,根据规范,它应用了height: auto(内容高度)。

    另一方面,Firefox现在接受父级的flex高度作为孩子的百分比高度的参考。 IE11和Edge也接受弯曲高度。

    同样,如果将Chrome与flex-basis结合使用,Chrome将接受作为适当的父级引用(任何数值有效(auto都不会,包括flex-basis: 0))。但是,在撰写本文时,此解决方案在Safari中失败。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #outer {
      display: flex;
      flex-direction: column;
      height: 300px;
      background-color: white;
      border: 1px solid red;
    }
    #middle {
      flex-grow: 1;
      flex-basis: 1px;
      background-color: yellow;
    }
    #inner {
      height: 100%;
      background-color: lightgreen;
    }
    1
          INNER

    四种解决方案

    1.在所有父元素上指定高度

    可靠的跨浏览器解决方案是在所有父元素上指定高度。这样可以防止丢失链接,基于Webkit的浏览器会认为这些链接违反了规范。

    请注意,min-heightmax-height是不可接受的。它必须是height属性。

    此处有更多详细信息:使用CSS height属性和百分比值

    2. CSS相对和绝对定位

    position: relative应用于父级,将position: absolute应用于子级。

    使用height: 100%width: 100%调整子项的大小,或使用偏移属性:top: 0right: 0bottom: 0left: 0

    通过绝对定位,百分比高度可以在父级上没有指定高度的情况下工作。

    3.删除不必要的HTML容器(推荐)

    button附近是否需要两个容器?为什么不删除.item.item-inner或两者都删除?尽管button元素有时无法作为flex容器使用,但它们可以是flex项。考虑将button设为.container.item的子级,并删除不必要的标记。

    这是一个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    .container {
        height: 20em;
        display: flex;
        flex-direction: column;
        border: 5px solid black
    }

    a {
        flex: 1;
        background: orange;
        border-bottom: 1px solid white;
        display: flex;                   /* nested flex container (for aligning text) */
        align-items: center;             /* center text vertically */
        justify-content: center;         /* center text horizontally */
    }
    1
    2
    3
        Button
        Button
        Button

    4.嵌套的Flex容器(推荐)

    摆脱百分比高度。摆脱表属性。摆脱vertical-align。避免绝对定位。一直坚持使用flexbox。

    display: flex应用于弹性项目(.item),使其成为弹性容器。这会自动设置align-items: stretch,这告诉子级(.item-inner)扩展父级的整个高度。

    重要提示:从弹性项目中删除指定的高度,此方法才能起作用。如果孩子有指定的身高(例如height: 100%),则它将忽略来自父母的align-items: stretch。为了使stretch默认值起作用,孩子的身高必须计算为auto(完整说明)。

    试试看(HTML不变):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    .container {
        display: flex;
        flex-direction: column;
        height: 20em;
        border: 5px solid black
    }

    .item {
        display: flex;                      /* new; nested flex container */
        flex: 1;
        border-bottom: 1px solid white;
    }

    .item-inner {
        display: flex;                      /* new; nested flex container */
        flex: 1;                            /* new */

        /* height: 100%;                    <-- remove; unnecessary */
        /* width: 100%;                     <-- remove; unnecessary */
        /* display: table;                  <-- remove; unnecessary */  
    }

    a {
        display: flex;                      /* new; nested flex container */
        flex: 1;                            /* new */
        align-items: center;                /* new; vertically center text */
        background: orange;

        /* display: table-cell;             <-- remove; unnecessary */
        /* vertical-align: middle;          <-- remove; unnecessary */
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
          Button
       
     

     
       
          Button
       
     

     
       
          Button

    的jsfiddle


    解决方案:删除.item-inner中的height: 100%并在.item中添加display: flex

    演示:https://codepen.io/tronghiep92/pen/NvzVoo


    对于Mobile Safari,有一个浏览器修复程序。 您需要为iOS设备添加-webkit-box。

    防爆。

    1
    2
    3
    4
    5
    6
    7
    display: flex;
    display: -webkit-box;
    flex-direction: column;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -webkit-flex-direction: column;
    align-items: stretch;

    如果您将align-items: stretch;属性用作父元素,请从子元素中删除height : 100%


    我在iOS 8、9和10中遇到过类似的问题,上面的信息无法解决,但是经过一天的努力,我确实找到了解决方案。 当然,它不适用于所有人,但在我的情况下,我的物品堆放在一列中,当它应该为内容高度时,其高度为0。 将CSS切换为行换行可解决此问题。 仅当您只有一个项目并且将它们堆叠在一起时,此方法才有效,但是由于花了我一天的时间才能找出答案,所以我认为我应该分享我的解决方案!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    .wrapper {
        flex-direction: column; // <-- Remove this line
        flex-direction: row; // <-- replace it with
        flex-wrap: wrap; // <-- Add wrapping
    }

    .item {
        width: 100%;
    }