2

I've been trying to scale images to fit a parent container. Here's my code:

Markup

<ul class="slides">
    <li class="scale"><img src="<?php echo $attachments->src('full'); ?>" /></li>
    <li class="scale"><img src="<?php echo $attachments->src('full'); ?>" /></li>
    <li class="scale"><img src="<?php echo $attachments->src('full'); ?>" /></li>
    <li class="scale"><img src="<?php echo $attachments->src('full'); ?>" /></li>
    <li class="scale"><img src="<?php echo $attachments->src('full'); ?>" /></li>
</ul>

CSS

.fullWidth {
    width:100%;
    height:auto;
}
.fullHeight {
    width:auto;
    height:100%;
}

JS

$('.scale img').each(function(){
    var img = $(this);

    if (img.height() < img.width()){
        img.addClass('fullWidth');
    } else {
        img.addClass('fullHeight');
    }
});

What's weird is that although some images are portrait and some are landscape, the JS gives all the images the fullHeight class. I want the images to scale and resize as it's parent does, as the parents use percentage dimensions. I've tried many plugins but none seem to work for me. Anyone got an idea?

CoreyRS
  • 2,227
  • 3
  • 26
  • 44
  • I think this will help you: http://stackoverflow.com/questions/18838963/proportionally-scale-iframe-to-fit-in-a-div-using-jquery/25222380#25222380 – Drew Baker Aug 24 '14 at 19:12

2 Answers2

1

Unless you are waiting for all the images to finish loading, then .height() and .width() will not return proper values as those values are only valid when the image has loaded. If they both return zero or undefined, then you will get the fullHeight class on all of them.

The solution here will be to use onload handlers and set the class when the image is loaded. Because images in the markup may load before your JS runs (particularly if they are in the browser cache), you will either have to check if the image is loaded and use it's height and width if loaded or, if not loaded yet, you will need to set an onload handler. Or, you can assign an onload handler in the markup with onload so that you're sure the load handler is installed before it loads.

Here's one way that checks to see if the image is loaded and adapts based on that:

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

    function setClass() {
        var img = $(this);
        if (img.height() < img.width()){
            img.addClass('fullWidth');
        } else {
            img.addClass('fullHeight');
        }
    }

    // if the image is loaded, then we can set the class now
    if (this.complete) {
        setClass.call(this);
    } else {
        // otherwise, must set class in load handler when it is loaded
        this.onload = setClass;
    }

});

If you can modify the markup, then you can do this which has the advantage of it's always set immediately as soon as the image loads:

Markup:

<ul class="slides">
    <li class="scale"><img onload="scaleDynamic()" src="<?php echo $attachments->src('full'); ?>" /></li>
    <li class="scale"><img onload="scaleDynamic()" src="<?php echo $attachments->src('full'); ?>" /></li>
    <li class="scale"><img onload="scaleDynamic()" src="<?php echo $attachments->src('full'); ?>" /></li>
    <li class="scale"><img onload="scaleDynamic()" src="<?php echo $attachments->src('full'); ?>" /></li>
    <li class="scale"><img onload="scaleDynamic()" src="<?php echo $attachments->src('full'); ?>" /></li>
</ul>

Code:

// this must be a global function
function scaleDynamic() {
    var img = $(this);
    if (img.height() < img.width()){
        img.addClass('fullWidth');
    } else {
        img.addClass('fullHeight');
    }
}

FYI, if any of these images might be visible as they load, then you may want to set their default style to be visibility: hidden and when they finish loading, set the style to visibility: visible when you've set the scaling class and the image is loaded.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • This is right. Generally, you should specify a default height and width for the containing box or for the images so that when the first image loads, it fills that height/width, which you can then tweak later. – Chris Krycho May 14 '13 at 02:14
  • every image is still being given the fullHeight class. this is what has been throwing me, the images are always read as the same - even for landscape images it is basically saying the height is greater. – CoreyRS May 14 '13 at 02:24
  • @CoreyRS - put `console.log()` statements in to print out the values from `.width()` and `.height()` to see what's going on. If you want further help from us, you'll probably have to provide a debuggable example (e.g. a jsFiddle) so we can set breakpoints and see what's going on. – jfriend00 May 14 '13 at 02:30
  • @CoreyRS - I would add that using "100%" height and width is sometimes a bit tricky in CSS so you should make sure that it's the class that is wrong and not an issue with your CSS. Again something you can verify with the DOM inspector and/or debugger. – jfriend00 May 14 '13 at 02:51
0

For a pure JQuery solution - set the image to be 100% width and height and scale its wrapper through JQuery:

HTML

<img class="fullSize" src="">

CSS

.fullSize{
   width:100%;
   height:100%;
}

JQuery

$(document).ready(function(){
function scaleContainer(){
    //check height based on 100% window width
    var expectedHeight =  ($(window).width() * flashHeight) / divWidth;
    if(expectedHeight <= $(window).height()){

        //height is within the window - we can set width to 100%


        $('.divWrapper').css('width', $(window).width()+'px');
        $('.divWrapper').css('height', expectedHeight+'px');



    }else{
        //height doesn't fit - set Height to 100% and scale width
        var scaledWidth = (divWidth*$(window).height())/flashHeight;



        $('.divWrapper').css('width', scaledWidth+'px');
        $('.divWrapper').css('height', $(window).height()+'px');    


    }


}
scaleContainer();


$(window).resize(function() {
    scaleContainer();           
});//window resize



});
Tomer Almog
  • 3,604
  • 3
  • 30
  • 36