为什么我的Grid元素的高度没有正确计算?

Rob*_*bie 10 html css 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%;
}

.content {
  background: rgba(255, 0, 0, 0.5);
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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

似乎百分比正在考虑子高度而不是父高度,因为如果我们仔细检查元素,我们将看到它的高度是子元素高度的两倍.

在此输入图像描述

带有'hi'的元素没有像预期的那样溢出.更改gridContainer为'block'确实可以正常工作,但不能使用'grid':

.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);
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

Mic*_*l_B 12

网格容器的高度固定为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);
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

  • @Temani Afif:对不起,我一无所获.但是,Michael_B的声明对应于将网格项的包含块定义为它们布局的网格区域的规范,而不是网格容器.但需要熟悉该规范第6.6和11.1节的人才能理解网格项目和区域的大小.至关重要的是,在这种情况下,它们的尺寸是明确的还是无限的.如果存在循环依赖,现在这[现在](https://drafts.c​​sswg.org/css-sizing-3/#percentage-sizing)解决了这个问题(这意味着它不再是未定义的,我有一个答案的谜团更新...). (4认同)

Tem*_*fif 6

新答案

终于找到了对这种行为的逻辑解释。

首先,我们需要了解它的行为1fr等于minmax(auto,1fr)并且如本问题所述,它将默认为最小内容,这就是为什么我们的网格区域大于定义的height:100px

如果我们将其替换为minmax(0,1fr)将使我们的网格面积等于容器高度,那么我们的项目仍然会大两倍。

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

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

.content {
  background: rgba(255, 0, 0, 0.5);
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

对于第二个行为 (the height:200%),我们需要参考规范我们可以阅读:

一旦确定了每个网格区域的大小,网格项目就会被布置到它们各自的包含块中。为此目的,网格区域的宽度和高度被认为是确定的。

所以网格区域首先是根据内容定义的,如果我们使用,1fr或者根据容器的高度,如果我们使用minmax(0,1fr)。然后将该高度用作我们百分比高度的参考。

这就是为什么在所有情况下,网格项最终会比网格区域大两倍,而在您的情况下,内容定义了该高度。


旧答案

首先,让我们从定义百分比高度的工作原理开始:

指定百分比高度。百分比是相对于生成的框的包含块的高度计算。如果未明确指定包含块的高度(即,它取决于内容高度),并且该元素不是绝对定位的,则该值计算为 'auto'。参考

规范中还有另一部分处理百分比值和周期:

有时,百分比大小的框的包含块的大小取决于框本身的内在大小贡献,从而产生循环依赖。在计算这样一个盒子的内在大小贡献时,一个循环百分比——也就是说,一个百分比值将解决一个包含块大小,它本身取决于该百分比——是专门解决的...... (然后是很多规则)

在某些特定情况下,即使未明确指定包含块的高度,浏览器也能够解析百分比值。


正如 Michael_B 所说,元素存在于容器内的轨道内,所以这里的包含块不再是容器而是轨道

网格轨道是网格列或网格行的通称——换句话说,它是两条相邻网格线之间的空间。每个网格轨道都分配了一个大小函数,该函数控制列或行可以增长的宽度或高度,从而控制其边界网格线相距多远。相邻的网格轨道可以被排水沟隔开,但否则会紧紧地挤在一起。参考

这些元素的大小如何?

网格的轨道(行和列)通过显式网格属性显式声明和调整大小,或者在项目放置在显式网格之外时隐式创建。grid 简写及其子属性定义了 grid ref的参数

我们还可以在此处阅读更多信息:6.2。网格项目大小调整,这里:6.6。网格项目的自动最小尺寸和这里7.2。显式轨道大小


所有这些规范都很难遵循,所以这里是我自己的简化解释,以了解正在发生的事情。

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

这是另一个示例,可以更好地显示正在发生的事情:

.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%;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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

如果我们检查开发工具,我们可以看到:

在此处输入图片说明

虚线框定义了我们的轨道大小,里面有两个网格单元。由于它是一个网格,轨道的高度将由最高的内容定义,这也将使两个单元格具有相同的高度。所以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%;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

正如我们所看到的,我指定了轨道,150px因此height:200%等于300px


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

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

.box > div {
  background:yellow;
  height:50%;
}
Run Code Online (Sandbox Code Playgroud)
<div class="container">
  <div class="box">
    <div></div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的 height:50%,工作正常,使黄色框占其父元素(蓝色框)的 50%。

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

如果 flex 项目有align-self: stretch,重做其内容的布局,将此使用的大小视为其确定的交叉大小,以便可以解析百分比大小的子项。参考

这是另一个示例,显示了网格示例的类似行为:

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

.box>div {
  background: rgba(0, 0, 0, 0.4);
}
.second >div {
  height:200%;
  background:yellow;
  width:50px;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

父元素的高度由最高的元素定义,即 second元素被拉伸到那个高度,黄色元素的高度是相同高度的两倍。

换句话说,我们所拥有的在某种程度上是合乎逻辑的,因为即使我们没有指定明确的高度,浏览器也能够首先计算包含块的高度,然后使用计算值解析百分比。

更新

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

这是一个插图:

.box {
  border:5px solid;
}
.box > div {
  position:relative;
  top:100%; 
  height:100px;
  background:red;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

现在如果我们考虑我们之前的案例, top将使用百分比值,例如 height 正在做的事情。

使用 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%;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

使用弹性盒:

.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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)