Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 980
Drew Baker Avatar asked Dec 26 '22 20:12

Drew Baker


2 Answers

Three issues noted:

  1. You have an error (trailing quote) in your example:

    :newWidth'

  2. You need to set the iframe actual height and width attributes and not the style. Styling an iframe size has no effect:

    $(this).width(newWidth);
    $(this).height(newHeight);
    
  3. the calculation for aspect ratio was wrong (needs to compare ratios to see which way they overlap). Without this not all overlap cases are catered for.

    var aspect = width/height;
    var parentAspect = parentWidth/parentHeight;
    if (aspect > parentAspect)
    {
        newWidth  = parentWidth;
        newHeight = newWidth / aspect;
    }
    else
    {
        newHeight = parentHeight;
        newWidth  = newHeight * aspect;
    }
    

I also cleaned up the code a little to speed up element access. Each call to jQuery(this) costs cycles.

JSFiddle here: http://jsfiddle.net/TrueBlueAussie/ZJDkF/8/

Updates:

The jsfiddle now has examples of the 4 different scenarios of overlap and each retains the proportions of the iframe. I also added the window resize you mentioned and made the first div resize dynamically with it to demonstrate.

like image 196
Gone Coding Avatar answered Feb 20 '23 21:02

Gone Coding


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!

like image 42
Drew Baker Avatar answered Feb 20 '23 19:02

Drew Baker