Chrome / Safari 没有填充 100% 的 flex 高度 parent

Chrome / Safari not filling 100% height of flex parent

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

每个 child 必须填充 parent 的高度并具有 middle-aligned 文本。

children 的数量是随机的,所以我必须使用动态值。

Div .container 包含随机数 children (.item) 总是要填满 parent 的高度。为此,我使用了 flexbox。

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

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

  1. 这个问题有解决办法吗?
  2. 或者是否有不同的技术让所有 .item 填充文本的高度 parent 垂直居中对齐?

Example here jsFiddle, should be viewed in Firefox and 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>

解决方案

使用嵌套弹性容器。

去除百分比高度。删除 table 属性。去掉vertical-align。避免绝对定位。 始终坚持使用 flexbox。

display: flex 应用到弹性项目 (.item),使其成为弹性容器。这会自动设置 align-items: stretch,它告诉 child (.item-inner) 扩展 parent.

的完整高度

重要提示:从弹性项目中删除指定的高度以使此方法起作用。如果 child 具有指定的高度(例如 height: 100%),则它会忽略来自 parent 的 align-items: stretch。要使 stretch 默认工作,child 的高度必须计算为 auto )。

试试这个(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 demo


说明

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.

换句话说,要使百分比高度适用于 in-flow child,parent 必须 具有设定的高度。

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

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

但在它们之间,second-level 容器 – .item 没有 定义的高度。 Webkit 将其视为缺失的 link.

.item-inner告诉Chrome:给我height: 100%。 Chrome 参考 parent (.item) 并回复:100% 是什么?我没有看到任何东西(忽略那里的 flex: 1 规则)。因此,它根据规范应用 height: auto(内容高度)。

另一方面,Firefox 现在接受 parent 的弹性高度作为 child 百分比高度的参考。 IE11 和 Edge 也接受弹性高度。

此外,如果与 flex-basis 一起使用(任何数值有效(auto 无效),包括 flex-basis: 0)。然而,在撰写本文时,此解决方案在 Safari 中失败了。

#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.在所有 parent 元素上指定高度

可靠的cross-browser 解决方案是在所有parent 元素上指定高度。这可以防止丢失 link,Webkit-based 浏览器认为这是违反规范的。

注意min-heightmax-height不接受table。必须是 height 属性.

此处有更多详细信息:

2。 CSS 相对和绝对定位

position: relative 应用到 parent 并将 position: absolute 应用到 child。

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

使用绝对定位,百分比高度在 parent.

上无需指定高度即可工作

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

button周围需要两个容器吗?为什么不删除 .item.item-inner,或两者都删除?尽管 ,它们可以是 flex 项目。考虑将 button 设为 .container.item 的 child,并删除不必要的 mark-up.

举个例子:

.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 容器(推荐)

去除百分比高度。删除 table 属性。去掉vertical-align。避免绝对定位。 始终坚持使用 flexbox。

display: flex 应用到弹性项目 (.item),使其成为弹性容器。这会自动设置 align-items: stretch,它告诉 child (.item-inner) 扩展 parent.

的完整高度

重要提示:从弹性项目中删除指定的高度以使此方法起作用。如果 child 具有指定的高度(例如 height: 100%),则它会忽略来自 parent 的 align-items: stretch。要使 stretch 默认工作,child 的高度必须计算为 auto )。

试试这个(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

解决方法:在.item-inner中删除height: 100%,在.item[=中添加display: flex 13=]

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

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

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

.item {
    width: 100%;
}

对于移动版 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;

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

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

.container {
    flex: 0 0 auto;
}

这可确保高度已设置且不会增长。