Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filling empty cells in CSS Grid Layout

I have a set of div tiles that I've arranged through the CSS Grid Layout as "automatically" as possible; my final idea is that even if I don't know how many tiles there are, they all get sized and placed correctly. This is working fine.

Now, I'm looking to double the area of any tile that is clicked on. As far as I know, that means increasing the span of this tile:

grid-row: span 2;
grid-column: span 2;

I'm happy with the results if I click on any tile that is not in the right-most column. When the rightmost tiles get expanded, they are wrapped down onto the next line.

Is there any way to force these tiles to expand to the left, so that other non-active tiles are wrapped instead?

Codepen example here

$('div.tile').click(function() {
  $('div.tile').not(this).removeClass('chosen');
  $(this).toggleClass('chosen');
  
  /*
Attempt to find current placement, to see if we could change the span rules based on results. Probably disregard.
  */
  var colCount = $('div.wrapper').css('grid-template-columns').split(' ').length;
  console.log(colCount);
  
  var placement = $(this).css('grid-row');
  console.log(placement);
});
body {
  margin: 0;
  padding: 0;
  background-color: #eee;
}

.wrapper {
  display: grid;
  margin: 18px;
  
  grid-template-columns: repeat(auto-fill, minmax(252px, 1fr));
  grid-auto-rows: 286px;
  grid-gap: 18px;
}

.tile {
  position: relative;
  background-color: #eee;
  background-color: #149;
  
  text-align: center;
  box-shadow:
    0 3px 12px rgba(0,0,0, 0.15),
    0 4px 6px rgba(0,0,0, 0.25);
}
.tile.chosen {
  grid-row: span 2;
  grid-column: span 2;
}
.tile.chosen::before {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  content: " ";
  background-color: rgba(255,255,255,.2);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
  <div class="tile">A</div>
  <div class="tile">B</div>
  <div class="tile">C</div>
  <div class="tile">D</div>
  <div class="tile">E</div>
  <div class="tile">F</div>
  <div class="tile">G</div>
  <div class="tile">H</div>
  <div class="tile">I</div>
</div>
like image 795
Fogle Avatar asked Jul 10 '17 15:07

Fogle


1 Answers

Working with CSS Grid Auto Placement

The CSS grid-auto-flow property controls how auto-placed grid items are placed in the grid.

This property has three possible values:

  • row (the default)
  • column
  • dense

With dense, the auto-placement algorithm fills unoccupied cells with items that fit.

Here's your code, with grid-auto-flow: dense on the grid container:

$('div.tile').click(function() {
  $('div.tile').not(this).removeClass('chosen');
  $(this).toggleClass('chosen');
  var colCount = $('div.wrapper').css('grid-template-columns').split(' ').length;
  console.log(colCount);
  var placement = $(this).css('grid-row');
  console.log(placement);
});
body {
  margin: 0;
  padding: 0;
  background-color: #eee;
}

.wrapper {
  display: grid;
  margin: 18px;
  grid-template-columns: repeat(auto-fill, minmax(252px, 1fr));
  grid-auto-rows: 286px;
  grid-gap: 18px;
  grid-auto-flow: dense; /* NEW */
}

.tile {
  position: relative;
  background-color: #eee;
  background-color: #149;
  text-align: center;
  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.15), 0 4px 6px rgba(0, 0, 0, 0.25);
}

.tile.chosen {
  grid-row: span 2;
  grid-column: span 2;
}

.tile.chosen::before {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  content: " ";
  background-color: rgba(255, 255, 255, .2);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
  <div class="tile">A</div>
  <div class="tile">B</div>
  <div class="tile">C</div>
  <div class="tile">D</div>
  <div class="tile">E</div>
  <div class="tile">F</div>
  <div class="tile">G</div>
  <div class="tile">H</div>
  <div class="tile">I</div>
</div>

revised codepen


From the spec:

7.7. Automatic Placement: the grid-auto-flow property

Grid items that aren’t explicitly placed are automatically placed into an unoccupied space in the grid container by the auto-placement algorithm.

grid-auto-flow controls how the auto-placement algorithm works, specifying exactly how auto-placed items get flowed into the grid.

row

The auto-placement algorithm places items by filling each row in turn, adding new rows as necessary. If neither row nor column is provided, row is assumed.

column

The auto-placement algorithm places items by filling each column in turn, adding new columns as necessary.

dense

If specified, the auto-placement algorithm uses a “dense” packing algorithm, which attempts to fill in holes earlier in the grid if smaller items come up later. This may cause items to appear out-of-order, when doing so would fill in holes left by larger items.


Working with CSS Grid Defined Placement

The CSS Grid specification provides many properties and methods for sizing and positioning grid items. So if you don't have to rely on auto placement, use defined placement for more control.

grid-container {
  display: grid;
  grid-template-rows: repeat(4, 25%);
  grid-template-columns: repeat(4, 25%);
  grid-gap: 5px;
  width: 400px;
  height: 400px;
}

[left]:hover {
  grid-column: -1 / -3;
  grid-row: 1 / 2;
  background-color: orange
}

[right]:hover {
  grid-column: 1 / 3;
  grid-row: 2 / 3;
  background-color: orange
}

[down]:hover {
  grid-column: -1 / -2;
  grid-row: 2 / 4;
  background-color: orange
}

[up]:hover {
  grid-column: 3 / 4;
  grid-row: -4 / -2;
  background-color: orange
}

grid-item {
  background-color: lightgreen;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
<grid-container>
  <grid-item></grid-item>
  <grid-item></grid-item>
  <grid-item></grid-item>
  <grid-item left>HOVER<br>to go left</grid-item>
  <grid-item right>HOVER<br>to go right</grid-item>
  <grid-item></grid-item>
  <grid-item></grid-item>
  <grid-item down>HOVER<br>to go down</grid-item>
  <grid-item></grid-item>
  <grid-item></grid-item>
  <grid-item up>HOVER<br>to go up</grid-item>
  <grid-item></grid-item>
</grid-container>
like image 65
Michael Benjamin Avatar answered Sep 23 '22 18:09

Michael Benjamin