为什么我的网格元素的高度计算不正确?

时间:2018-08-22 07:50:13

标签: html css css3 css-grid

我在处理CSS网格元素的高度时遇到麻烦。 我正在使用的代码是:

.gridContainer {
  border: thin solid black;
  background: rgba(255, 0, 0, 0.5);
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  width: 100px;
  height: 100px;
  grid-template-areas: 'windowContentHolder';
}

.gridItem {
  grid-area: windowContentHolder;
  background: rgba(255, 255, 0, 0.5);
  width: 200%;
  height: 200%;
  overflow: auto;
}

.content {
  background: rgba(255, 0, 0, 0.5);
}
<div class="gridContainer">
  <div class="gridItem">
    <div class="content">hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>
    </div>
  </div>
</div>

如您所见,gridItem设置为height:200%,预期结果与预期不符。它的高度(200px)应该是父级(100px)的两倍,滚动条会隐藏任何额外的高度,尽管height属性似乎根本没有设置。

似乎该百分比正在考虑子高度,而不是父高度,因为如果我们仔细检查该元素,我们会发现其高度是子元素高度的两倍。

enter image description here

带有“ hi”的元素不会像预期的那样溢出。将gridContainer更改为“阻止”确实可以正常工作,但不能使用“网格”:

.gridContainer {
  border: thin solid black;
  background: rgba(255, 0, 0, 0.5);
  display: block;
  width: 100px;
  height: 100px;
}

.gridItem {
  grid-area: windowContentHolder;
  background: rgba(255, 255, 0, 0.5);
  width: 200%;
  height: 200%;
  overflow: auto;
}

.content {
  background: rgba(255, 0, 0, 0.5);
}
<div class="gridContainer">
  <div class="gridItem">
    <div class="content">hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>
    </div>
  </div>
</div>

4 个答案:

答案 0 :(得分:11)

网格容器的高度固定为100px。

网格项的高度设置为200%。

网格项目存在于内部轨道中,而这些项目存在于容器内部

您可以将网格项视为位于容器下方两层的现有项目。

换一种说法,网格项目的父项是轨道,而不是容器。

由于行高既不是固定的,也不是长度的真实单位–设置为1fr –网格项目的百分比高度失败,可以根据需要随意扩展行(height: auto)。

无论您在容器上设置的固定高度是多少,在行上也要设置。

.gridContainer {
  border: thin solid black;
  background: rgba(255, 0, 0, 0.5);
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 100px;    /* adjustment; value was 1fr */
  width: 100px;
  height: 100px;
  grid-template-areas: 'windowContentHolder';
}

.gridItem {
  grid-area: windowContentHolder;
  background: rgba(255, 255, 0, 0.5);
  width: 200%;
  height: 200%;
  overflow: auto;
}

.content {
  background: rgba(255, 0, 0, 0.5);
}
<div class="gridContainer">
  <div class="gridItem">
    <div class="content">hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>
    </div>
  </div>
</div>

答案 1 :(得分:2)

首先,让我们开始定义百分比高度的工作方式:

  

指定百分比高度。百分比是用   尊重生成的框的包含块的高度。如果   未明确指定包含块的高度(即   取决于内容的高度),并且此元素不是绝对的   定位,该值将计算为“自动”。 red

很明显,需要显式指定元素的包含块。因此,我们需要确定包含块及其定义的高度

正如Michael_B所说,元素存在于容器内的 tracks 中,因此此处的包含块不再是容器,而是轨道。

  

网格跟踪是网格列或网格行的通用术语,换句话说,   换句话说,它是两条相邻的网格线之间的空间。每个网格   轨道分配有尺寸调整功能,该功能控制宽度或高度   列或行可能会增长,因此其边界网格会分开多远   线是。相邻的网格轨迹可以由装订线分隔,但可以   否则会紧紧包装。 ref

现在这些元素的大小如何?

  

声明网格的轨迹(行和列)并确定其大小   通过显式网格属性来显式地   将项目放置在显式网格之外时隐式创建。   网格简写及其子属性定义了   网格 ref

我们还可以在6.2. Grid Item Sizing,此处:6.6. Automatic Minimum Size of Grid Items和此处7.2. Explicit Track Sizing

上了解更多相关信息

嗯,所有这些规范都很难遵循,但是考虑到我的理解,这是我自己的解释:

首先由浏览器考虑内容和网格属性来计算轨道的大小,然后将该高度用作百分比值的参考。

这是另一个更好地显示正在发生的情况的示例:

.box {
  display: grid;
  height: 100px;
  width: 200px;
  grid-template-columns: 1fr 1fr;
  grid-gap:5px;
  background: red;
}

.box>div {
  background: rgba(0, 0, 0, 0.4);
  height: 200%;
}
<div class="box">
  <div class="first">
    lorem<br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br>
  </div>
  <div class="second">
    lorem<br> lorem
    <br> lorem
    <br> lorem
    <br>
  </div>
</div>

我们有一个包含display:grid和2列的容器,第一列比第二列包含更多的内容,并且我们对height:200%都应用了这两个容器,令人惊讶的是它们的高度都是内容高度的两倍。第一个!

如果我们检查devtools,我们可以看到:

enter image description here

虚线框定义了轨道的大小,其中内部有两个网格单元。由于是网格,因此轨道的高度将由最高的内容定义,这也将使两个单元具有相同的高度。因此height:200%并不完全是内容的高度,而是内容最初定义的轨道的高度。

这看起来不错,但是我们没有明确定义!所以问题是:为什么在规范中明确指出需要明确定义高度的地方,才考虑这个隐式高度?

如果我们再次检查Micheal_B的答案,则明确定义轨道高度将为我们提供相同的结果,但这将与之前的规范化保持一致:

.box {
  display: grid;
  height: 100px;/*this will not be considered*/
  width: 200px;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 150px;/* this will be considered*/
  grid-gap: 5px;
  background: red;
}

.box>div {
  background: rgba(0, 0, 0, 0.4);
  height: 200%;
}
<div class="box">
  <div class="first">
    lorem<br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br>
  </div>
  <div class="second">
    lorem<br> lorem
    <br> lorem
    <br> lorem
    <br>
  </div>
</div>

enter image description here

我们可以看到,我将轨道指定为150px,因此height:200%等于300px


这不是唯一的情况。我还发现了flexbox的另一种情况,我们可以使用百分比高度,而在包含块上没有任何明确的高度。

.container {
  height:200px;
  background:red;
  display:flex;
}
.box {
  width:100px;
  background:blue;
}

.box > div {
  background:yellow;
  height:50%;
}
<div class="container">
  <div class="box">
    <div></div>
  </div>
</div>

我们可以看到height:50%工作正常,将黄色框设为其父元素(蓝色框)的50%。

我自己的解释与flexbox的默认stretch behavior有关。默认情况下,弹性项目没有由内容定义的高度,但是其高度被拉伸以填充父容器的高度,因此浏览器将计算一个新的高度,该高度使子项的百分比值相对于该高度。 / p>

这是另一个显示与网格示例相似行为的示例:

.box {
  display: flex;
  width: 200px;
  background: red;
}

.box>div {
  background: rgba(0, 0, 0, 0.4);
}
.second >div {
  height:200%;
  background:yellow;
  width:50px;
}
<div class="box">
  <div class="first">
    lorem<br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br>
  </div>
  <div class="second">
    <div></div>
  </div>
</div>

父级的高度由最高的元素定义,second元素被拉伸到该高度,而黄色元素的高度是同一高度的两倍。

所以问题是:为什么要考虑浏览器计算的不依赖于内容且未明确定义的高度并将其用作百分比值的参考?

换句话说,我们拥有的逻辑是合理的,但是违反了针对百分比高度定义的规范,或者对 explicit 的解释是模棱两可的,可能因为我们已经将高度计算视为明确的,因为它们涉及比仅考虑内容高度更复杂的大小调整算法。

更新

这是另一个有趣的结果,考虑top属性。我们也知道top的百分比值还指元素包含块的高度,需要定义该高度。

这是一个例子:

.box {
  border:5px solid;
}
.box > div {
  position:relative;
  top:100%; 
  height:100px;
  background:red;
}
<div class="box">
  <div>This div won't move because the parent has no height specified</div>
</div>

<div class="box" style="height:100px;">
  <div>This div will move because the parent has a height specified</div>
</div>

现在,如果考虑以前的情况,top将可以像百分比一样使用百分比值。

使用CSS网格

.box {
  display: grid;
  height: 100px;/*this will not be considered*/
  width: 200px;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 150px;/* this will be considered*/
  grid-gap: 5px;
  background: red;
}

.box>div {
  position:relative;
  top:100%;
  background: rgba(0, 0, 0, 0.4);
  height: 200%;
}
<div class="box">
  <div class="first">
    lorem<br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br>
  </div>
  <div class="second">
    lorem<br> lorem
    <br> lorem
    <br> lorem
    <br>
  </div>
</div>
<div class="b">
  <div class="a">
  
  </div>
</div>

使用flexbox:

.box {
  display: flex;
  width: 200px;
  background: red;
}

.box>div {
  background: rgba(0, 0, 0, 0.4);
}
.second >div {
  position:relative;
  top:100%;
  height:200%;
  background:yellow;
  width:50px;
}
<div class="box">
  <div class="first">
    lorem<br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br> lorem
    <br>
  </div>
  <div class="second">
    <div></div>
  </div>
</div>

答案 2 :(得分:0)

正如BoltClock♦在评论线程中所说,询问者有兴趣了解这种行为,根据我的最佳解释可能是:

根据问题=>为什么/如何从孩子计算身高?

此处未根据孩子计算身高。 如果我们在下面引用:

根据规格:

5.2. Sizing Grid Containers

您将知道具有类“ .gridContainer”的div充当整个代码段的父包装,并且已对其应用 display:grid 。 在这种情况下,父对象的大小将取决于其最大内容大小。

设置大小后,类别为“ .gridItem”的div将根据其父项占用宽度和高度。因此,似乎不是从孩子那里计算出的身高,尽管并非如此。 可以从以下情况中最好地解释此行为:

1)

.gridContainer {
  border: thin solid black;
  background: rgba(255, 0, 0, 0.5);
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  width: 100px;
  height: 100px;
  grid-template-areas: 'windowContentHolder';
}

.gridItem {
  grid-area: windowContentHolder;
  background: rgba(255, 255, 0, 0.5);
  width: 200%;
  height: 200%;
  overflow: auto;
}

.content {
  background: rgba(255, 0, 0, 0.5);
}
<div class="gridContainer">
  <div class="gridItem">
    <div class="content">hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi 
    </div>
  </div>
</div>

2)

.gridContainer {
  border: thin solid black;
  background: rgba(255, 0, 0, 0.5);
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  width: 100px;
  height: 100px;
  grid-template-areas: 'windowContentHolder';
}

.gridItem {
  grid-area: windowContentHolder;
  background: rgba(255, 255, 0, 0.5);
  width: 200%;
  height: 200%;
  overflow: auto;
}

.content {
  background: rgba(255, 0, 0, 0.5);
}
<div class="gridContainer">
  <div class="gridItem">
    <div class="content">hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>
    </div>
  </div>
</div>

因此,可以从以上两种情况中推断出,网格大小是由其内容决定的。

答案 3 :(得分:-3)

.wrap {
  height: 100px;
  width: 100px;
}
.gridContainer {
  border: thin solid black;
  background: rgba(255, 0, 0, 0.5);
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 100%;
  width: 100%;
  height: 100%;
  grid-template-areas: 'windowContentHolder';
}

.gridItem {
  grid-area: windowContentHolder;
  background: rgba(255, 255, 0, 0.5);
  width: 200%;
  height: 200%;
  overflow: auto;
}

.content {
  background: rgba(255, 0, 0, 0.5);
}
<div class="wrap">
 <div class="gridContainer">
  <div class="gridItem">
   <div class="content">hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>hi<br/>
   </div>
  </div>
 </div>
</div>

您可以尝试将grid-template-rows设置为100%。这将使您的gridItem占据gridContainer的200%

这意味着gridContainer元素的父元素必须是一个块元素并具有指定的高度值。

grid-template-rows definition on MDN

中读取
  

(百分比)是相对于网格容器的块大小的非负值。

尝试将gridContainer包装在另一个div中,然后在其上设置height: 100px;。然后您可以在grid-template-rows: 100%;

中使用百分比值