How to Create a Responsive Square with CSS

,

During a recent project, the designer wanted to create square elements for a gallery-style layout where the elements are laid out on a consistent grid. Is easy to make a square when you have fixed width and height.

.box {
    width:  200px;
    height: 200px;
}

This works great, but when we try to make it responsive using percentages, we realize that it does not function the way we want.

.box {
    width:  25%;
    height: 25%;
}

Simply using percentages does not work because the element’s width is calculated by its parent’s width and the height it’s calculated by its parent’s height. Since the width and height are of different measures, the square will not hold its shape.

The Solution(s)

After researching, I found that there are two main solutions that you can achieve this. Depending on your project you can choose on over the other one.

Using viewport-percentage

This is definitely the cleanest solution out there, however, according to http://caniuse.com/#feat=viewport-units there are some issues with different browsers and versions.

.box {
    width: 50vw;
    height: 50vw;
}

Using the :after pseudo-element

By making use of the padding-top, we can create a perfect square. While it sounds crazy, padding is calculated by the parent’s width, not height. This means you can use padding-bottom if we want. For this to work, we just need to remove the height property from the .box element.

.box {
  width: 50%;
}

.box:after {
  content: "";
  display: block;
  padding-top: 100%;
}

Since the pseudo element’s padding is calculated from the parent’s width, we are fixing its height. If the width of the .box is going to change, the height of the pseudo-element is going to change as well.

Adding Content

The solution above works perfectly if there is no content inside the .box element since it relies on having a height of 0. If we want to add content, the solution is going to break.

Fortunately, there is an easy way to fix this problem. We can place a position absolute div inside the .box. The new element is going to take the width and the height of its parent since is position absolute. Don’t forget to add position relative to .box

.box {
  position: relative;
  width: 25%;
}

.box:after {
  content: "";
  display: block;
  padding-top: 100%;
}

.content {
  position: absolute;
  width: 100%;
  height: 100%;
}

See the Pen Responsive Square Elements by Mihai Slujitoru (@MihaiSlujitoru) on CodePen.

Other Aspect Ratios

If you want to create other ratios, you can just change the padding-top percentage.

.ratio2_1:after{
	padding-top: 50%;
}
.ratio1_2:after{
	padding-top: 200%;
}
.ratio4_3:after{
	padding-top: 75%;
}
.ratio16_9:after{
	padding-top: 56.25%;
}