1

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!

isherwood
  • 58,414
  • 16
  • 114
  • 157
  • https://stackoverflow.com/questions/48616165/get-screen-proportion-by-dividing-width-with-height-in-css – UmairFarooq Sep 14 '22 at 18:50
  • Yeah, that solution fails because of the division issue I mentioned. I'm not sure why it ever worked. – isherwood Sep 14 '22 at 19:01
  • @isherwood you are fixated on `calc()`, but according to your question, you do not need to calculate any viewport AR because `vw`, `vh`, `vmin`, and `vmax` **are the viewport dimensions**. They are hard coded values yet dynamic. Not sure why you don't expect limitations trying to cram an element with dynamic dimensions into an element that never changes dimensions using only CSS. Anyways, I resolved the question for what it's worth. BTW, that duplicate doesn't really address the question, only an aspect of it. – zer00ne Sep 15 '22 at 00:06
  • I'm not fixated on _anything_. That was merely my current attempt. The duplicate does seem to correctly indicate that this isn't possible. – isherwood Sep 15 '22 at 12:44

1 Answers1

1

"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>
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • This doesn't meet my requirements. How would you make it fit a container? – isherwood Sep 14 '22 at 19:22
  • It doesn't meet the requirements in the question. No aspect ratio is ever calculated. It simply applies hard-coded values. – isherwood Sep 14 '22 at 19:35
  • Aspect-ratio is that of whatever the viewport is as requested, but a container that has absolute units doesn't adapt to a viewport. Which is why I probably omitted the container (not by choice but by habit). The "hard coded" values are relative units which dynamically change according to viewport. – zer00ne Sep 14 '22 at 19:58
  • @isherwood Updated to fit within a static container. – zer00ne Sep 14 '22 at 23:38
  • That's certainly closer, but it doesn't fit the container. Notice I didn't say "fit _into_". I said "fit". You wouldn't want to merely _fit into_ your clothes. :) --1 for your effort. I appreciate the attempt. – isherwood Sep 15 '22 at 12:41
  • I ended up going with JavaScript. I think the linked duplicate is correct in that it's not possible. – isherwood Sep 15 '22 at 12:43