Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scale a div to fit in window but preserve aspect ratio

People also ask

How do I keep my div aspect ratio?

In the HTML, put the player <iframe> in a <div> container. In the CSS for the <div>, add a percentage value for padding-bottom and set the position to relative, this will maintain the aspect ratio of the container. The value of the padding determines the aspect ratio. ie 56.25% = 16:9.

How do I fit an image IMG inside a div and keep the aspect ratio?

Answer: Use the CSS max-width Property You can simply use the CSS max-width property to auto-resize a large image so that it can fit into a smaller width <div> container while maintaining its aspect ratio.

How do you make a div scale proportionally?

For proportional resizing purposes, it makes matters extremely simple: Define the width of an element as a percentage (eg: 100%) of the parent's width, then define the element's padding-top (or -bottom) as a percentage so that the height is the aspect ratio you need. And that's it!

How do you maintain aspect ratio in CSS?

In order to maintain the aspect ratio of a div with CSS create flexible elements that keep their aspect ratio (4:3, 16:9, etc.) when resize the browser window.


You don't need javascript for this. You can use pure CSS.

A padding-top percentage is interpreted relative to the containing block width. Combine it with position: absolute on a child element, and you can put pretty much anything in a box that retains its aspect ratio.

HTML:

<div class="aspectwrapper">
  <div class="content">
  </div>
</div>

CSS:

.aspectwrapper {
  display: inline-block; /* shrink to fit */
  width: 100%;           /* whatever width you like */
  position: relative;    /* so .content can use position: absolute */
}
.aspectwrapper::after {
  padding-top: 56.25%; /* percentage of containing block _width_ */
  display: block;
  content: '';
}
.content {
  position: absolute;
  top: 0; bottom: 0; right: 0; left: 0;  /* follow the parent's edges */
  outline: thin dashed green;            /* just so you can see the box */
}

The display: inline-block leaves a little extra space below the bottom edge of the .aspectwrapper box, so another element below it won't run flush against it. Using display: block will get rid of it.

Thanks to this post for the tip!


Another approach relies on the fact that browsers respect an image's aspect ratio when you resize only its width or height. (I'll let google generate a 16x9 transparent image for demonstration purposes, but in practice you would use your own static image.)

HTML:

<div class="aspectwrapper">
  <img class="aspectspacer" src="http://chart.googleapis.com/chart?cht=p3&chs=160x90" />
  <div class="content">
  </div>
</div>

CSS:

.aspectwrapper {
  width: 100%;
  position: relative;
}
.aspectspacer {
  width: 100%; /* let the enlarged image height push .aspectwrapper's bottom edge */
}
.content {
  position: absolute;
  top: 0; bottom: 0; right: 0; left: 0;
  outline: thin dashed green;
}

Thanks to Geoff for the tip on how to structure the math and logic. Here's my jQuery implementation, which I'm using to size a lightbox so it fills the window:

var height = originalHeight;
var width = originalWidth;
aspect = width / height;

if($(window).height() < $(window).width()) {
    var resizedHeight = $(window).height();
    var resizedWidth = resizedHeight * aspect;
}

else { // screen width is smaller than height (mobile, etc)
    var resizedWidth = $(window).width();
    var resizedHeight = resizedWidth / aspect;      
}

This is working well for me right now across laptop and mobile screen sizes.


I have a different pure HTML/CSS approach which does not rely on padding or absolute positioning. Instead it uses em units and relies on the CSS min() function plus a little bit of math.

Imagine that we want a viewport div with 16:9 aspect ratio which always fits the browser window and is centered in the axis with excess space. Here's how we can accomplish that:

HTML

  <body>
    <div class="viewport">
      <p>
        This should be a 16:9 viewport that fits the window.
      </p>
    </div>
  </body>

CSS

body {
  width: 100vw;
  height: 100vh;
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: white;
  font-size: min(1vw, 1.778vh);
}

div.viewport {
  width: 100em;
  height: 56.25em;
  background-color: lightblue;
}

div.viewport > p {
  font-size: 3em;
  text-align: center;
}

You can experiment with this in a sample JSFiddle here.

The secret sauce is in the body font-size. It should be set to min(1vw, Avh), where A is the aspect ratio you want the div to have, i.e. width / height. In the example above we're using 1.778, which is approximately 16 / 9.

In CSS, em units are based on the font-size of the element, which is inherited from parent element if not explicitly set. For your viewport div, set the width to 100em (NOT rem) and the height to Iem, where I is the inverse of the aspect ratio expressed as a percentage, i.e. 100 / A or 100 * height / width. In the example above we're using 56.25, which is 100 * 9 / 16.

One bonus of this approach is that all of your nested elements may also use em units so that they always scale precisely with the size of the viewport. You can see this used on the p element in the example.

Note that as an alternative to the above, you may set the font-size on your html element and use rem units everywhere. CSS rem units are similar to em units but always relative to the root element's font-size.


This is possible with JQuery and a bit of maths.

Use JQuery to get the view ports width and height as well as the divs current dimensions.

$(document).width();

Calculate the divs current aspect ratio. eg width/height

You need a bit of logic to determine whether to set the width or height first, then use the initial ratio to calculate the other side.


jQuery has a plugin that grows an object until one of it's sides reaches a certain px-value. Coupling this will the viewport's height, you could expand any element to that size: jQuery MaxSide.