Table of contents
The problem
You want to display items side by side in a grid. You set the number of columns, and you want each item's height to match its width to form a square. How do you do this?
I faced this problem at work. I needed to create a gallery like on iPhone, WhatsApp, or Telegram, where you see a grid of images and can click on them to view in full screen.
Achieve equal width
To achieve the items having equal width, we can use display Grid.
<div className="grid grid-cols-4 gap-1">
{images &&
images.map((image) => (
<img key={image.id} src={image.url} alt="image" className="w-full" />
))}
</div>
This will give us a grid of 4 columns with a gap of 4px. Each column will take equal width. The images will take the full width of the column and their height will adjust to maintain the aspect ratio.
The issue here is that we want the images to take equal height. Once that's done, we could use object-fit: cover;
to ensure the images cover the entire space and their aspect ratio is maintained.
Achieve equal height
To make height the same value as the width, we can use padding-top: 100%;
to achieve this. When you use padding with percentage, it's calculated based on the width of the element.
<div className="grid grid-cols-4 gap-1">
{images &&
images.map((image) => (
<div
// padding top 100% to ensure square based off the width
className="relative w-full pt-[100%]"
key={image.id}
>
<img
src={image.url}
alt=""
className="absolute left-0 top-0 h-full w-full object-cover"
/>
</div>
))}
</div>
As you can see, we now have a wrapper around the image.
Let's try to understand how things work here in chronological order:
div
is the wrapper. It takes full width and its height is the same as the width.div
haspadding-top: 100%;
. This means it will naturally push down the image inside of it to fill the space.Therefore, the image can not be inside the normal flow of the document.
div
is given relative positioning.img
is given absolute positioning and can be placed anywhere.Because the parent of
img
has relative positioning, theimg
will be positioned relative to its closest ancestor that has relative or absolute positioning.img
is givenleft: 0; top: 0;
. This means the top left corner of the image will be at the top left corner of thediv
.img
is givenh-full w-full
. This means the image will take the full height and width of thediv
.img
is givenobject-cover
. This means the image will cover the entire space of thediv
and its aspect ratio is maintained.
And that's how you achieve a grid of squares.