Responsive aspect ratios with pure css: how to fill container's height?

Viewed 1197

I have a div (the one with class container) with fixed height (which is supposed to be dynamic and not known in advance) which contains another div (the one with class fixed-aspect-ratio).

I would like the inner div to fill the container's height while keeping a fixed aspect ratio of 1:1.

The commonly used trick to achieve fixed aspect ratios is to exploit padding: in fact when declaring percentages instead of fixed values for padding, the percentage is calculated based on the WIDTH of the element in question, even if we are declaring a vertical value such as padding-top or padding-bottom.

This makes padding a great trick to exploit if you want to fill the container's WIDTH, but not if you want to fill the container's HEIGHT.

Is it possibile to achieve it using CSS only? No javascript thanks.

Ideally I would love to have CSS units complementary to the viewport ones, but relative to the container. Something like:

  • cw (container width)
  • ch (container height)
  • cmin (container min)
  • cmax (container max)

Would be freaking awesome.

<!DOCTYPE html>
<html>

<head>
  <style>
    .container {
      background-color: green;
      height: 30vh;
    }
    
    .fixed-aspect-ratio {
      background-color: red;
      width: 100%;
      padding-top: 100%;
      /* 1:1 Aspect Ratio */
      position: relative;
      /* If you want text inside of it */
    }
    /* If you want text inside of the container */
    
    .text {
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="fixed-aspect-ratio">
      <div class="text">Some text</div>
      <!-- If you want text inside the container -->
    </div>
  </div>
</body>

</html>

https://www.w3schools.com/code/tryit.asp?filename=FLJBS4J2MTWS

2 Answers

There is no similar CSS solution for height, as the padding-bottom for width.

Besides script, here is a this trick I have used, where I place an img, with a data url SVG (could be a Base64 png as well) to avoid an extra roundtrip to the server, having a square size.

By setting its height to 100%, it will keep its parent, being inline block, a square, and with visibility: hidden hide it.

Stack snippet

.container {
  background-color: green;
  height: 50vh;
}

.fixed-aspect-ratio {
  display: inline-block;
  background-color: red;
  height: 100%;
  position: relative;
}

.fixed-aspect-ratio img {
  display: block;
  height: 100%;
  visibility: hidden;
}

.text {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
}
<div class="container">
  <div class="fixed-aspect-ratio">
    <img src="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><rect width='10' height='10'/></svg>">
    <div class="text">Some text</div>
    <!-- If you want text inside the container -->
  </div>
</div>

Set height to 100% and width to x%

<!DOCTYPE html>
<html>

<head>
  <style>
    .container {
      background-color: green;
      height: 30vh;
    }
    
    .fixed-aspect-ratio {
      background-color: red;
      height: 100%;
      width: 10%;
      /* 1:1 Aspect Ratio */
      position: relative;
      /* If you want text inside of it */
    }
    /* If you want text inside of the container */
    
    .text {
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="fixed-aspect-ratio">
      <div class="text">Some text</div>
      <!-- If you want text inside the container -->
    </div>
  </div>
</body>

</html>

Related