Remove wide gaps in CSS Grid

2020-07-06 05:38发布

I made a design using css grids which gave me unexpected space between rows. I reproduced my issue with the following code:

main {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}
article {
  background: red;
}
.item1 {
  height: 30px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 1;
  grid-row-end: 2;
}
.item2 {
  height: 100px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 2;
  grid-row-end: 3;
}
.item3 {
  height: 300px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 3;
  grid-row-end: 4;
}
.item4 {
  height: 490px;
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 5;
}
.item5 {
  height: 160px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 4;
  grid-row-end: 6;
}
.item6 {
  height: 520px;
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 5;
  grid-row-end: 7;
}
.item7 {
  height: 300px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 6;
  grid-row-end: 7;
}
<main>
  <article class="item1"></article>
  <article class="item2"></article>
  <article class="item3"></article>
  <article class="item4"></article>
  <article class="item5"></article>
  <article class="item6"></article>
  <article class="item7"></article>
</main>

Here you can see extra gap on top of the bottom items.

I found a similar question -- Why does CSS Grid layout add extra gaps between cells? -- where the extra gap was caused by figures and solved using display: flex on the figures, but that didn't work for me.

Any idea?


EDIT:

My example was misleading, here is a closer-to-the-real-problem version:

main {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}
article {
  background: red;
}
article div {
  background: blue;
}
.item1 {
  grid-column-start: 1;
  grid-column-end: span 1;
  grid-row-start: 1;
  grid-row-end: span 1;
}
.item1 div {
  height: 30px;
}
.item2 {
  grid-column-start: 1;
  grid-column-end: span 1;
  grid-row-start: 2;
  grid-row-end: span 1;
}
.item2 div {
  height: 100px;
}
.item3 {
  grid-column-start: 1;
  grid-column-end: span 1;
  grid-row-start: 3;
  grid-row-end: span 1;
}
.item3 div {
  height: 300px;
}
.item4 {
  grid-column-start: 2;
  grid-column-end: span 1;
  grid-row-start: 1;
  grid-row-end: span 4;
}
.item4 div {
  height: 490px;
}
.item5 {
  grid-column-start: 1;
  grid-column-end: span 1;
  grid-row-start: 4;
  grid-row-end: span 2;
}
.item5 div {
  height: 160px;
}
.item6 {
  grid-column-start: 2;
  grid-column-end: span 1;
  grid-row-start: 5;
  grid-row-end: span 2;
}
.item6 div {
  height: 520px;
}
.item7 {
  grid-column-start: 1;
  grid-column-end: span 1;
  grid-row-start: 6;
  grid-row-end: span 1;
}
.item7 div {
  height: 300px;
}
<main>
  <article class="item1"><div></div></article>
  <article class="item2"><div></div></article>
  <article class="item3"><div></div></article>
  <article class="item4"><div></div></article>
  <article class="item5"><div></div></article>
  <article class="item6"><div></div></article>
  <article class="item7"><div></div></article>
</main>

Here you can see extra gap in red. The heights on the contained div are just here to simulate the real content of the articles, so they can't be modified in the real example (they are left to default in the real code). Based on the pre-edit answers, I tried grid-auto-rows property, but it didn't solve the problem.

3条回答
Luminary・发光体
2楼-- · 2020-07-06 06:21

You have a grid container with three explicit columns and 10px gutters:

main {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}

There are no rows defined. All rows are implicit and take content height (because a default setting of a grid container is grid-auto-rows: auto).

Inside this container are seven grid items that are positioned using line-based placement.

Let's break this down to individual pieces.


Item 1

.item1 {
    height: 30px;
    grid-column-start: 1;
    grid-column-end: 2;
    grid-row-start: 1;
    grid-row-end: 2;
}

enter image description here

Simple enough. Item 1 spans across the first column and first row. It is 30px in height, which sets the row height.


Item 2

.item2 {
    height: 100px;
    grid-column-start: 1;
    grid-column-end: 2;
    grid-row-start: 2;
    grid-row-end: 3;
}

enter image description here

Again, pretty straightforward. Item 2 spans across the first column and second row. It is 100px in height, which sets the row height.


Item 3

.item3 {
    height: 300px;
    grid-column-start: 1;
    grid-column-end: 2;
    grid-row-start: 3;
    grid-row-end: 4;
}

enter image description here

Like the two items above, Item 3 is clear and simple. It spans across the first column and third row. It is 300px in height, which sets the row height.

Now it starts to get a bit tricky...


Item 4

.item4 {
    height: 490px;
    grid-column-start: 2;
    grid-column-end: 3;
    grid-row-start: 1;
    grid-row-end: 5;
}

enter image description here

Item 4 is set to span a total of four rows:

grid-row-start: 1 / grid-row-end: 5

It has a height of 490px.

But items 1, 2 & 3 are set to span a total of three rows:

grid-row-start: 1 / grid-row-end: 4

...and their total height is: 430px (30px + 100px + 300px)

Therefore, Item 4 creates a new row with a height of 30px (490px - 430px - 30px grid row gaps).


Item 5

.item5 {
    height: 160px;
    grid-column-start: 1;
    grid-column-end: 2;
    grid-row-start: 4;
    grid-row-end: 6;
}

enter image description here

Item 5 has a height of 160px and is set to span two rows. It starts at the fourth row (which was created by Item 4) and creates a new fifth row.

Because row heights are set to auto, each row receives an equal distribution of the height of the grid item, as defined in the spec for grid areas that cover multiple tracks. This makes rows 4 and 5 each 80px tall.

Important: Notice how Item 5 equal height rows expand row 4, which is now spaced away from its original position at the bottom of Item 4. The first gap has been created.


Item 6

.item6 {
    height: 520px;
    grid-column-start: 2;
    grid-column-end: 3;
    grid-row-start: 5;
    grid-row-end: 7;
}

enter image description here

Item 6 is set to start at row 5. As explained above (see Important), row 5 can no longer be fitted to Item 4 because of grid-auto-rows: auto on the Item 5 grid area. This results in a 50px gap above Item 6.

80px height of row 4 - 30px excess of Item 4 = 50px

But now Item 6 adds to the 80px height of row 5 created by Item 5. The second gap has been created.


Item 7

.item7 {
    height: 300px;
    grid-column-start: 1;
    grid-column-end: 2;
    grid-row-start: 6;
    grid-row-end: 7;
}

enter image description here

The height of the last two rows is determined by the following three factors:

  • the height of Item 5, which is 80px in row 5
  • the height of Item 6, which is 520px, which combines with the height of row 5 and spans two rows
  • the height of Item 7, which is 300px and spans 1 row

For the same reason that grid row line 5 is spaced away from Item 4, grid row line 6 spaces away from Item 5: The auto row height is distributing the height of Item 6 among the rows it covers.


One Solution

Instead of setting heights to Grid Items, consider setting grid-auto-rows to something like 10px. Then use the span keyword to created the grid areas you want.

So instead of this...

main {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}

.item5 {
  height: 160px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 4;
  grid-row-end: 6;
}

consider this:

main {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 10px; /* new */
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}

.item5 {
  /* height: 160px; */
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 4;     /* this would have to be adjusted, as well */
  grid-row-end: span 16; /* new */
}

This approach is covered here: CSS-only masonry layout but with elements ordered horizontally

查看更多
相关推荐>>
3楼-- · 2020-07-06 06:24

apparently it's not the same issue ( in Why does CSS Grid layout add extra gaps between cells? )

the thing is you're specifying the height of the column forcing it not to fill the remaining and messing up the grid , since you're specifying where it should start and end in grid-column and grid-row , setting the height to auto for the right column items will fix your issue,

enter image description here

i believe the reason why the grid is behaving like this is because you didn't set the grid-template-rows for the grid , the rows are having the heights of their content on the first columns,

i think you should not set the heights of your grid-items and use grid-template-rows , and if you're not satisfied with heights with height:auto , maybe you should consider reworking your grid-row-start and grid-row-end

i hope this solves your issue or at least gives you an idea on how to fix it.

main {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}
article {
  display: flex;
  background: red;
}
.item1 {
  height: 30px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 1;
  grid-row-end: 2;
}
.item2 {
  height: 100px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 2;
  grid-row-end: 3;
}
.item3 {
  height: 300px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 3;
  grid-row-end: 4;
}
.item4 {
  height: auto;
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 5;
}
.item5 {
  height: 160px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 4;
  grid-row-end: 6;
}
.item6 {
  height: auto;
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 5;
  grid-row-end: 7;
}
.item7 {
  height: 300px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 6;
  grid-row-end: 7;
}
<main>
  <article class="item1"></article>
  <article class="item2"></article>
  <article class="item3"></article>
  <article class="item4"></article>
  <article class="item5"></article>
  <article class="item6"></article>
  <article class="item7"></article>
</main>

查看更多
神经病院院长
4楼-- · 2020-07-06 06:32

The gap come from a miscalculation of heights you are setting to the containers. You should mind the 10px gutters your element element is spanning through.

To keep it fluid, you might use min-height instead height and use grid-template-rows or grid-auto-rows to somehow set a min-height to the rows.

You can also set no heights at all and let the boxes and rows adapt their size to the content they hold.

Test with min-height and grid-template-rows (grid-auto-rows, see other answer).

main {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows:repeat(auto-fill, 4em);/* min-height of 4em if row is empty*/
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}
article {
  display: flex;
  background: red;
}
.item1 {
  /* it will be at least 4em of height*/
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 1;
  grid-row-end: 2;
}
.item2 {
  min-height:180px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 2;
  grid-row-end: 3;
}
.item3 {
  min-height:80px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 3;
  grid-row-end: 4;
}
.item4 {
  min-height:150px;
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 5;
}
.item5 {
  min-height:450px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 4;
  grid-row-end: 6;
}
.item6 {
 min-height:240px;
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 5;
  grid-row-end: 7;
}
.item7 {
  min-height:160px;
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 6;
  grid-row-end: 7;
}
/* see and name me */
article:before{
  content:attr(class);
  font-size:2em;
}
<main>
  <article class="item1"></article>
  <article class="item2"></article>
  <article class="item3"></article>
  <article class="item4"></article>
  <article class="item5"></article>
  <article class="item6"></article>
  <article class="item7"></article>
</main>

Or do not set any heights and let the layout grow from its content:

main {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
   grid-column-gap: 10px;
  grid-row-gap: 10px;
}
article {
  display: flex;
  background: red;
  /* to deal with 'lorem ipsum' content added  */
  flex-flow:column;
  padding:0.5em;
}
.item1 {
  /* it will be at least 4em of height*/
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 1;
  grid-row-end: 2;
}
.item2 {
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 2;
  grid-row-end: 3;
}
.item3 {
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 3;
  grid-row-end: 4;
}
.item4 {
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 5;
}
.item5 {
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 4;
  grid-row-end: 6;
}
.item6 {
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 5;
  grid-row-end: 7;
}
.item7 {
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 6;
  grid-row-end: 7;
}
<main>
  <article class="item1"><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p></article>
  <article class="item2"><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p></article>
  <article class="item3"><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p></article>
  <article class="item4"><h1>HTML Ipsum Presents</h1>

<p><strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p>

<h2>Header Level 2</h2>

<ol>
   <li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
   <li>Aliquam tincidunt mauris eu risus.</li>
</ol>
</article>
  <article class="item5"><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus</p></article>
  <article class="item6"><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p></article>
  <article class="item7"></article>
</main>

查看更多
登录 后发表回答