Let’s build a literal grid of squares, and we’ll put the logos of some magazines centered inside each square. I imagine plenty of you have had to build a logo grid before. You can probably already picture it: an area of a site that lists the donors, sponsors, or that is showing off all the big fancy companies that use some product. Putting the logos into squares is a decent way of handling it, as it forces some clean structure amongst logos that are all different sizes, aspect ratios, and visual weights, which can get finicky and look sloppy.

By “grid” I mean CSS grid. Setting up a grid of (flexible) squares is a little trick of its own. Then we’ll plop those logos in there in a way that keeps them sized and centered. At the end, we’ll look at one little oddity.

1) Grid markup

Have you ever tried this in an editor that supports Emmet?

.grid>div*5>img

Then press tab. It will expand out into:

<div class="grid"> <div><img src="" alt=""></div> <div><img src="" alt=""></div> <div><img src="" alt=""></div> <div><img src="" alt=""></div> <div><img src="" alt=""></div> </div>

Just a little trick for working quickly.

2) CSS Grid basics

We’ll use the infamous flexible columns technique:

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

That will give us not only flexible columns, but a flexible number of columns. Remember, we don’t really care how many columns there are — we’re just building a grid of logos to display.

If we give each of those grid item divs a background and a forced height, we’d see something like:

This screenshot is at a parent width of about 800px. The three columns seen here will increase and decrease to fill the space, thanks to that grid magic.

2) Making real squares

Rather than force the grid items to any particular height, let’s use an aspect-ratio trick. We’ll plop an empty pseudo-element in there with padding-bottom: 100%; meaning it will force the height to be at least as tall as it is wide.

.grid > div { background: black; padding: 1rem; } .grid > div::before { content: ""; padding-bottom: 100%; display: block; }

If we temporarily hide the images, you’ll see the grid of rectangles has become a grid of perfect squares:

3) Overlapping the Images

But with the images in there, they grow a little oblong because the image sits in the pseudo-element.

We’ll need a way to sit them on top of one another. Usually, with aspect-ratio techniques, we reach for absolute positioning to place the in-child container to cover the now aspect-ratioed shape. But since we’re using grid already anyway, let’s use grid again to place the items into the same space:

.grid > div { /* ... */ display: grid; } .grid > div::before, .grid > div > img { grid-area: 1 / 1 / 2 / 2; }

That says to make the grid items of the main grid also into grid containers, with no explicit rows and columns, then to place both the pseudo-element and image onto the first row and column of that grid. This will force them to overlap them, making a nice grid of squares again.

4) Placing the images

Let’s plop a proper src in there for each image. If we make sure the images fill the space (and limit themselves) with width: 100% , we’ll see them along the top of the grid items:

Not terrible, but we would prefer to see them centered. Here’s one trick to do that. First, we’ll also make their height: 100% , which distorts them:

Then fix that up with object-fit !

.grid > div > img { width: 100%; height: 100%; object-fit: contain; }

There we go:

That will work responsively:

5) Quirky dragging size

This (probably) isn’t a massive deal, but notice how the logos look when you drag them off (like a user might if they are trying to save one):

The images look like they have width: 100%; height: 100%; without the object-fit: contain; .

Here’s the working demo so far, with that quirk:

CodePen Embed Fallback

6) Use absolute positioning instead

If that dragging quirk is a big deal, we can always just absolutely position the images inside the grid children instead.

Here’s one way, assuming the grid child div is position: relative; :

.grid > div > img { position: absolute; max-width: 100%; top: 0; bottom: 0; right: 0; left: 0; margin: auto; }

And here’s another:

.grid > div > img { position: absolute; max-width: 100%; top: 50%; left: 50%; transform: translate(-50%, -50%); }

Either of those fix that dragging quirk. Here’s a demo:

CodePen Embed Fallback

Video

If you’d like to watch a video walkthrough of all this, here ya go!