Responsive Grid of Squares

This is how you can build a responsive grid of squares (not to be confused with grid layouts) that always fits the screen no matter the width or height of the screen, while also keeping each square in the grid.. er.. square.

I found myself needing this bit of styling for a potential game board. I figured now days it's easy as pie to make a grid, but I quickly found out there were two pieces of this puzzle that turned out to be a bit tricky. The first was making sure the grid fit the screen no matter what the size and orientation of the viewport is. The second sticking point was making sure each square in the grid was always had equal width and height (i.e. is a legit square).

The first point of making it fit in the window was solved via the vw and vh units in conjunction with a max-width and max-height.

.grid {
    margin: 0 auto;
    width: 80vw;
    max-width: 60vh;
    height: 80vw;
    max-height: 60vh;
    font-size: 1rem;
}

The standard width and height is there to set the general size of the board which is to be 80vw which is 80% of the width of the viewport (notice that both are set as vw, this is part of what helps keep the grid as a square). Now to keep the grid visible. If we left it with just the width and height properties than the grid could get cut off if the window is much longer than it is high. To prevent this we add the max-width and max-height properties to be both 60vh. This causes the grid to shrink below it's set width when the screen is too short.

Horray! The grid now fits on the screen at all times. Next up is keeping each box to be an exact square. This one involves the fact that a percentage in the padding property is relative to the element's width, regardless if we are declaring the top or bottom padding. So, for each box we will leave off it's height and it's width is set via flexbox styling. To get it's height correct we add a psuedo element for the box with a padding-top of 100% which should equal 100% of the width of the box.

.box {
    flex: 1 0 auto;
    position: relative;
}
.box:after {
    content: "";
    float:left;
    display: block;
    padding-top: 100%;
}

The final trick is getting text to be centered in each square, here is a job for flexbox again mixed in with some absolute positioning inside of an inner div.

.box .inner {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

That's about it. Check out below for the full code and demo. Have any suggestions on how to improve this concept? Send me a line on Twitter @BlueCaret.

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

HTML

<div class="grid">
    <div class="row">
        <div class="box"><div class="inner">1</div></div>
        <div class="box"><div class="inner">2</div></div>
        <div class="box"><div class="inner">3</div></div>
        <div class="box"><div class="inner">4</div></div>
        <div class="box"><div class="inner">5</div></div>
    </div>
    <div class="row">
        <div class="box"><div class="inner">6</div></div>
        <div class="box"><div class="inner">7</div></div>
        <div class="box"><div class="inner">8</div></div>
        <div class="box"><div class="inner">9</div></div>
        <div class="box"><div class="inner">10</div></div>
    </div>
    <div class="row">
        <div class="box"><div class="inner">11</div></div>
        <div class="box"><div class="inner">12</div></div>
        <div class="box"><div class="inner">13</div></div>
        <div class="box"><div class="inner">14</div></div>
        <div class="box"><div class="inner">15</div></div>
    </div>
    <div class="row">
        <div class="box"><div class="inner">16</div></div>
        <div class="box"><div class="inner">17</div></div>
        <div class="box"><div class="inner">18</div></div>
        <div class="box"><div class="inner">19</div></div>
        <div class="box"><div class="inner">20</div></div>
    </div>
    <div class="row">
        <div class="box"><div class="inner">21</div></div>
        <div class="box"><div class="inner">22</div></div>
        <div class="box"><div class="inner">23</div></div>
        <div class="box"><div class="inner">24</div></div>
        <div class="box"><div class="inner">25</div></div>
    </div>
</div>

CSS

.grid {
    margin: 0 auto;
    width: 80vw;
    max-width: 60vh;
    height: 80vw;
    max-height: 60vh;
    font-size: 1rem;
}
.row {
    display: flex;
}
.box {
    background: tomato;
    margin: 5px;
    color: white;
    font-weight: bold;
    flex: 1 0 auto;
    position: relative;
}
.box:after {
    content: "";
    float:left;
    display: block;
    padding-top: 100%;
}
.box .inner {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

View CodePen