Maintaining aspect ratio with min/max height/width?
Asked Answered
P

4

32

I have a gallery on my site where users can upload images.

I would like the images to sit in a div that maintains its height, the images should be no larger than 500px in height. The width should be automatic to maintain aspect ratio.

HTML:

<div id="gallery">
    <img src="uploads/my-dynamic-img.jpg">
</div>

I've tried this CSS:

#gallery{
    height: 500px;

    img{
        max-height: 500px;
        max-width: 100%;
    }
}

The above works well, the gallery is always 500px high and images never exceed 500px in height. I run into problems though with smaller images, if a user uploads a really small image, I would like it 'blown up' to a minimum of 200px. I know this can be achieved by setting a min-height on the image, the problem with this is, if the image is less than 200px in height but say, 2000px wide, the image gets blown up to 200px in height, but then the aspect ratio is screwed, as the image is wider than the images parent div.

How can I have a min height but retain aspect ratio?

Pneumatophore answered 23/11, 2014 at 21:48 Comment(3)
That's not CSS syntax -- are you using a language like SASS or Stylus or is that just an error?Sculpsit
The first thing that comes to my mind is using background images with background-size: contain, but that wouldn't work if you need to cover <= IE8.Sculpsit
if you have control over the html output, use server-side processing to determine the aspect ratio, then add a "wide" or "tall" class and handle their styling separately. If you don't have control over html, than use javascript to do the same thing, and again, style them separately.Sleeper
B
46

The property you're looking for is object-fit. This is one of Opera's innovations, you can read more about it in their 2011 dev article on object-fit (yep, it's been around that long). A few years ago, I wouldn't have been able to recommend it to you, but caniuse shows that everyone else is starting to catch up:

  • Opera 10.6-12.1 (-o- prefix)
  • Chrome 31+
  • Opera 19+
  • Safari 7.1+
  • iOS 8+
  • Android 4.4+

http://caniuse.com/#search=object-fit

#gallery img {
    -o-object-fit: contain;
    object-fit: contain;
}

Using a value of contain will force the image to maintain its aspect ratio no matter what.

Alternately, you might want to use this instead:

#gallery img {
    -o-object-fit: cover;
    object-fit: cover;
    overflow: hidden;
}

http://sassmeister.com/gist/9b130efdae95bfa4338e

Belen answered 23/11, 2014 at 23:16 Comment(4)
As of Microsoft Edge, this still has not been implemented. However, they state that it is under consideration for Edge. https://developer.microsoft.com/en-us/microsoft-edge/platform/status/objectfitandobjectposition/Chewy
One problem with this sullotion is that it only forces the actual image and not the img-tag to contain proportions, so if you for example put a border on the image tag it won't keep the proportions: jsfiddle.net/pwxca5afSupercharger
Thanks! It works perfectly if you want to define places were will be an image but you still haven't load it yet because of network delay. I'm combining it with lazy load on a big grid of 4x20 image elements.Overalls
@Chewy it seems that today Edge has object-fit implemented. It works!Overalls
D
7

The only way that I know of to possibly accomplish this is by setting either the width or height to auto.

#gallery{
    height: 500px;

    img{
        max-height: 500px;
        width: auto;
    }
}
Deem answered 23/11, 2014 at 23:6 Comment(0)
R
0

I don't know if this is possible using only CSS.

However, you may be able to accomplish the same thing with a few lines of JavaScript:

var img= document.querySelectorAll('img');
for(var i = 0 ; i < img.length ; i++) {
  img[i].onload= function() {
    var h= this.naturalHeight;
    h= Math.min(500,Math.max(200,h));
    this.style.height= h+'px';
  }
}

This sets the height of all images to be between 200px and 500px. The width will automatically be scaled.

var img= document.querySelectorAll('img');
for(var i = 0 ; i < img.length ; i++) {
  img[i].onload= function() {
    var h= this.naturalHeight;
    h= Math.min(500,Math.max(200,h));
  }
}
#gallery{
  height: 500px;
  width: 400px;
  overflow: hidden;
}
<div id="gallery">
  <img src="http://cdn.sstatic.net/stackexchange/img/logos/so/so-logo-med.png">

</div>
Ricks answered 23/11, 2014 at 22:12 Comment(1)
I left out this.naturalHeight from my original post, so the image height would always be either 200px or 500px. Now it can take on values in between.Ricks
J
0

I've been meaning to do something similar, actually. Here's something in jQuery if you're into that.

SCSS:

#gallery {
  height: 500px;

  img {
    max-height: 100%;
  }

  .small {
    width: 100%;
    max-width: 500px;
    height: auto;
  }

  .regular {
    width: auto;
    min-height: 200px;
  }
}

jQuery:

$( 'img' ).each( function() {

  var imageWidth = parseFloat( $( this ).css( 'width' ) );
  var imageHeight = parseFloat( $( this ).css( 'height' ) );

  if( imageHeight <= 200 && imageWidth >= 200 ) {
    $( this ).addClass( 'small' );
  }
  else {
    $( this ).addClass( 'regular' );
  }
});

CodePen

Jakejakes answered 24/11, 2014 at 1:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.