Chrome / Safari 未填充 flex 父级的 100% 高度

Chrome / Safari not filling 100% height of flex parent

提问人:Ricardo Castañeda 提问时间:11/11/2015 最后编辑:Michael BenjaminRicardo Castañeda 更新时间:3/5/2020 访问量:233941

问:

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

每个子项必须填满父项的高度,并具有中间对齐的文本。

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

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

为了制作与中间对齐的文本的链接,我正在使用技术。但是使用表格显示器需要使用 100% 的高度。display: table-cell

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

  1. 有解决此问题的办法吗?
  2. 或者有没有一种不同的技术可以使所有文本都用垂直对齐到中间的文本填充父项的高度?.item

这里的例子 jsFiddle,应该在 Firefox 和 Chrome 中查看

.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;
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

CSS Google-Chrome WebKit Flexbox

评论

1赞 vsync 11/4/2016
现已修复 - bugs.chromium.org/p/chromium/issues/detail?id=426898
4赞 AlexMA 1/11/2017
这与 OP 没有特别相关,但可能与因“safari 显示绝对高度 100% 不起作用”或类似内容而登陆这里的谷歌员工有关。我在 flex 容器中有一个这样的元素,必须指定并使其按预期显示。top:0left:0
1赞 TylerH 9/15/2017
@vsync尚未修复:stackoverflow.com/questions/46226298/...

答:

506赞 Michael Benjamin 11/11/2015 #1

溶液

使用嵌套的 flex 容器。

摆脱百分比高度。删除表属性。摆脱.避免绝对定位。只要一直坚持使用flexbox即可。vertical-align

应用于柔性项目 (),使其成为柔性容器。这会自动设置 ,告诉子项 () 展开父项的全高。display: flex.itemalign-items: stretch.item-inner

重要提示:从柔性项目中删除指定的高度,此方法才能正常工作。如果一个孩子指定了一个高度(例如),那么它将忽略来自父母的身高。要使默认值起作用,孩子的身高必须计算为(完整解释)。height: 100%align-items: stretchstretchauto

试试这个(对 HTML 没有变化):

.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 */
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

jsFiddle 演示


解释

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

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

10.5 内容高度:height 属性

percentage
指定百分比高度。该百分比是根据生成的框的高度计算的 包含块。如果包含块的高度不是 显式指定,并且此元素不是绝对定位的,则该值计算为 。
auto

auto
高度取决于其他属性的值。

换言之,要使百分比高度对流入的子项起作用,父项必须具有设定的高度。

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

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

但是在它们之间,第二层容器 – – 没有定义的高度。Webkit 认为这是一个缺失的环节。.item

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

另一方面,Firefox 现在接受父母的弹性身高作为孩子身高百分比的参考。IE11 和 Edge 也接受弹性高度。

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

#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;
}
<div id="outer">
  <div id="middle">
    <div id="inner">
      INNER
    </div>
  </div>
</div>


四大解决方案

1. 指定所有父元素的高度

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

请注意,最小高度和最大高度是不可接受的。它必须是 height 属性。

更多详细信息,请参阅:使用 CSS height 属性和百分比值

2. .CSS 相对和绝对定位

适用于父母和孩子。position: relativeposition: absolute

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

使用绝对定位时,百分比高度在父项上没有指定高度的情况下工作。

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

周围需要两个集装箱吗?为什么不删除 or 或两者兼而有之?尽管按钮元素有时无法作为 flex 容器,但它们可以是 flex 项。考虑将 或 设为子项,并删除无偿标记。button.item.item-innerbutton.container.item

下面是一个示例:

.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 */
}
<div class="container">
    <a>Button</a>
    <a>Button</a>
    <a>Button</a>
</div>

4. 嵌套 Flex 容器(推荐)

摆脱百分比高度。删除表属性。摆脱.避免绝对定位。只要一直坚持使用flexbox即可。vertical-align

应用于柔性项目 (),使其成为柔性容器。这会自动设置 ,告诉子项 () 展开父项的全高。display: flex.itemalign-items: stretch.item-inner

重要提示:从柔性项目中删除指定的高度,此方法才能正常工作。如果一个孩子指定了一个高度(例如),那么它将忽略来自父母的身高。要使默认值起作用,孩子的身高必须计算为(完整解释)。height: 100%align-items: stretchstretchauto

试试这个(对 HTML 没有变化):

.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 */
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

jsFiddle

评论

4赞 Alfrex92 11/25/2018
我使用 height:auto 解决了我的问题
3赞 flocbit 5/27/2019
我可以确认使用嵌套的 flex 容器效果最好。我们在菜单中使用了不一致的 flexbox。在某些地方,我们没有在父容器上使用 flex: 1 和 display: flex,而是使用了 height: 100%。在我们替换了相应的定义后,一切都按预期进行。感谢@Michael_B的提示!:)
2赞 DerMike 9/24/2019
@JamesHarrington,CSS随着时间的推移而发展,并且是复杂的 ;-)
1赞 C.Tale 11/12/2022
我发誓,你是一个彻头彻尾的救命恩人。我从来没有这样看待它:“摆脱一切,一直使用 flexbox”让我的风格在任何事情上都更加一致
1赞 LuckyLuke Skywalker 12/22/2022
这个(不是这个答案,而是 flexbox)是一个混乱的实现。应该说,Flexbox 应该用于它所指定的元素,而不是把所有东西都弄乱,或者说是父级结构。但谢谢你的回答。
16赞 Nghiệp 8/24/2017 #2

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

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

评论

0赞 Reece Kenney 8/25/2017
谢谢,这帮助了我。弹性儿童会自动将拉伸到容器的高度吗?这就是它起作用的原因吗?
0赞 Michael Benjamin 8/29/2017
@ReeceKenney,是的,回答你的问题。这在我的回答中得到了解释。请参阅解决方案 #4。
2赞 Designer023 9/6/2018 #3

我在 iOS 8、9 和 10 中遇到了类似的问题,上面的信息无法解决它,但是经过一天的工作,我确实找到了解决方案。当然,它并不适合所有人,但在我的情况下,我的项目堆叠在一列中,并且当它应该是内容高度时,它的高度为 0。将 css 切换为 row 和 wrap 解决了这个问题。这仅适用于您有一个项目并且它们堆叠在一起的情况,但由于我花了一天时间才发现这一点,我想我应该分享我的修复程序!

.wrapper {
    flex-direction: column; // <-- Remove this line
    flex-direction: row; // <-- replace it with
    flex-wrap: wrap; // <-- Add wrapping
}

.item {
    width: 100%;
}
11赞 Nara 11/1/2018 #4

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

前任。

display: flex;
display: -webkit-box;
flex-direction: column;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
align-items: stretch;

如果对父元素使用 property,请从子元素中删除 。align-items: stretch;height : 100%

评论

0赞 Big Money 9/26/2020
天哪,非常感谢你,你让我免于如此多的头痛! 正是我需要的。事实证明,即使在 2020 年底,iOS 设备仍然没有可预测的 flex 支持display: -webkit-box;
40赞 huseyin39 11/6/2019 #5

为容器指定一个 flex 属性对我有用:

.container {
    flex: 0 0 auto;
}

这样可以确保高度已设置,也不会增长。

评论

0赞 boatcoder 1/12/2021
我本来想让它工作,但我最终把容器从视口的底部移开了