Chrome中flexbox项目的高度不正确。

4
我有一个微妙的问题需要CSS大师们的帮助。 我的绿色div具有灵活的高度,占据剩余部分。 现在我想在该div内放置一个div,应该是绿色div的一半。但似乎Chrome将其视为整个页面的一半,而不是flex项目的一半。

http://jsfiddle.net/unh5rw9t/1/

HTML

<body>
    <div id="wrapper">
        <div id="menu">
            1
        </div>
        <div id="content">2
            <div id="half_of_content">2.1</div>
        </div>
        <div id="footer" style="">
            3
        </div>
    </div>
</body>

CSS

html,body {
    height: 100%;
    margin: 0;
}

#wrapper {
    display: flex;
  flex-flow: column;
    height: 100%;
}

#menu {
    height: 70px; 
    background-color: purple
}

#content {
    flex: 1;
    height: 100%;
    background-color: green;
}

#half_of_content {
    height: 50%;
    background-color: yellow;
}

#footer {
    height: 100px; 
    background-color: cyan
}
4个回答

3

@Michael_B 解释了为什么Chrome会有这样的行为:

您给body设置了height: 100%。然后给它的子元素(.wrapper)设置了height: 100%。接着给它的子元素(.content)设置了height: 100%因此,它们的高度都是相等的。如果给下一个子元素(#half_of_content)设置height: 50%,那自然就是body的50%高度。

然而,Firefox并不同意这种做法,因为实际上.contentheight: 100%被忽略了,并且它的高度是根据flex: 1计算的。

也就是说,Chrome根据父元素的height属性值来解析百分比。而Firefox则是根据父元素的可伸缩高度来解析百分比。

正确的行为是Firefox的行为。根据Definite and Indefinite Sizes

如果一个百分比将针对 flex itemmain size 进行解析,并且该 flex item 具有 definiteflex basis,且该 flex container 具有 definitemain size,则必须将该 flex itemmain size 视为 definite,以解析百分比,且百分比必须针对 flex item弯曲main size 进行解析(即,在为 flex itemflex container 完成下面的布局算法并且 flex item 获得其最终大小之后)。

这里是 Chrome 的解决方法:

#content {
  display: flex;
  flex-direction: column;
}
#content::after {
  content: '';
  flex: 1;
}
#half_of_content {
  flex: 1;
  height: auto;
}

这样,#content 中可用的空间将均匀分配给 #half_of_content::after 伪元素。

假设 #content 没有其他内容,则 #half_of_content 将为 50%。在您的示例中,其中有一个 2,因此它会略小于 50%

html,
body {
  height: 100%;
  margin: 0;
}
#wrapper {
  display: flex;
  flex-flow: column;
  height: 100%;
}
#menu {
  height: 70px;
  background-color: purple
}
#content {
  flex: 1;
  height: 100%;
  background-color: green;
  display: flex;
  flex-direction: column;
}
#content::after {
  content: '';
  flex: 1;
}
#half_of_content {
  flex: 1;
  background-color: yellow;
}
#footer {
  height: 100px;
  background-color: cyan
}
<div id="wrapper">
  <div id="menu">
    1
  </div>
  <div id="content">2
    <div id="half_of_content">2.1</div>
  </div>
  <div id="footer" style="">
    3
  </div>
</div>


在不进行丑陋的修复操作的情况下,我是否可以在# half_of_content容器内使用正常的高度百分比计算?因为我将在以后分割很多空间... - user2441535
@Doodlemeat 由于#half_of_content具有height: auto,因此您无法在其子元素的height中使用百分比。但是您可以再次使用相同的技巧,例如,如果您想要一个子元素为70%,请设置flex:70并添加带有flex:100的伪元素。 - Oriol
这是Chrome和FF之间有趣的区别。我认为传统上,在计算百分比高度时,浏览器将规范解释为由“height”属性定义的高度。在处理百分比高度时,我从未见过父元素使用“min-height”,“max-height”或“flex-basis”(直到现在)。 - Michael Benjamin
规范有点老,正如你所指出的那样,似乎需要一个高度(通用术语),但不需要 height,尽管 height 是主要实现。看起来 FF 正在放宽其解释。 - Michael Benjamin
1
@Michael_B 在我看来,Firefox 实现使用已解决的高度而不是 height 值更有意义。前几天我发现了另一个有趣的情况,其中容器的高度并不直接取决于内容的高度,但通过 min-height: auto 实现。我想我们必须等到新的规范澄清这些情况。 - Oriol

0
你可以使用绝对定位来定位 div id="half_of_content"
#content {
    flex: 1;
    height: 100%;
    background-color: green;
    position: relative; /* new */
}

#half_of_content {
    height: 50%;
    background-color: yellow;
    position: absolute; /* new */
    width: 100%; /* new */
}

演示

关于您的声明:

但是似乎Chrome将其视为整个页面的一半,而不是弹性项。

您给body设置了height: 100%。然后给它的子元素(.wrapper)设置了height: 100%。然后给它的子元素(.content)设置了height: 100%所以它们的高度都相等。给下一个子元素(#half_of_content)设置height: 50%自然会是body的50%高度。

然而,使用绝对定位您不需要指定父级高度


这实际上比Oriols的解决方案看起来更好,尽管这可能看起来更丑。但在Chrome修复这个bug之前,我会使用最简单的方法。 - user2441535
如果可以的话,我想避免在#wrapper上设置height:100%,因为它已经从flexbox接收到高度。但是,如果这样做,我就无法在子元素上设置50%的高度,因为……我不知道为什么。所以我们可以正式说,增长的flex项目不会接收到它们的实际高度 - user2441535
“丑陋?”我在那个解决方案中看到了美的东西 :-) 50%的div在父div中美丽、优雅、精确地扩展和收缩。 - Michael Benjamin
只是为了明确,因为我不确定你在说哪个 div#half_of_height 不是 一个 flex 项。 - Michael Benjamin
50%的意思是取父母身高的一半。但在这种情况下,它并不是这样。 - user2441535

0
嵌套flexbox有一些小问题。我重新安排了你的标记,添加了一个内部包装器,并使用display: flex;,这似乎可以解决问题。这是fiddle(还使用类名而不是ID)。
<div class="content">
  <div class="wrapper-inner">
    2
    <div class="half">
      2.1
    </div>
  </div>
</div>

.wrapper-inner {
    position: absolute;
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 100%;
}

0
修复:
#content 上设置

display: flex; 
flex-flow: column nowrap; 
justify-content: flex-end

#half_of_content 上设置 flex: 0 0 50%

注意:您需要添加一个作为 #content 子元素的 extra div。

以下是完整示例:

html,body {
    height: 100%;
    margin: 0;
}

#wrapper {
    display: flex;
  flex-flow: column;
    height: 100%;
}

#menu {
    height: 70px; 
    background-color: purple
}

#content {
    flex: 1;
    height: 100%;
    display:flex;
    flex-flow: column nowrap;
    justify-content: flex-end;
    background-color: green;
}

#half_of_content {
    flex: 0 0 50%;
    background-color: yellow;
}

#footer {
    height: 100px; 
    background-color: cyan
}
<body>
    <div id="wrapper">
        <div id="menu">
            1
        </div>
        <div id="content">2
            <div id="half_of_content">2.1</div>
        </div>
        <div id="footer" style="">
            3
        </div>
    </div>
</body>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接