Search code examples
jqueryscaleaspect-ratio

Proportionally resize iframe to fit in a DIV using jQuery


I have an iframe of a video inside a div, like so:

<div class="media">
    <iframe>
</div>

I set the DIV's size dynamically on window resize.

I want to scale the iframe to fit inside the div, while maintaining it's aspect ratio. Most of the code out there deals with scaling images, which is easier.

This is what I have so far, but it doesn't work:

jQuery.fn.fitToParent = function()
{
    this.each(function()
    {
        var width  = jQuery(this).width();
        var height = jQuery(this).height();
        var parentWidth  = jQuery(this).parent().width();
        var parentHeight = jQuery(this).parent().height();

        if(width < parentWidth)
        {
            newWidth  = parentWidth;
            newHeight = newWidth/width*height;
        }
        else
        {
            newHeight = parentHeight;
            newWidth  = newHeight/height*width;
        }

        jQuery(this).css({
            'height'     :newHeight,
            'width'      :newWidth'
        });
    });
};

Basically, I'm looking to replicate the sizing that "background-size: contain" does for images in CSS, but for an iframe in a DIV.

Thanks for the help!


Solution

  • I have really improved on the answer from @TrueBlueAussie over time, and thought I'd post a more sophisticated answer here for future reference.

    Made it a plugin on GitHub here: https://github.com/drewbaker/fitToParent

    Here is the jQuery plugin:

    jQuery.fn.fitToParent = function (options) {
    
        this.each(function () {
    
            // Cache the resize element
            var $el = jQuery(this);
    
            // Get size parent (box to fit element in)
            var $box;
            if( $el.closest('.size-parent').length ) {
                $box = $el.closest('.size-parent');
            } else {
                $box = $el.parent();
            }
    
            // These are the defaults.
            var settings = jQuery.extend({  
                    height_offset: 0,
                    width_offset: 0,
                    box_height: $box.height(),
                    box_width: $box.width(),
            }, options );
    
            // Setup box and element widths
            var width = $el.width();
            var height = $el.height();
            var parentWidth = settings.box_width - settings.width_offset;
            var parentHeight = settings.box_height - settings.height_offset;
    
            // Maintin aspect ratio
            var aspect = width / height;
            var parentAspect = parentWidth / parentHeight;
    
            // Resize to fit box
            if (aspect > parentAspect) {
                newWidth = parentWidth;
                newHeight = (newWidth / aspect);
            } else {
                newHeight = parentHeight;
                newWidth = newHeight * aspect;
            }
    
            // Set new size of element
            $el.width(newWidth);
            $el.height(newHeight); 
    
        });
    };
    

    So, assuming you have HTML of this:

    <div id="wrapper">
        <iframe width="720" height="405" src="//player.vimeo.com/video/19223989"></iframe>
    </div>
    

    The most basic way to call the plugin is like this:

    jQuery('#wrapper iframe').fitToParent();
    

    But I'll often set #wrapper to be close to window height and width, like this:

    // Get window height and width
    var winHeight = jQuery(window).height();
    var winWidth = jQuery(window).width();
    
    // Set wrapper height/width to that of window
    jQuery('#wrapper').height(winHeight).width(winWidth);
    
    // Size Iframe
    jQuery('#wrapper iframe').fitToParent({
        height_offset: 100, // Put some space around the video
        width_offset: 100, // Put some space around the video
    });
    

    You can also feed in a custom box size to fit the element in, like this:

    // Get window height and width
    var winHeight = jQuery(window).height();
    var winWidth = jQuery(window).width();
    
    // Size element
    jQuery('#wrapper iframe').fitToParent({
        height_offset: 100, // Put some space around the video
        width_offset: 100, // Put some space around the video
        box_height: winHeight, // Force use of this box size
        box_width: winWidth // Force use of this box size
    });
    

    I've also added the ability to set a CSS class of "size-parent" to a parent element, and it will then use that parent element for the box size. A full example of that:

    // HTML like this
    <div id="wrapper" class="size-parent">
        <div class="media">
            <iframe width="720" height="405" src="//player.vimeo.com/video/19223989"></iframe>
        </div>
    </div>
    
    // jQuery like this
    jQuery('.media iframe').fitToParent();    
    

    If you don't set a .size-parent, it will fallback to the element parent. If you set the box_height/box_width parameter, then those override everything obviously.

    Now, to show how powerful this can be, try this for a vertically centered, horizontal centered aspect ratio correct iFrame!

    // CSS like this
    #wrapper {
        text-align: center;
        display: table-cell;
        vertical-align: middle;
    }
    #wrapper iframe {
        display: inline-block;
    }
    
    // HTML like this
    <div id="wrapper" class="size-wrapper">
        <iframe width="720" height="405" src="//player.vimeo.com/video/19223989"></iframe>
    </div>
    
    // jQuery like this
    // Get window height and width
    var winHeight = jQuery(window).height();
    var winWidth = jQuery(window).width();
    
    // Size wrapper
    jQuery('#wrapper').height( winHeight ).width( winWidth );
    
    // Size element
    jQuery('#wrapper iframe').fitToParent({
        height_offset: 200, // Put some space around the video
        width_offset: 200, // Put some space around the video
    });
    
    // Fit iFrame to wrapper
    jQuery('#wrapper iframe').fitToParent();
    

    In real life, I wrap the jQuery in a function, and then call that function on window resize for true responsive iFrames!