有没有“子网格”功能,可以定位网格容器的“孙子元素”?

26

所有关于CSS Grid的指南似乎都暗示了一种结构,即在网格中定位的元素是网格元素本身的直接子元素:

<div class="wrapper">
  <div>A</div>
  <div>B</div>
</div>

.wrapper 具有 display: grid 和对于 grid 属性的定义。

如果我想要将一个作为网格的“孙元素”定位在网格本身上(而不是依赖其父元素),这样做有意义吗?

<div class="wrapper">
  <div>A</div>
  <div>
    <div>B</div>
    <div>C</div>
  </div>
</div>

我希望将A, BC分别放在网格的不同行中,这样做有意义吗?


5
这个说法很有道理,但是当前的网格实现不允许这样做:(。这是一个众所周知的限制。曾经有过提出子网格解决它的方案,但由于难以实现,因此被推迟到未来的 CSS Grid Level 2 规范中。在某种程度上,可以通过为应该放置在网格中的子元素使用 display: contents 来解决它,但目前仅受到 Firefox、WebKit TP 和 Chrome 标志后面支持。 - Ilya Streltsyn
@IlyaStreltsyn 这是一个答案,我会发布它。这是类似问题的良好标记。 - Paulie_D
1
@IlyaStreltsyn 我也会接受这个答案。 "在网格中,只有直接子元素才是网格项,并且可以在网格上定位。"(igalia文章中的一行)是我希望在每个关于网格的指南的顶部以红色印刷的内容。 叹气 - phtrivier
2个回答

11

display: subgrid

来自CSS Grid Level 2草案规范

2.网格容器

子网格提供了通过嵌套元素传递网格参数,并将基于内容的大小信息传回其父网格的能力。

如果元素是网格项(即它处于流中且其父级是网格容器),则display: subgrid使该元素成为子网格(这是一种特殊类型的网格容器框),因此忽略其grid-template-*grid-*-gap属性,而采用跨度的父网格轨道。

3.子网格

网格项本身可以通过给它display: grid来成为网格容器。在这种情况下,其内容的布局将独立于其参与的网格的布局。

在某些情况下,可能需要多个网格项的内容相互对齐。一个作为网格项的网格容器可以通过使用display: subgrid推迟其行和列的定义到其父网格容器中,从而使其成为子网格。

在这种情况下,子网格的网格项参与调整父网格容器的网格大小,使两个网格的内容对齐。了解更多

此功能尚未在主要浏览器中实现。不知道它何时会被实现。

在网格中,只有容器的流动子元素变成网格项并接受网格属性。

在网格项上使用display: subgrid,项目的子元素将遵循容器的线条。

根据Grid Level 1规范display: subgrid已推迟到Level 2

目前,在网格项(即嵌套网格容器)上使用display: grid可能在某些情况下很有用。

另一种可能的解决方法是display: contents。该方法在此处解释:

更多信息:


温馨提示:以上链接涉及技术内容。

除了“display: subgrid”部分外,我接受这个意味着“不,目前还不可能”的说法 :) - phtrivier
5
Subgrid 现在已经在 Firefox 69+ 中实现。不过其他浏览器还没有,所以目前还不能使用。 - W Biggs
截至今天,subgrid 已在 Safari 16.0+ 中得到支持,并且 目前仍在 Chrome 的开发阶段 - Sigurd Mazanti

8

由于截至本回答撰写时,除最新的Firefox v71外的其他浏览器都不支持子网格Subgrids,即使其他浏览器开始支持它,用户使用旧版浏览器仍将被落下,至少需要等一年时间,直到足够多的用户升级浏览器以便能够使用这样的新功能。

我已经想出了一种方法,可以对祖先网格上的嵌套深度网格元素进行对齐:

从其实质上讲,此解决方案是关于将display: contents应用于网格所有嵌套元素,直到希望作为网格项使用的元素,这实际上做了一个反向继承,因此每个设置为{{display:contents}}的元素实际上是投射其子元素的显示,因此最终深度嵌套的元素会被视为直接是.container元素的子元素。

.container {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  max-width: 500px;
  margin: auto;
}

.container div{
  display: contents; /* <-- makes the div elements "transparent" to the grid */
}

input{ height: 40px; }
label{ align-self: center; }
<div class="container">
  <div>
    <div>
      <div>
        <label contenteditable>very long label</label>
        <input>
      </div>
    </div>
  </div>
  <div>
    <div>
      <div>
        <label contenteditable>short</label>
        <input>
      </div>
    </div>
  </div>
</div>

浏览器会将此视为:

<div class="container">
  <label contenteditable>very long label</label>
  <input>
  <label contenteditable>short</label>
  <input>
</div>

在上面的示例中,标签是可编辑的,以展示网格轨道的动态特性,因此所有网格项都对齐。

Codepen演示


这对于在React中与循环一起使用时满足特定的网格布局非常有用。如果设计要求每个列表项输出多个元素,但仍然保持与网格对齐,不幸的是,React会要求为每个项添加额外的容器,因为每个子元素都需要一个唯一的键。React所需的额外容器会导致子元素无法对齐,但这个问题可以通过使用这个解决。谢谢! - Chris McDonald
1
我不明白"extra item"是什么意思。为什么React会"需要"那个?作为一个React专家,除非你在JSX迭代中返回原始字符串,否则你根本不需要任何额外的容器。 - vsync
我已经习惯了 React Fragments 的简写,以至于忘记了我们可以在实际的 Fragment 组件上设置一个键(key)如果我们导入它。你对此提出异议让我记起了这一点。谢谢你。 - Chris McDonald

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