Grid of responsive squares

HtmlCssResponsive DesignGrid LayoutAspect Ratio

Html Problem Overview


I'm wondering how I would go about creating a layout with responsive squares. Each square would have vertically and horizontally aligned content. The specific example is displayed below...

responsive squares with content

Html Solutions


Solution 1 - Html

You can make responsive grid of squares with vertically and horizontally centered content only with CSS. I will explain how in a step by step process but first here are 2 demos of what you can achieve:

Responsive 3x3 square grid Responsive square images in a 3x3 grid

Now let's see how to make these fancy responsive squares!



1. Making the responsive squares :

The trick for keeping elements square (or whatever other aspect ratio) is to use percent padding-bottom.
Side note: you can use top padding too or top/bottom margin but the background of the element won't display.

As top padding is calculated according to the width of the parent element (See MDN for reference), the height of the element will change according to its width. You can now Keep its aspect ratio according to its width.
At this point you can code:

HTML :

<div></div>

CSS :

div {
    width: 30%;
    padding-bottom: 30%; /* = width for a square aspect ratio */
}

Here is a simple layout example of 3*3 squares grid using the code above.

With this technique, you can make any other aspect ratio, here is a table giving the values of bottom padding according to the aspect ratio and a 30% width.

 Aspect ratio  |  padding-bottom  |  for 30% width
------------------------------------------------
    1:1        |  = width         |    30%
    1:2        |  width x 2       |    60%
    2:1        |  width x 0.5     |    15%
    4:3        |  width x 0.75    |    22.5%
    16:9       |  width x 0.5625  |    16.875%

2. Adding content inside the squares :

As you can't add content directly inside the squares (it would expand their height and squares wouldn't be squares anymore) you need to create child elements (for this example I am using divs) inside them with position: absolute; and put the content inside them. This will take the content out of the flow and keep the size of the square.

Don't forget to add position:relative; on the parent divs so the absolute children are positioned/sized relatively to their parent.

Let's add some content to our 3x3 grid of squares :

HTML :

<div class="square">
    <div class="content">
        .. CONTENT HERE ..
    </div>
</div>
... and so on 9 times for 9 squares ...

CSS :

.square {
    float: left;
    position: relative;
    width: 30%;
    padding-bottom: 30%; /* = width for a 1:1 aspect ratio */
    margin: 1.66%;
    overflow: hidden;
}

.content {
    position: absolute;
    height: 80%; /* = 100% - 2*10% padding */
    width: 90%; /* = 100% - 2*5% padding */
    padding: 10% 5%;
}

RESULT <-- with some formatting to make it pretty!


3. Centering the content :

Horizontally :

This is pretty easy, you just need to add text-align:center to .content.
RESULT

Vertical alignment :

This becomes serious! The trick is to use

display: table;
/* and */
display: table-cell;
vertical-align: middle;

but we can't use display:table; on .square or .content divs because it conflicts with position:absolute; so we need to create two children inside .content divs. Our code will be updated as follow :

HTML :

<div class="square">
    <div class="content">
        <div class="table">
            <div class="table-cell">
                ... CONTENT HERE ...
            </div>
        </div>
    </div>
</div>
... and so on 9 times for 9 squares ...

CSS :

.square {
    float:left;
    position: relative;
    width: 30%;
    padding-bottom : 30%; /* = width for a 1:1 aspect ratio */
    margin:1.66%;
    overflow:hidden;
}

.content {
    position:absolute;
    height:80%; /* = 100% - 2*10% padding */
    width:90%; /* = 100% - 2*5% padding */
    padding: 10% 5%;
}

.table{
    display:table;
    height:100%;
    width:100%;
}

.table-cell{
    display:table-cell;
    vertical-align:middle;
    height:100%;
    width:100%;
}

We have now finished and we can take a look at the result here :

LIVE FULLSCREEN RESULT

editable fiddle here


Solution 2 - Html

You could use vw (view-width) units, which would make the squares responsive according to the width of the screen.

A quick mock-up of this would be:

html,
body {
  margin: 0;
  padding: 0;
}
div {
  height: 25vw;
  width: 25vw;
  background: tomato;
  display: inline-block;
  text-align: center;
  line-height: 25vw;
  font-size: 20vw;
  margin-right: -4px;
  position: relative;
}
/*demo only*/

div:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  height: inherit;
  width: inherit;
  background: rgba(200, 200, 200, 0.6);
  transition: all 0.4s;
}
div:hover:before {
  background: rgba(200, 200, 200, 0);
}

<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>

Solution 3 - Html

The accepted answer is great, however this can be done with flexbox.

Here's a grid system written with BEM syntax that allows for 1-10 columns to be displayed per row.

If there the last row is incomplete (for example you choose to show 5 cells per row and there are 7 items), the trailing items will be centered horizontally. To control the horizontal alignment of the trailing items, simply change the justify-content property under the .square-grid class.

.square-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.square-grid__cell {
  background-color: rgba(0, 0, 0, 0.03);
  box-shadow: 0 0 0 1px black;
  overflow: hidden;
  position: relative;
}

.square-grid__content {
  left: 0;
  position: absolute;
  top: 0;
}

.square-grid__cell:after {
  content: '';
  display: block;
  padding-bottom: 100%;
}

// Sizes – Number of cells per row

.square-grid__cell--10 {
  flex-basis: 10%;
}

.square-grid__cell--9 {
  flex-basis: 11.1111111%;
}

.square-grid__cell--8 {
  flex-basis: 12.5%;
}

.square-grid__cell--7 {
  flex-basis: 14.2857143%;
}

.square-grid__cell--6 {
  flex-basis: 16.6666667%;
}

.square-grid__cell--5 {
  flex-basis: 20%;
}

.square-grid__cell--4 {
  flex-basis: 25%;
}

.square-grid__cell--3 {
  flex-basis: 33.333%;
}

.square-grid__cell--2 {
  flex-basis: 50%;
}

.square-grid__cell--1 {
  flex-basis: 100%;
}

.square-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.square-grid__cell {
  background-color: rgba(0, 0, 0, 0.03);
  box-shadow: 0 0 0 1px black;
  overflow: hidden;
  position: relative;
}

.square-grid__content {
  left: 0;
  position: absolute;
  top: 0;
}

.square-grid__cell:after {
  content: '';
  display: block;
  padding-bottom: 100%;
}

// Sizes – Number of cells per row

.square-grid__cell--10 {
  flex-basis: 10%;
}

.square-grid__cell--9 {
  flex-basis: 11.1111111%;
}

.square-grid__cell--8 {
  flex-basis: 12.5%;
}

.square-grid__cell--7 {
  flex-basis: 14.2857143%;
}

.square-grid__cell--6 {
  flex-basis: 16.6666667%;
}

.square-grid__cell--5 {
  flex-basis: 20%;
}

.square-grid__cell--4 {
  flex-basis: 25%;
}

.square-grid__cell--3 {
  flex-basis: 33.333%;
}

.square-grid__cell--2 {
  flex-basis: 50%;
}

.square-grid__cell--1 {
  flex-basis: 100%;
}

<div class='square-grid'>
  <div class='square-grid__cell square-grid__cell--7'>
    <div class='square-grid__content'>
      Some content
    </div>
  </div>
  <div class='square-grid__cell square-grid__cell--7'>
    <div class='square-grid__content'>
      Some content
    </div>
  </div>
  <div class='square-grid__cell square-grid__cell--7'>
    <div class='square-grid__content'>
      Some content
    </div>
  </div>
  <div class='square-grid__cell square-grid__cell--7'>
    <div class='square-grid__content'>
      Some content
    </div>
  </div>
  <div class='square-grid__cell square-grid__cell--7'>
    <div class='square-grid__content'>
      Some content
    </div>
  </div>
  <div class='square-grid__cell square-grid__cell--7'>
    <div class='square-grid__content'>
      Some content
    </div>
  </div>
  <div class='square-grid__cell square-grid__cell--7'>
    <div class='square-grid__content'>
      Some content
    </div>
  </div>
  <div class='square-grid__cell square-grid__cell--7'>
    <div class='square-grid__content'>
      Some content
    </div>
  </div>
</div>

Fiddle: https://jsfiddle.net/patrickberkeley/noLm1r45/3/

This is tested in FF and Chrome.

Solution 4 - Html

Now we can easily do this using the aspect-ratio ref property

.container {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr)); /* 3 columns */
  grid-gap: 10px;
}

.container>* {
  aspect-ratio: 1 / 1; /* a square ratio */
  border: 1px solid;
  
  /* center content */
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

img {
  max-width: 100%;
  display: block;
}

<div class="container">
  <div> some content here </div>
  <div><img src="https://picsum.photos/id/25/400/400"></div>
  <div>
    <h1>a title</h1>
  </div>
  <div>more and more content <br>here</div>
  <div>
    <h2>another title</h2>
  </div>
  <div><img src="https://picsum.photos/id/104/400/400"></div>
</div>

Also like below where we can have a variable number of columns

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

.container>* {
  aspect-ratio: 1 / 1; /* a square ratio */
  border: 1px solid;
  
  /* center content */
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

img {
  max-width: 100%;
  display: block;
}

<div class="container">
  <div> some content here </div>
  <div><img src="https://picsum.photos/id/25/400/400"></div>
  <div>
    <h1>a title</h1>
  </div>
  <div>more and more content <br>here</div>
  <div>
    <h2>another title</h2>
  </div>
  <div><img src="https://picsum.photos/id/104/400/400"></div>
  <div>more and more content <br>here</div>
  <div>
    <h2>another title</h2>
  </div>
  <div><img src="https://picsum.photos/id/104/400/400"></div>
</div>

Solution 5 - Html

I use this solution for responsive boxes of different rations:

HTML:

<div class="box ratio1_1">
  <div class="box-content">
            ... CONTENT HERE ...
  </div>
</div>

CSS:

.box-content {
  width: 100%; height: 100%;
  top: 0;right: 0;bottom: 0;left: 0;
  position: absolute;
}
.box {
  position: relative;
  width: 100%;
}
.box::before {
    content: "";
    display: block;
    padding-top: 100%; /*square for no ratio*/
}
.ratio1_1::before { padding-top: 100%; }
.ratio1_2::before { padding-top: 200%; }
.ratio2_1::before { padding-top: 50%; }
.ratio4_3::before { padding-top: 75%; }
.ratio16_9::before { padding-top: 56.25%; }

See demo on JSfiddle.net

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiongarethdnView Question on Stackoverflow
Solution 1 - Htmlweb-tikiView Answer on Stackoverflow
Solution 2 - Htmljbutler483View Answer on Stackoverflow
Solution 3 - HtmlPatrick BerkeleyView Answer on Stackoverflow
Solution 4 - HtmlTemani AfifView Answer on Stackoverflow
Solution 5 - HtmlmitjajezView Answer on Stackoverflow