Maintain aspect ratio with a fixed height
Asked Answered
U

1

3

So I want to maintain a specific aspect ratio of a div, where the height is fixed. In the past I have done this, but only when using a fixed width like this:

.one-one {
  position: relative;
}
.one-one:before {
  display: block;
  content: " ";
  width: 100%;
  padding-top: 56.25%;
  /* Ratio of 16:9 (16w:9h)
   * (h / w) * 100 = %
   * (9 / 16) * 100 = %
   * 0.5625 * 100 = 56.25%
   * 1:1 = 100%
   */
}

So that's how I would do it using a fixed width of 100% in this example. However, this time I want to make an iPhone mockup where there is a fixed height of 100% and the ratio is 4:7 (4w:7h). Using a fixed height, I can set a height of 100% and a max-height of 100% so it doesn't overflow off the page while still keeping the 4:7 ratio. So, does anyone know how you would do that? Either using this method or another method.

Thanks for any help!

Unreflective answered 6/9, 2015 at 15:4 Comment(6)
You want the full height of the screen, and a width of 4/7 of the height, is that correct? On a phone with a 16:9 screen, that would cause a horizontal scrollbar to appear in portrait mode, are you all right with that?Stolid
And in landscape mode, it would mean that two thirds of the screen would go unused.Stolid
@MrLister Yes, so it would always be 4w:7h, where the height is 100%. I'm not sure what you mean in your use case? But, I think I would set a max-width so that it doesn't overflow that way either. Anyway, one step at a time, first I'd like to be able to set the aspect ratio with 4:7 and we'll go from there! For now, I'd be happy with the horizontal scrollbar.Unreflective
@MrLister That's ok if the screen is unused, it's just for my own learning purposes.Unreflective
Have you looked into css3-viewports? w3.org/TR/css3-values/#viewport-relative-lengthsCassiodorus
@Teolha Yes, but I wanted something that would be supported on most browsers. I'm not a fan of using 100vh etc. because every time I use it I end up with a bunch of devices/browsers which are broken.Unreflective
W
2

You can:

  • Place a replaced element with the desired ratio inside your target element.

    For example, it can be an image with the desired intrinsic sizes, or a canvas.

    Style this replaced element with height: 100%, so that it spans the entire target element.

    Let it have the default width: auto, so that its width respects the aspect ratio.

    Style it with display: block to avoid the extra space below image problem.

  • Make the target element use the shrink-to-fit width algorithm to calculate its width, so that it "inherits" the aspect ratio of the replaced element.

    For example, you can achieve this by floating it or with display: inline-block.

  • If you want the target element to have contents, place them in an absolutely positioned wrapper in order to prevent them from altering the sizes of the target element.

    Make that wrapper as big as the target element with top:0; right:0; bottom:0; left:0, and make the target element its relative container.

This should work. However, for some reason browsers do not seem to update the width when the window is resized, so it only works initially. Forcing a rerender with JS solves this problem.

var s = document.getElementById('aspect-ratio'),
    p = s.parentNode,
    n = s.nextSibling;
window.addEventListener('resize', function() {
  // Force a rerender
  p.removeChild(s);
  p.insertBefore(s, n);
});
html, body {
  height: 100%;
  margin: 0;
}
#aspect-ratio {
  height: 100%;       /* Some fixed height */
  float: left;        /* Shrink-to-fit width */
  position: relative; /* Containing block for #contents */
  background: orange;
}
#aspect-ratio > canvas {
  height: 100%;       /* Span #aspect-ratio entirely */
  display: block;     /* Remove space below canvas */
}
#aspect-ratio > #contents {
  overflow: auto;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
<div id="aspect-ratio">
  <canvas height="16" width="9"></canvas>
  <div id="contents">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</div>
</div>
Welldone answered 6/9, 2015 at 16:6 Comment(3)
Strangely resizing the window updates the height but not the width. I think that contravenes w3c standards. Reloading the page works, though.Welldone
The width doesn't actually change in this example? If I try this then the height is always 100% but the width doesn't actually change at all.Unreflective
@Unreflective I fixed the problem here. It needs a rerender with JS. See updated answer.Welldone

© 2022 - 2024 — McMap. All rights reserved.