Specify the natural size of an HTML element

Calvin picture Calvin · Jul 27, 2012 · Viewed 9.3k times · Source

Let's talk about images in HTML. If I drop an image onto the page with no other constraints, it will assume its "natural size"---that is, the literal size of the image in pixels. If I specify a CSS max-width and max-height then it will keep its natural aspect ratio but scale down to fit the size constraint. Awesome!

I want that exact behavior on an arbitrary element. That is, I want to create a <div> or something else that has a natural size (which I would specify in pixels) and maintains its aspect ratio when affected by max-width and max-height. (Bonus points: it would be cool if the technique also supported min-width and min-height.)

Here is some more information I have collected:

  • For an HTML5 image you can read the natural size of an image with the naturalWidth and naturalHeight attributes, provided the complete attribute is true. Unfortunately, as MDN points out, these properties are read-only and are specific to image elements.

  • This approach is brilliant, but (even though the height responds to max-width) the width does not respond to max-height.

  • A bit of searching has failed to turn up a CSS-only solution, which makes me think that one may not exist. I will also accept JavaScript solutions, but they need to be robust to changes in window size and parent element size.

Answer

Jo&#227;o Paulo Macedo picture João Paulo Macedo · Jul 28, 2012

Here's my super duper solution:

The HTML

<div class="ratioBox">
    <div class="dummy"></div>

     <div class="el">This is the super duper ratio element </div>

</div>

The CSS

.ratioBox{
    position: relative;
    overflow: hidden;      /* to hide any content on the .el that might not fit in it */
    width: 75%;            /* percentage width */
    max-width: 225px;
    min-width: 100px;
    max-height: 112.5px;
    min-height: 50px;  
}

.dummy {
    padding-top: 50%;      /* percentage height */
}

.el {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: silver;
}

​

See it working here: http://jsfiddle.net/joplomacedo/7rAcH/

The explanation, in case you can't understand what is happening, will come at the end of the day as I'm unfortunately out of time. [it's July 28, 2:54PM (GMT Time) as I write this]