6

I have found this css code that allows me to keep a div's aspect ratio.

.container {
  width: 100%;
  height: 100%;
  background-color: red;
  position: absolute;
 }


.wrapper {
  width: 100%;
  /* whatever width you want */
  display: inline-block;
  position: relative;
  top: 50%;
  transform: translate(0%, -50%);
}
.wrapper:after {
  padding-top: 56.25%;
  /* 16:9 ratio */
  display: block;
  content: '';
}
.main {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
 /* fill parent */
  background-color: deepskyblue;
  /* let's see it! */
  color: white;
}

See this JSFiddle example: https://jsfiddle.net/1uyo07tg/3/

I would like a css-only solution (without the use of VW or VH) to keep this aspect ratio even when the parent is wider than the aspect ratio in question (in this case, 16:9).

In other words, I would like the blue-colored div to stay at 16:9 ratio even when the parent (.container) is stretched wider than 16:9.

Clarifying - i would like some css-only solution, to have a child div stay always in a fixed ratio, centered vertically and horizontally, no matter the size or aspect ratio of the parent div, and without using vw,vh. I am pretty sure this needs JS code (which I have), but just wanted to see if someone has a css-only neat trick for it.

Bottom line - looking for this functionality in CSS only, no vh or vw.

Hope that makes sense. Any ideas?

Thanks in advance, Sa'ar

Saariko
  • 502
  • 6
  • 21

2 Answers2

10

CSS "contain" for elements. Preserve aspect ratio

CSS contain with aspect ratio for elements

  • Use CSS flex with centered content on a parent Element
  • Use the aspect-ratio CSS property.
  • Use an :after element to force the box's aspect-ratio initial state

/* QuickReset */ * { margin: 0; box-sizing: border-box; }

#parent {
  /* This can be just any element with responsive W/H */
  min-height: 100vh;
  background-color: red;
  position: relative;
}

#aspectRatio {
  background-color: #0bf;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  max-width: 100%;
  max-height: 100%;
  aspect-ratio: 16 / 9;
}
<div id="parent">
  <div id="aspectRatio">Lorem</div>
</div>

Here's another example Fixed header and footers, aspect ratio body

JavaScript solution:

Here I created a JS implementation if you're interested in the intricacies and calculation:

JS contain with aspect ratio for elements

const contain = (EL, rx, ry) => {
  // We need to rely on JS since Firefox is still experimental with aspect-ratio
  // https://stackoverflow.com/a/66721382/383904

  const scale = 1.0; // 1 = max parent size. 0.8 = scale down
  const margin = 0;  // PX gutter around the box

  rx *= scale;
  ry *= scale;
  const parent = EL.parentElement;
  const pw = parent.offsetWidth * scale - margin;
  const ph = parent.offsetHeight * scale - margin;
  // If H should apply instead of W and vice versa
  const isSwap = pw / ph > rx / ry;
  const w = isSwap ? (ph / ry) * rx : pw;
  const h = isSwap ? ph : (pw / rx) * ry;
  EL.style.cssText = `width: ${w}px; height: ${h}px;`;
};


const ELS_aspectRatio = document.querySelectorAll(".ar-box");
const applyContain = () => ELS_aspectRatio.forEach(EL => contain(EL, 16, 9));

window.addEventListener("resize", applyContain);
applyContain();
* { margin: 0; box-sizing: border-box; }

/* DEMO ONLY: This can be any responsive parent with any responsive unit! */
#parent { 
  width: 100vw;
  height: 100vh;
  background-color: red;
  display: flex;
  justify-content: center;
  align-items: center;
}

.ar-box {
  background-color: #0bf;
}
<div id="parent">
  <div class="ar-box">Contain using JS</div>
</div>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
  • This worked very well for me. Thank you. I wonder if you'd be able to elaborate on how to get the CSS solution done with a sticky footer? https://stackoverflow.com/questions/71145799/fixed-header-and-footers-aspect-ratio-body – goodson Feb 16 '22 at 16:42
-1
body,html {
  margin: 0;
  height: 100%;
  width: 100%;
}
.container {
  width: 100%;
  height: 100%;
  background-color: red;
  overflow: hidden;
}     
.wrapper {
  width: 100%;
  max-width: calc(100vh / 0.5625);
  padding-top: 56.25%;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: deepskyblue;
}

.main is even not nessary

Chibiao.Wang
  • 396
  • 2
  • 5
  • thanks so much. I forgot to mention in my question: no VH or VW. Is it still possible without it? – Saariko Nov 21 '16 at 12:29
  • sorry I can't. Without VH I can't compare the window height with its width, which means it's hard to confirm the BODY can always contain the wrapper box. – Chibiao.Wang Nov 21 '16 at 15:19
  • what about a background-image(16:9 ratio) with background-size:contain and background-position:50%... – Chibiao.Wang Nov 21 '16 at 15:32
  • thanks, but i need the child div to be a container, not just an image. I updated the question with clarification – Saariko Nov 22 '16 at 13:27