Gh05d
Gh05d

Reputation: 8982

Prevent "widows" - items alone in a row - when using css grid

I created a responsive grid which should contain rows of 4, 3, 2 or 1 items, depending on the window size. Hard requirement from Design is that no widows and no half filled rows are allowed. So for 11 items, there could be two rows of four items and one of three, or three rows of three items and one of two items, or... . You get the idea.

To solve the problem, I created a css grid:

display: grid;
grid-template-columns: repeat(auto-fit, minmax(264px, 1fr));
grid-gap: 24px;

This works fine for the resizing, but it does not take care of the widow problem. At first I did the naive approach of selecting the last item with a last-of-type selector and giving it a grid-row: 1 / -1 style, but that does not ensure that the row above is fully filled.

I guess there won't be a css only solution. Is there a way for an element to realize that it is alone in a row, or that it has to grow to fill the row? I had an idea using the nextSibling property to select the last child via JavaScript and maybe determine via the page offset if it fills the whole row. But my problem is that I can't hardcode the width of the screen.

Alternatively, is there a way to tell an element to spread until the end of the row? I tried this, but it did not work:

.card:last-of-type {
  grid-column-end: span -1;
}

Click here for minimal reproducible example.

Upvotes: 1

Views: 500

Answers (1)

Reyno
Reyno

Reputation: 6505

A solution is to use flexbox instead of grid. This way it can stretch with the screen size. We use 25% for a 4 column layout. Subtracting 1rem for a bit of margin. (0.5 left + 0.5 right)

(Open snippet in fullscreen to see it working)

.my-grid {
  display: flex;
  flex-wrap: wrap;
}

.card {
  min-width: 264px;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 1px 1px #00000026;
  font-size: 14px;
  background-color: red;
  margin: .5rem;
  flex: 1 1 calc(25% - 1rem);
}
<div class="my-grid">
  <div class="card">1</div>
  <div class="card">1</div>
  <div class="card">1</div>
  <div class="card">1</div>
  <div class="card">1</div>
  <div class="card">1</div>
  <div class="card">1</div>
  <div class="card">1</div>
  <div class="card">1</div>
  <div class="card">blub</div>
</div>

Upvotes: 1

Related Questions