Saariko
Saariko

Reputation: 512

Keeping div aspect ratio and centered regardless of parent's aspect ratio

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

Upvotes: 7

Views: 2874

Answers (2)

Roko C. Buljan
Roko C. Buljan

Reputation: 206102

CSS "contain" for elements. Preserve aspect ratio

CSS contain with aspect ratio for elements

  • Set position: absolute with top,right,bottom,left positions, or just the inset rule to 0
  • setmargin: 0 to center it
  • set aspect-ratio CSS property
  • finally, set max-width and max-height to 100% for the contain magic

/* 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;
  inset: 0;    /* or use: top:0; right:0; bottom:0; left:0;*/
  margin: auto;
  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>

Upvotes: 17

Chibiao.Wang
Chibiao.Wang

Reputation: 394

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

Upvotes: -1

Related Questions