Using CSS Grid to put elements on top of each other

·

3 min read

This is a very cool trick I learned recently.

The problem

I have a card that contains an image and some text. The size of the image depends on the width of the card. The text could be any length.

When you hover on the card it fills the whole card with a background colour and shows some other text.

The non-grid solution

The obvious solution is to have a div for the card and a div for the hover and use position absolute to put them on top of each other. However, the card has to be long enough to fit all of the hover text on, even if it takes up more space than the image and text on the card. Which is a problem because an absolutely positioned element doesn't take up space.

The solution is to go to JavaScript, get it to work out the heights of both divs and set the card height to be whichever is taller. It's a pretty simple script and not too much work.

Except that the card image was being lazy loaded and wasn't at the top of the screen. And I had multiple cards. At this point the JavaScript was looking more complicated and I went back to the drawing board (ie Google) to see if there was another way of putting two divs on top of each other. And there is!

The grid solution

CSS Grid is pretty cool and will respect the position of your element on the grid, even if it's absolutely positioned. Which we can absolutely use.

For this solution we need a container that has both the card contents and the hover div inside it:

<div class="card">
  <div class="card-contents">
  <div class="card-hover">
  </div>
</div>

Then we can make the .card into a grid:

.card {
  display: grid;
}

Since we haven't told it how many rows or columns we want on our grid it works it out for itself. Since we have two elements inside it it's implicitly created two rows, one for the contents and one for the hover.

All we have to do is to tell it we want them both on the first row:

.card-contents,
.card-hover {
  grid-row: 1;
}

Except now it's implicitly created two columns instead... But that's easily fixed by telling it we also want them both on the first column:

.card-contents,
.card-hover {
  grid-row: 1;
  grid-column: 1;
}

And that's it! By the magic of CSS grid, both divs are on top of each other. You can see in this CodePen, where I've added some extra CSS for the hover effect and also to make it look not too terrible. And I've made the card slightly transparent so you can see the hover behind it without needing to actually hover.