具有 CSS 网格布局的网格项内元素的高度相等

Equal height of elements inside grid item with CSS grid layout

我在长度超过 4 的 div 中有一系列文章,没有任何舍入行标记。我需要将其表示为每行 3 篇文章(列)的 table,可能 display: grid。每篇文章都有一个 header、一个部分和一个页脚。

如何在每行文章中为每个 header 实现等高、每个部分的等高以及与文章底部对齐的等高页脚?有可能吗?我应该使用 display: table 吗?

PS 我需要根据屏幕宽度动态更改每行的文章数。谢谢

HTML:

body {
  width: 100%;
  max-width: 1024px;
  margin: auto;
}

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.container article {
  display: grid;
}

article header {
  background-color: #eeeeee;
}

article section {
  background-color: #cccccc;
}

article footer {
  background-color: #dddddd;
}
<div class="container">
  <article>
    <header>
      <h2>Header</h2>
      <h2>Header</h2>
    </header>
    <section>
      <p>Content</p>
    </section>
    <footer>
      <p>Footer</p>
    </footer>
  </article>
  <article>
    <header>
      <h2>Header</h2>
    </header>
    <section>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
    </section>
    <footer>
      <p>Footer</p>
      <p>Footer</p>
    </footer>
  </article>
  <article>
    <header>
      <h2>Header</h2>
    </header>
    <section>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
    </section>
    <footer>
      <p>Footer</p>
    </footer>
  </article>
  <article>
    <header>
      <h2>Header</h2>
    </header>
    <section>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
    </section>
    <footer>
      <p>Footer</p>
      <p>Footer</p>
    </footer>
  </article>
</div>

注意:JS 已弃用。

https://codepen.io/yudnikov/pen/mBvbGW?editors=1100#0

:

grid-auto-rows: 1fr; 

已被建议为重复项,但事实并非如此。它只会给文章相等的高度,而例如每篇文章的 header 大小保持不同。

我最初有这个问题:

grid-auto-rows: 1fr 解决方案的结果是:

Is it even possible?

tldr;是的。

Codepen Demo #1

Codepen Demo # 2(使用 SASS 并且是可配置的)


这里的困难在于每篇文章本身就是一个网格,因此任何一篇文章都不知道另一篇文章。因此,像header这样的一篇文章的组件无法根据另一篇文章中的header的高度进行调整。

实际上有一种方法可以在不更改任何标记的情况下使用 css 网格实现这一目标!

我们可以 'flatten' 具有 CSS 的结构,这样所有文章的所有组件都只是一个 CSS 网格的一部分 - 文章容器。

通过使用 display: contents

设置文章,甚至无需更改当前标记即可实现这一点

display: contents (caniuse)

来自 Caniuse:

display: contents causes an element's children to appear as if they were direct children of the element's parent, ignoring the element itself. This can be useful when a wrapper element should be ignored when using CSS grid or similar layout techniques.

因此,如果我们将文章设置为 display: contents

.container article {
  display: contents;
}

现在所有 header、部分和页脚都变成(直接)网格项(容器的 - 具有 display:grid),我们可以使用 grid-template-areas 属性.

.container {
  display: grid;
  grid-column-gap: 1em; /* horizontal gap between articles */
  grid-template-columns: repeat(3, 1fr);

  grid-template-areas: "header1 header2 header3" 
                       "section1 section2 section3"
                       "footer1 footer2 footer3"
                       "header4 header5 header6" 
                       "section4 section5 section6"
                       "footer4 footer5 footer6"
}

由于每个 header/section/footer 正好占据一个单元格 - 这迫使它们占据 相同的垂直高度 。所以例如header1、header2 和 header3 无论内容如何,​​都将具有相同的高度。

现在为每个单元格设置 grid-area 属性。

article:nth-child(1) header {
  grid-area: header1;
}
article:nth-child(2) header {
  grid-area: header2;
}
article:nth-child(3) header {
  grid-area: header3;
}
article:nth-child(4) header {
  grid-area: header4;
}
article:nth-child(1) section {
  grid-area: section1;
}
...
article:nth-child(4) section {
  grid-area: section4;
}
article:nth-child(1) footer {
  grid-area: footer1;
}
...
article:nth-child(4) footer {
  grid-area: footer4;
}

最后,设置每行文章之间的垂直间距(从第二行文章开始):

article:nth-child(n + 4) header {
  margin-top: 1em;
}

演示:

body {
  width: 100%;
  max-width: 1024px;
  margin: auto;
}

.container {
  display: grid;
  grid-column-gap: 1em;
  grid-template-columns: repeat(3, 1fr);
  grid-template-areas: "header1 header2 header3" 
                      "section1 section2 section3"
                        "footer1 footer2 footer3"
                        "header4 header5 header6" 
                      "section4 section5 section6"
                        "footer4 footer5 footer6"
}

.container article {
  display: contents;
}

article header {
  background-color: #eeeeee;
}

article section {
  background-color: #cccccc;
}

article footer {
  background-color: #dddddd;
}

article:nth-child(n + 4) header {
  margin-top: 1em;
}

article:nth-child(1) header {
  grid-area: header1;
}
article:nth-child(2) header {
  grid-area: header2;
}
article:nth-child(3) header {
  grid-area: header3;
}
article:nth-child(4) header {
  grid-area: header4;
}
article:nth-child(1) section {
  grid-area: section1;
}
article:nth-child(2) section {
  grid-area: section2;
}
article:nth-child(3) section {
  grid-area: section3;
}
article:nth-child(4) section {
  grid-area: section4;
}
article:nth-child(1) footer {
  grid-area: footer1;
}
article:nth-child(2) footer {
  grid-area: footer2;
}
article:nth-child(3) footer {
  grid-area: footer3;
}
article:nth-child(4) footer {
  grid-area: footer4;
}
<div class="container">
    <article>
        <header>
            <h2>Header</h2>
            <h2>Header</h2>
        </header>
        <section>
            <p>Content</p>
        </section>
        <footer>
            <p>Footer</p>
        </footer>
    </article>
    <article>
        <header>
            <h2>Header</h2>
        </header>
        <section>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
        </section>
        <footer>
            <p>Footer</p>
            <p>Footer</p>
        </footer>
    </article>
    <article>
        <header>
            <h2>Header</h2>
        </header>
        <section>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
        </section>
        <footer>
            <p>Footer</p>
        </footer>
    </article>
    <article>
        <header>
            <h2>Header</h2>
        </header>
        <section>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
        </section>
        <footer>
            <p>Footer</p>
            <p>Footer</p>
        </footer>
    </article>
</div>

Codepen Demo)

当然,我们可以使用 grid-row + grid-column 属性来代替 grid-template-areas + grid-area 属性来获得相同的结果 - Codepen demo


注意:我确实意识到上面的内容很冗长,并不是最佳解决方案 - 但我的意思是这是可能的.另外,we could use SASS loops to make that code much cleaner and also configurable.

如果有某种方法可以使用 grid-template-areas 重复一个模式 可能会更好 - 例如:

pseudo-code(不合法):

grid-template-areas: repeat("header1 header2 header3" 
                           "section1 section2 section3"
                           "footer1 footer2 footer3")

...然后我们可以获得更动态的解决方案,该解决方案适用于 n 文章解决方案,方法是使用 nth-child 设置 grid-area,例如:

article:nth-child(3n + 1) header {
  grid-area: header1;
} 

等...但我认为目前这不可能(或者可能没有必要,因为 subgrids 能够做到这一点?)


注意:

Grid Layout Module Level 2 引入了 Subgrids 这将使这个问题更容易解决并且不必使用 display: contents


Should I use display: table?

对于您需要的布局 - display:table 帮不上什么忙。首先,您必须完全重组您的标记以将 文章组件 组合在一起作为文章,您必须四处寻找 table 的样式以使其看起来像 'articles' 但即便如此 - tables 也不会换行,所以你需要将每三篇文章换行到一个单独的 table 中......即使可能也会很乱并且难以维护。

我想到的最简单的想法是使用百分比。例如:

.container{
    width: 30%;
    height: 80%;
}

要完全控制您的布局,请检查 CSS 默认值参考:

https://www.w3schools.com/cssref/css_default_values.asp

对于不同的设备,只需使用单独的 CSS 个文件…