Awaiting for aspect-ratio: "hacks" for proportional boxes
Published: 2021-02-13 00:30:05

While waiting for [widespread support of aspect-ratio](https://caniuse.com/?search=aspect-ratio) property, I invite you to think back on a few variations of the hack that you can still use to achieve the same behaviour with regular boxes.

## Table Of Contents
* [padding-top/bottom in %](#padding)
* [padding-top/bottom + calc() function](#calc)
* [padding-top/bottom for :: before](#before)
* [flexbox option](#flexbox)
* [What next? @supports not](#supports-not)

### padding-top/bottom in % <a name="padding"></a>

Aspect-ratio without the new property could be achieved by setting the box with zero height padding-top or padding-bottom in %. The percentage was calculated using the formula:

height / width * 100%

For instance:
1x1 aspect ratio = 1 / 1 * 100% = padding-top: 100%
4x3 aspect ratio = 3 / 4 * 100% = padding-top: 75%
16x9 aspect ratio = 9 / 16 * 100% = padding-top: 56.25%

In some cases, percentages were rounded to the nearest hundredth:
3x2 aspect ratio = 2 / 3 * 100% = padding‑top: 66.67% (66.66666666666667%)

Apparently people didn't like writing 16-digit property values. Which brings us to

### padding‑top/bottom + calc() function <a name="calc"></a>

```
.aspect-ratio-box {
  padding-bottom: calc(100% / (327 / 120));
  height: 0;
}
```

It was more appealing and gave people, not familiar with the hack, a little hint about what was going on.

Since the box height was zero, we needed to use absolute positioning to place something (a heading, for example) in it. Because of this, it wasn't protected from content overflow.

Also, you may have come across another reason why we could not use this method. Here's a good example:
![Block of the Loop studio landing page from frontendmentor.io](https://dev-to-uploads.s3.amazonaws.com/i/ga97tv30i6p1zop4p6b2.png)
Block of the [Loop studio landing page](https://www.frontendmentor.io/challenges/loopstudios-landing-page-N88J5Onjw) from [frontendmentor.io](https://www.frontendmentor.io/)

All projects of this block are essentially an article tag with the heading inside. Images are specified through the background-image property. Projects blocks must also be clickable. We can wrap the entire content of the article block in a link. In this case, it won't be a problem. However, if we ever want to add a description to the project card, we will have an accessibility problem. The screen reader will read everything inside the link — both the heading and the description section.
There is a [solution to that issue](https://inclusive-components.design/cards/): put the link in the header tag and stretch its clickable area through a pseudo-element. But for this, we need the headings not to be absolutely positioned. So we need another version of the aspect-ratio box.

### padding-top/bottom for ::before <a name="before"></a>

Next modification was to set the padding in % but for a pseudo‑element with a float: left; Like this:

```
.aspect-ratio-box {
    display: flow-root;
/* required to prevent the container collapsing */
}

.aspect-ratio-box::before {
    content: "";
    float: left;
    padding-bottom: calc(100% / (327 / 120));
}
```

For broader support than [flow-root](https://caniuse.com/?search=flow-root) (i.e. browsers ~ until mid-2017), you could alternatively use the [column-count](https://caniuse.com/?search=column-count) property for the container:

```
.aspect-ratio-box {
    column-count: 1;
/* Bulletproof clearfix */
}

.aspect-ratio-box::before {
    content: "";
    float: left;
    padding-bottom: calc(100% / (327 / 120));
}
```

### flexbox option <a name="flexbox"></a>
display: flex; will change the normal [document flow](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow) to horizontal (from left to right):

```
.aspect-ratio-box {
  display: flex;
}

.aspect-ratio-box::before {
    content: "";
    padding-bottom: calc(100% / (327 / 120));
}
```
Remember that the last two alternatives still do not allow you to add padding to the container. If you need padding, you will have to add it to the child boxes.

### What's next? @supports not <a name="supports-not"></a>
What variation to use in work? It seems to me that we can start using aspect‑ratio and use a fail-safe with the @supports at-rule and not operator:
```
.aspect-ratio-box {
  aspect-ratio: 327 / 120;
}

@supports not (aspect-ratio: 1 / 1) {
/* if the browser does NOT support the property, then */
/* apply styles inside */
  .aspect-ratio-box {
    column-count: 1;
  }

  .aspect-ratio-box::before {
    content: "";
    float: left;
    padding-bottom: calc(100% / (327 / 120));
  }
}
```
This method is the most reliable.

If someone who works with your CSS needs to reposition the heading, they can use flexbox and margins with value auto.
Float property will stop working. This way, they won't accidentally break anything.

And over time, when support becomes more widespread, we will only remove the at-rule with its content.