DEV Community 👩‍💻👨‍💻

Aleksei Berezkin
Aleksei Berezkin

Posted on • Updated on

Making perfect square tiles with flexbox

Added on May 30, 2021. The post was originally written keeping old browsers in mind. For recent browsers there's better solution kindly suggested by Temani Afif.

Making square tiles with flexbox is simple! Just add flex-wrap and width, and everything will magically work as together!

<div class='container'>
  <div class='tile'>1</div>
  <div class='tile'>2</div>
  <div class='tile'>3</div>
  <div class='tile'>4</div>
  <div class='tile'>5</div>
  <div class='tile'>6</div>
</div>
Enter fullscreen mode Exit fullscreen mode
.container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

.tile {
  width: 32%;
  &:nth-child(2n) {
    background-color: Bisque;
  }
  &:nth-child(2n+1) {
    background-color: PowderBlue;
  }
}
Enter fullscreen mode Exit fullscreen mode

Hmm... That doesn't look nice: tiles are far from being square; and the problem here is that we didn't specify any height. But here comes a tricky thing: the height must be equal width. Is it even possible when width is not fixed? It is! But it's very hard to guess unless you know 😉 See what MDN says about padding-top:

<percentage>
The size of the padding as a percentage, relative to the width of the containing block

Let's apply it:

.tile {
  width: 32%;
  padding-top: 100%;
  // backgrounds...
}
Enter fullscreen mode Exit fullscreen mode

Again, something went terribly wrong. Why is that? Well, padding-top works correctly, and it took the width from .container, not .tile. In other words, tiles are as high as the container is wide 😄 Can we fix it? Let's move padding to an inner element of .tile which we create with ::before pseudo-element:

.tile {
  width: 32%;
  &::before {
    content: '';
    display: block;
    padding-top: 100%;
  }
  // backgrounds...
}
Enter fullscreen mode Exit fullscreen mode

Much better! However, there are still 3 small issues.

There's no vertical space between tiles

It's quite easy: just add some bottom-margin to .tile. What should it be? Let's calculate:

space=100%32%32=2% space = {100\% - 32\% \sdot 3 \over 2} = 2\%
.tile {
  width: 32%;
  margin-bottom: 2%;
  // ::before...
  // backgrounds...
}
Enter fullscreen mode Exit fullscreen mode

Last tile is right-aligned

That's because flex allocates space between elements even if the row is not full. The easiest way to fix this is to add some right-margin to the last element. The trick is to select it only when it's the second in a row:

.tile {
  width: 32%;
  margin-bottom: 2%;
  &:last-child:nth-child(3n+2) {
    margin-right: 34%;
  }
  // ::before...
  // backgrounds...
}
Enter fullscreen mode Exit fullscreen mode

What is 34%? It's simply 32%+2%32\%+2\% — a width normally occupied by the last tile and the space before it.

Having just colored numbers is not fun

That's easy yet the most important! Let's plug in some photo.

.tile {
  background-image: url(...);
  background-position: center;
  background-size: cover;
  // width, margins, ::before...
}
Enter fullscreen mode Exit fullscreen mode

We can also remove numbers from HTML:

<div class='container'>
  <div class='tile'></div>
  ...
</div>
Enter fullscreen mode Exit fullscreen mode

Let's enjoy the result!


Thanks for reading this! Do you know other interesting flexbox use cases?

Top comments (6)

Collapse
 
afif profile image
Temani Afif

You can do like this too: jsfiddle.net/s85o9ag6/2/ (aspect-ratio + calc + gap) and you no more need to bother with complex calculation and the padding that will push your content..

Collapse
 
alekseiberezkin profile image
Aleksei Berezkin Author • Edited on

Thanks, bookmarked your solution. EDIT: updated the post

Collapse
 
andrewboddy profile image
Andrew Boddy

I am hunting for a solution you might like to write about... responsive tiles ( not square) . I am trying flexbox but the last row is stretching but I want all the tiles to be equal. Also height is a ratio of width... any tips?

Collapse
 
alekseiberezkin profile image
Aleksei Berezkin Author

What about this comment? dev.to/afif/comment/1ei41 It's better than my solution 😉 Of course given you are free of old browsers.

Collapse
 
ariajanke profile image
Aria Janke

Hello, under which license are your code snippets released? I cannot use anything posted here until I'm sure that it is legal to use.

Thank you

Collapse
 
alekseiberezkin profile image
Aleksei Berezkin Author

Hi, I believe Code Pen license applies blog.codepen.io/documentation/lice...

Find what you were looking for? Join hundreds of thousands of developers on DEV so you can:

 
🌚 Enable dark mode
🔠 Change your default font
📚 Adjust your experience level to see more relevant content