CSS网格包裹布局

287

如何在不使用媒体查询的情况下实现CSS网格布局自动换行?

我的情况是,我有一个数量不确定的项目要放置在网格中,并希望该网格自动换行。使用Flexbox无法可靠地使物品间距美观。我也想避免使用大量的媒体查询。

这里是一些示例代码

.grid {
  display: grid;
  grid-gap: 10px;
  grid-auto-flow: column;
  grid-template-columns: 186px 186px 186px 186px;
}

.grid > * {
  background-color: green;
  height: 200px;
}
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

这里是一个 GIF 图像:

GIF image of what I'm seeing

作为一个小提示,如果有人能告诉我如何避免像我在grid-template-columns中那样指定所有项目的宽度,那就太好了。我更希望子元素指定自己的宽度。
6个回答

486
请使用auto-fillauto-fit作为repeat()符号的第一个参数。 <auto-repeat>变体是repeat()符号的一种形式:
repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )

auto-fill

当重复次数设置为auto-fill时,如果网格容器在相关轴上具有definite大小或最大大小,则重复次数是最大可能的正整数,不会导致网格溢出其网格容器。

https://www.w3.org/TR/css-grid-1/#valdef-repeat-auto-fill

.grid {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fill, 186px);
}

.grid>* {
  background-color: green;
  height: 200px;
}
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

网格将尽可能重复多个轨道,而不会溢出其容器。

Using auto-fill as the repetition number of the repeat() notation

在这种情况下,考虑以上例子(参见图片),只有5个轨道可以适应格子容器而不溢出。我们的网格中只有4个项目,因此第五个项目将作为空轨道创建在剩余空间内。
其余的剩余空间,轨道#6,结束了显式网格。这意味着没有足够的空间来放置另一个轨道。

auto-fit

auto-fit关键字与auto-fill相同,但在网格项目放置之后,任何空的重复轨道都会被折叠。

https://www.w3.org/TR/css-grid-1/#valdef-repeat-auto-fit

.grid {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fit, 186px);
}

.grid>* {
  background-color: green;
  height: 200px;
}
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

网格仍会尽可能重复尽可能多的轨道,而不会溢出其容器,但是空轨道将被折叠到0
折叠的轨道被视为具有固定的轨道大小函数0px

Using auto-fit as the repetition number of the repeat() notation

与“自动填充”图像示例不同,空的第五个轨道被折叠,将显式网格限制在第4个项目之后。

auto-fillauto-fit

两者的区别在使用minmax()函数时会有所体现。

使用minmax(186px, 1fr)将项目从186px网格容器中剩余空间的一部分进行范围排列。

当使用auto-fill时,项目将随着空轨道的增加而增长。

.grid {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));
}

.grid>* {
  background-color: green;
  height: 200px;
}
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

使用auto-fit时,项目将会增长以填充剩余空间,因为所有空轨道都将被折叠到0px

.grid {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(186px, 1fr));
}

.grid>* {
  background-color: green;
  height: 200px;
}
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>


游乐场:

CodePen

检查自动填充轨道

auto-fill


检查自适应跟踪

auto-fit


13
有没有办法让它居中显示下一行的内容? - kentcdodds
7
和使用 flex 布局一样,在 display: grid 元素上使用 justify-content: center - Spittal
3
亲爱的@ Ricky,如何使minmax的第一个属性(例如repeat(auto-fill,minmax(186px,1fr));)不是像素,而是与div内的文本长度一样? - mesqueeb
3
@mesqueeb,这是不可能的,需要一个明确的大小。您可以查看此答案以获取更多详细信息:https://dev59.com/o1cO5IYBdhLWcg3wtz_1#45334006。 - Ricky Ruiz
2
有没有办法让它在需要换行时,两个项目下移而不仅仅是一个?所以像从4到2到1,而不是从4到3到2到1? - sammiepls
显示剩余8条评论

24

你需要在 repeat() 函数内使用 auto-fitauto-fill

grid-template-columns: repeat(auto-fit, 186px);

如果您还使用minmax()允许灵活的列大小,则两者之间的差异变得明显:

grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));

这允许您的列大小灵活变化,从186像素到跨越容器全宽度的等宽列。 auto-fill会创建尽可能多的列以适应宽度。例如,即使只有四个网格项,但如果可以放下五列,则会产生第五个空列:

输入图像描述

改用auto-fit将避免产生空列,并在必要时进一步拉伸:

输入图像描述


我该如何做到与“从186像素到等宽列”的完全相反 - 即我希望它自动适应等宽列,范围最多为186像素宽的列? - Ned Martin

16

您可能在寻找自动填充

grid-template-columns: repeat(auto-fill, 186px);

演示:http://codepen.io/alanbuchanan/pen/wJRMox

要更有效地利用可用空间,您可以使用minmax,并将auto作为第二个参数传入:

grid-template-columns: repeat(auto-fill, minmax(186px, auto));

示例:http://codepen.io/alanbuchanan/pen/jBXWLR

如果您不想要空列,则可以使用auto-fit而不是auto-fill


2
有没有办法让它居中显示下一行的内容? - kentcdodds

2

我遇到了类似的情况。除了你所做的之外,我还想将我的列居中在容器中,同时不允许空的列出现在左侧或右侧:

最初的回答:

.grid { 
    display: grid;
    grid-gap: 10px;
    justify-content: center;
    grid-template-columns: repeat(auto-fit, minmax(200px, auto));
}

关于“while not allowing empty columns to for them”:您是指“同时不允许它们有空列(也不允许)”吗?还是“同时不允许它们有空列”(没有“to”)?或者其他什么(这似乎不符合逻辑)? - Peter Mortensen

1
这是一个常见的日历示例,具有许多元素的布局。我在CSS中使用grid-template-columns: repeat(7, 1.5em);将一周的7天显示在all-days中,然后只需在每个all-days的开头放置正确数量的空白。 我将它设置为4个“假月份”,因为更多的话只会增加多余的HTML。

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

.actions {
  display: flex;
  gap: 1em;
}

.calendar-container {
  display: grid;
  grid-gap: 0.5em;
  grid-template-columns: repeat(auto-fill, 13em);
  justify-content: center;
}

.calendar-month {
  display: grid;
  grid-gap: 0.25em;
  grid-template-columns: repeat(auto-fill, 1fr);
  grid-template-rows: 1.5em;
  border: solid 1px green;
  place-items: center;
}

.calendar-month .all-days {
  display: grid;
  grid-template-columns: repeat(7, 1.5em);
  grid-gap: 0.25em;
  place-items: center;
}

.no {
  text-align: center;
  display: block;
  width: 1.5em;
  background: lightgreen;
}
<div class="parent-container">
  <div class="calendar-container">
    <div class="calendar-month">
      <div class="actions">
        <button>Next</button>
        <span>January</span> <button>Last</button>
      </div>
      <div class="all-days">
        <span class="no">1</span>
        <span class="no">2</span>
        <span class="no">3</span>
        <span class="no">4</span>
        <span class="no">5</span>
        <span class="no">6</span>
        <span class="no">7</span>
        <span class="no">8</span>
        <span class="no">9</span>
        <span class="no">10</span>
        <span class="no">11</span>
        <span class="no">12</span>
        <span class="no">13</span>
        <span class="no">14</span>
        <span class="no">15</span>
        <span class="no">16</span>
        <span class="no">17</span>
        <span class="no">18</span>
        <span class="no">19</span>
        <span class="no">20</span>
        <span class="no">21</span>
        <span class="no">22</span>
        <span class="no">23</span>
        <span class="no">24</span>
        <span class="no">25</span>
        <span class="no">26</span>
        <span class="no">27</span>
        <span class="no">29</span>
        <span class="no">30</span>
        <span class="no">31</span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
      </div>
    </div>
    <div class="calendar-month">
      <div class="actions">
        <span>February</span>
      </div>
      <div class="all-days">
        <span class="no"></span>
        <span class="no"></span>
        <span class="no">1</span>
        <span class="no">2</span>
        <span class="no">3</span>
        <span class="no">4</span>
        <span class="no">5</span>
        <span class="no">6</span>
        <span class="no">7</span>
        <span class="no">8</span>
        <span class="no">9</span>
        <span class="no">10</span>
        <span class="no">11</span>
        <span class="no">12</span>
        <span class="no">16</span>
        <span class="no">13</span>
        <span class="no">14</span>
        <span class="no">15</span>
        <span class="no">16</span>
        <span class="no">17</span>
        <span class="no">18</span>
        <span class="no">19</span>
        <span class="no">20</span>
        <span class="no">21</span>
        <span class="no">22</span>
        <span class="no">23</span>
        <span class="no">24</span>
        <span class="no">25</span>
        <span class="no">26</span>
        <span class="no">27</span>
        <span class="no">28</span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
      </div>
    </div>
    <div class="calendar-month">
      <div class="actions">
        <span>Bearanary</span>
      </div>
      <div class="all-days">
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no">1</span>
        <span class="no">2</span>
        <span class="no">3</span>
        <span class="no">4</span>
        <span class="no">6</span>
        <span class="no">7</span>
        <span class="no">8</span>
        <span class="no">9</span>
        <span class="no">10</span>
        <span class="no">11</span>
        <span class="no">12</span>
        <span class="no">13</span>
        <span class="no">14</span>
        <span class="no">15</span>
        <span class="no">16</span>
        <span class="no">17</span>
        <span class="no">18</span>
        <span class="no">19</span>
        <span class="no">20</span>
        <span class="no">21</span>
        <span class="no">22</span>
        <span class="no">23</span>
        <span class="no">24</span>
        <span class="no">25</span>
        <span class="no">26</span>
        <span class="no">27</span>
        <span class="no">29</span>
        <span class="no">30</span>
        <span class="no">31</span>
      </div>
    </div>
    <div class="calendar-month">
      <div class="actions">
        <span>Fishly</span>
      </div>
      <div class="all-days">
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no">1</span>
        <span class="no">2</span>
        <span class="no">3</span>
        <span class="no">4</span>
        <span class="no">6</span>
        <span class="no">7</span>
        <span class="no">8</span>
        <span class="no">9</span>
        <span class="no">10</span>
        <span class="no">11</span>
        <span class="no">12</span>
        <span class="no">13</span>
        <span class="no">14</span>
        <span class="no">15</span>
        <span class="no">16</span>
        <span class="no">17</span>
        <span class="no">18</span>
        <span class="no">19</span>
        <span class="no">20</span>
        <span class="no">21</span>
        <span class="no">22</span>
        <span class="no">23</span>
        <span class="no">24</span>
        <span class="no">25</span>
        <span class="no">26</span>
        <span class="no">27</span>
        <span class="no">29</span>
        <span class="no">30</span>
      </div>
    </div>
  </div>
</div>


-4

这是我的尝试。请原谅我多余的话语,我当时感觉特别有创意。

我的方法是使用一个具有固定尺寸的父级div。其余的只是相应地将内容适配到该

中。

这将重新调整图像大小,而不考虑其宽高比。也不会有硬裁剪

body {
    background: #131418;
    text-align: center;
    margin: 0 auto;
}

.my-image-parent {
    display: inline-block;
    width: 300px;
    height: 300px;
    line-height: 300px; /* Should match your div height */
    text-align: center;
    font-size: 0;
}

/* Start demonstration background fluff */
    .bg1 {background: url(https://unsplash.it/801/799);}
    .bg2 {background: url(https://unsplash.it/799/800);}
    .bg3 {background: url(https://unsplash.it/800/799);}
    .bg4 {background: url(https://unsplash.it/801/801);}
    .bg5 {background: url(https://unsplash.it/802/800);}
    .bg6 {background: url(https://unsplash.it/800/802);}
    .bg7 {background: url(https://unsplash.it/802/802);}
    .bg8 {background: url(https://unsplash.it/803/800);}
    .bg9 {background: url(https://unsplash.it/800/803);}
    .bg10 {background: url(https://unsplash.it/803/803);}
    .bg11 {background: url(https://unsplash.it/803/799);}
    .bg12 {background: url(https://unsplash.it/799/803);}
    .bg13 {background: url(https://unsplash.it/806/799);}
    .bg14 {background: url(https://unsplash.it/805/799);}
    .bg15 {background: url(https://unsplash.it/798/804);}
    .bg16 {background: url(https://unsplash.it/804/799);}
    .bg17 {background: url(https://unsplash.it/804/804);}
    .bg18 {background: url(https://unsplash.it/799/804);}
    .bg19 {background: url(https://unsplash.it/798/803);}
    .bg20 {background: url(https://unsplash.it/803/797);}
/* end demonstration background fluff */

.my-image {
    width: auto;
    height: 100%;
    vertical-align: middle;
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
}
<div class="my-image-parent">
    <div class="my-image bg1"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg2"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg3"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg4"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg5"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg6"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg7"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg8"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg9"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg10"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg11"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg12"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg13"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg14"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg15"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg16"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg17"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg18"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg19"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg20"></div>
</div>


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