How can I calculate the current viewport aspect ratio with CSS?

Viewed 58

I need to represent the current viewport shape in miniature, fitting 100% of a containing element's width or height, as appropriate for the aspect ratio. I want to offer a preview of how an HTML structure will fit into the screen as it is at that moment.

To do this, I believe I need to determine the aspect ratio of the screen. Of course this can be done with JavaScript, but it would be more elegant in my case to do it with CSS.

It might look something like this. Here I'm using the zero height trick with bottom padding providing the aspect ratio. It doesn't work because the calc() function can't divide by a value with units.

.container {
  width: 240px;
  height: 160px;
  background: #ddd;
}

.vieweport-miniature {
  height: 0;
  padding-bottom: calc(100vw / 100vh); /* can't divide by viewport units */
  padding-bottom: 45%; /* for demonstration purposes only */
  max-width: 100%;
  max-height: 100%;
  background: pink;
}
<div class="container">
  <div class="vieweport-miniature"></div>
</div>

There are many questions on SO asking something similar, but they tend to have a predefined aspect ratio. Here I want it to match that of the viewport dynamically.

Thanks!

1 Answers

"I need to represent the current viewport shape in miniature, fitting a containing element." "Here I want it to match that of the viewport dynamically"

Update

Since the mini-viewport element needs to be in a container that has absolute dimensions, then it is necessary to use those "hard-coded" values to calculate the size of the mini-viewport element in order to fit within the container's perimeter.

Using the zero height and padding-bottom trick is used for elements if you actually want a specific ratio. Dynamically adjusting to viewport is easy, just assign width and height at equal value of vw and vh units respectively. The scale has to be predetermined of course. For example, if the mini viewport element is half the size of viewport then the dimensions should be w: 50vw x h: 50vh.

In addition to using vw and vh units as previously mentioned (which is the only way to get the viewport dimensions with CSS), use the CSS function min() so that the mini-viewport element always fits within the container, see Figure I.

Figure I

.mini {
  /* This is 15% of viewport width, but will not exceed 240px */
  width: min(15vw, 240px);
  /* This is 15% of viewport height */
  height: 15vh;
}

View the example in full page mode, dimensions rendered in the iframe are a little distorted. JavaScript has been added to the example for demonstration purposes only and is not part of the solution to the question. Resize the window and note the console -- the first number is the quotient of the viewport width/height, the second number is the quotient of .mini width/height. Note that they are very close (differs by a hundredth on the average.)

/*~~~~~~~For Demonstration Purposes Only~~~~~~~*/

function getAR(e) {
  const vpw = window.innerWidth;
  const vph = window.innerHeight;

  const mini = document.querySelector('.mini');
  const mnw = Math.round(mini.getBoundingClientRect().width);
  const mnh = Math.round(mini.getBoundingClientRect().height);

  const vpar = vpw / vph;
  const mnar = mnw / mnh;
  console.log(vpar.toFixed(2), mnar.toFixed(2));
}

getAR();
window.onresize = getAR;
body {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

.box {
  width: 240px;
  height: 160px;
  background: lightgrey;
}

.mini {
  width: min(15vw, 240px);
  height: 15vh;
  background: pink;
}
<div class="box">
  <div class="mini"></div>
</div>

Related