Scale and Reposition Iframe Like Background-Size: Cover

Scale and reposition iframe like background-size: cover

Similar to Alvaro Menendez's answer, credit needs to go to this answer stackoverflow.com/a/29997746/3400962 by Qwertman. I got as far as using the "padding percentage" trick, but this answer's clever use of viewport units is crucial to this working.

The key to implementing this behaviour is to ensure two things:

  1. That the iframe always maintains the same aspect ratio as its video content 16 : 9. This will ensure that no black "padding" is present around the outside of the video
  2. That the iframe always fills the height or width depending on the size of the viewport

One way to maintain the aspect ratio of an element is to use the "padding percentage" trick which takes advantage of the fact that top and bottom padding uses the width of the element as the basis for their value. Using the formula B / (A / 100) = C% we can calculate the required percentage for the padding. Given the video has a 16 : 9 ratio this translates to 9 / (16 / 100) = 56.25.

The only problem is that in your case the calculation is required for both the horizontal and vertical axis (as we don't know what dimensions the viewport will be) and this trick will not work with left and right padding to get the aspect ratio in relation to the height.

html, body {    height: 100%;    margin: 0;    padding: 0;}.container {    background: #eee;    height: 100%;    overflow: hidden;    padding: 0;    position: relative;}.inner {    left: 50%;    min-height: 43.75%;    padding-top: 56.25%;    position:absolute;    top: 50%;    transform: translate(-50%, -50%);    width: 100%;}.container iframe {    bottom: 0;    height: 100%;    left: 0;    position:absolute;    right: 0;    top: 0;    width: 100%;}
<div class="container">    <div class="inner">        <iframe src="https://player.vimeo.com/video/135335257?autoplay=false" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>    </div></div>

simulate background-size:cover on video or img

Here's how I did this. A working example is in this jsFiddle.

var min_w = 300; // minimum video width allowedvar vid_w_orig;  // original video dimensionsvar vid_h_orig;
jQuery(function() { // runs after DOM has loaded
vid_w_orig = parseInt(jQuery('video').attr('width')); vid_h_orig = parseInt(jQuery('video').attr('height')); $('#debug').append("<p>DOM loaded</p>");
jQuery(window).resize(function () { resizeToCover(); }); jQuery(window).trigger('resize');});
function resizeToCover() { // set the video viewport to the window size jQuery('#video-viewport').width(jQuery(window).width()); jQuery('#video-viewport').height(jQuery(window).height());
// use largest scale factor of horizontal/vertical var scale_h = jQuery(window).width() / vid_w_orig; var scale_v = jQuery(window).height() / vid_h_orig; var scale = scale_h > scale_v ? scale_h : scale_v;
// don't allow scaled width < minimum video width if (scale * vid_w_orig < min_w) {scale = min_w / vid_w_orig;};
// now scale the video jQuery('video').width(scale * vid_w_orig); jQuery('video').height(scale * vid_h_orig); // and center it by scrolling the video viewport jQuery('#video-viewport').scrollLeft((jQuery('video').width() - jQuery(window).width()) / 2); jQuery('#video-viewport').scrollTop((jQuery('video').height() - jQuery(window).height()) / 2);
// debug output jQuery('#debug').html("<p>win_w: " + jQuery(window).width() + "</p>"); jQuery('#debug').append("<p>win_h: " + jQuery(window).height() + "</p>"); jQuery('#debug').append("<p>viewport_w: " + jQuery('#video-viewport').width() + "</p>"); jQuery('#debug').append("<p>viewport_h: " + jQuery('#video-viewport').height() + "</p>"); jQuery('#debug').append("<p>video_w: " + jQuery('video').width() + "</p>"); jQuery('#debug').append("<p>video_h: " + jQuery('video').height() + "</p>"); jQuery('#debug').append("<p>vid_w_orig: " + vid_w_orig + "</p>"); jQuery('#debug').append("<p>vid_h_orig: " + vid_h_orig + "</p>"); jQuery('#debug').append("<p>scale: " + scale + "</p>");};
#video-viewport {  position: absolute;  top: 0;  overflow: hidden;  z-index: -1; /* for accessing the video by click */}
#debug { position: absolute; top: 0; z-index: 100; color: #fff; font-size: 12pt;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div id="video-viewport">  <video autoplay controls preload width="640" height="360">    <source src="http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4"type="video/mp4" />    <source src="http://www.quirksmode.org/html5/videos/big_buck_bunny.webm"type="video/webm" />    <source src="http://www.quirksmode.org/html5/videos/big_buck_bunny.ogv"type="video/webm" />  </video></div>
<div id="debug"></div>

Force iframe YouTube video to center fit and full cover the screen in the background using HTML5 CSS3

For a real full screen solution, this can be achieved like this:

HTML

<div class="video-background">
<div class="video-foreground">
<iframe src="https://www.youtube.com/embed/I4agXcHLySs?controls=0&showinfo=0&rel=0&autoplay=1&loop=1&mute=1" frameborder="0" allowfullscreen></iframe>
</div>
</div>

CSS

* { box-sizing: border-box; }
.video-background {
background: #000;
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
z-index: -99;
}
.video-foreground,
.video-background iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}

@media (min-aspect-ratio: 16/9) {
.video-foreground { height: 300%; top: -100%; }
}
@media (max-aspect-ratio: 16/9) {
.video-foreground { width: 300%; left: -100%; }
}
@media all and (max-width: 600px) {
.vid-info { width: 50%; padding: .5rem; }
.vid-info h1 { margin-bottom: .2rem; }
}
@media all and (max-width: 500px) {
.vid-info .acronym { display: none; }
}

It is not perfect, e.g. it does not work well with extreme aspect ratios of the container, but is doing a great job in most situations. Here is a working example:

https://codepen.io/hnrchrdl/pen/YzPwjBV

Edit: Check Oliver's answer, he seems to have an improved version of this solution.

Fix video to background position, when using background-size cover

Cascading style solution

There is a way to achieve this in pure CSS, but — as usual — it does come with some caveats:

  1. It relies on vh and vw units. These are relatively new, so support for them is not perfect, but it isn't that bad either. Yay for CSS3!

  2. In order for this to work, your target image has to be sized to the viewport, or at least something that relates to the viewport.

  3. It relies on media queries, but then again, so does much of the mobile-enabled interweb.

It may need a little tweaking to get the video exactly where you want it. But it has worked in everything modern I've tested so far.


Explanification

The key point to realise is that when "covering" an image, the browser switches between two ways of scaling the image. This switch happens when the viewport width goes above a certain proportion of the height. That proportion depends on the aspect ratio of the image you are using.

I'd like to say I'm awake enough at the moment to have actually calculated the value used in @media (min-width: 178vh) but if I'm honest, I trialed and errored it. Just know that taking the original dimensions of your image 3264 x 1836, and calculating a ratio from that, 3264 / 1836 = 1.7777777778 leaves you with a certain number. Because vh and vw a 1/100ths of the viewport dimensions, you should multiply this number by a 100 and you get 178 when rounded. This is the switch point. Obviously if you change the dimensions of your original image, you will need to recalculate this and update the media query's selector.

Other than that it's just the simple case of working out what proportion of the viewport your video occupies in terms of vh and vw. Again, this was trial and errored, but in my defense beer seems to increase the likelihood that I'll use that methodology... no idea why.


Ramifications

Ah well, after a bit further testing it seems that webkit doesn't like the vh in the media query — or at least it doesn't seem to be applying. I shall have to investigate as to why. It's possible that it just doesn't support this in max-width which is a shame. There may be a solution in using vmin and vmax however.

Some time later.

Yep. Webkit lets the side down, again. Sorry, hats off to what is a very good browser... it just seems I can always rely on Firefox to do the right thing, Webkit, not so much. Unfortunately if a browser doesn't understand vh and vw in a particular context, there isn't much that can be done, save for falling back to scripting. Annoyingly Webkit does understand the viewport lengths in other contexts, so they have implemented code to handle these values, just not for media queries — as far as I can tell.

There is a slight fix though, it involves using orientation in the media query instead. This isn't perfect, as it fails when the viewport is anything that approximates a square. It definitely decreases the number of different ratios it will fail for however. I've updated the code below.


Concollusions

In the end if I were implementing this (as the browsers currently stand). I'd use the CSS version, and then enhance with JavaScript for browsers that don't support the viewport metrics in media queries. You could do this from scratch using window.matchMedia or a library such as Enquire.js.

I've updated the following with a JavaScript fallback, it should be noted this should be improved upon... most likely by using existing libraries to use cross-browser methods for applying event listeners and adding and removing class names. The current code will override any class names set on the HTML tag, so beware!

/// with thanks to http://stackoverflow.com/questions/3437786/#answer-11744120var viewportDimensions = function(){  var w = window,      d = document,      e = d.documentElement,      g = d.getElementsByTagName('body')[0];  return {    w: w.innerWidth || e.clientWidth || g.clientWidth,     h: w.innerHeight|| e.clientHeight|| g.clientHeight  };};
window.matchMedia && (function(){ var test = window.matchMedia('screen and (min-width: 0vh)'), f; /// this will only fail on browsers that do not support vh in media queries if ( !test.matches ) { /// listen out for resize window.addEventListener('resize', (f=function(e){ /// get the viewport dimensions var vpd = viewportDimensions(); /// run our js based test, same as the media query if ( vpd.w > (1.78 * vpd.h) ) { document.documentElement.className = 'min-width-178vh'; } else { document.documentElement.className = 'max-width-178vh'; } })); /// first run! f(); }})();
/* Shifts the coordinates to the center, because   that is the only fixed coordinate when using   "cover" on an image */.layer {    position: absolute;    left: 50%;    top: 50%;    width: 1px;    height: 1px;}
/* By default base our values on viewport height This is what "cover" is doing, at least when your image is streched to the viewport */.video { position: absolute; width: 25.5vh; left: -50.5vh; top: -22.8vh; background: #F00;}
/* Half fix for webkit, it seems webkit does not support vh and vw in its media queries... why??? This will work as long as the viewport dimension are not squareish */@media screen and (orientation: landscape) { .video { top: -12.75vw; left: -28.5vw; width: 14.2vw; }}
/* Detect when we change scaling/cropping reaction and base our values on viewport width instead */@media screen and (min-width: 178vh) { .video { top: -12.75vw; left: -28.5vw; width: 14.2vw; }}
/* Repeating myself to repair the damage that the webkit fix does to Firefox's handling */@media screen and (max-width: 178vh) { .video { width: 25.5vh; left: -50.5vh; top: -22.8vh; }}
/* These styles override the media queries when called in by the JavaScript fallback */.min-width-178vh .video { top: -12.75vw !important; left: -28.5vw !important; width: 14.2vw !important;}.max-width-178vh .video { width: 25.5vh !important; left: -50.5vh !important; top: -22.8vh !important;}
/* These styles are just for set-up. You don't need to split the background image out into .inner, I just did so to open up options whilst trialing a solution. */.main { top: 0; left: 0; position: absolute; width: 100%; height: 100%;}
.inner { position: absolute; background: url("http://www.codelamp.co.uk/so/cover-video-pos-bg.jpg") no-repeat center center / cover; background-color: #000; width: 100%; height: 100%;}
<div class="main">    <div class="inner"></div>    <div class="layer">        <div class="video">            <video width="100%"></video>        </div>    </div></div>

How to scale an image to cover entire parent div?

http://jsfiddle.net/Log82brL/7/

#img {
width: 100%;
height: 100%;
object-fit: cover;
}

object-fit: cover allows the replaced content is sized to maintain its aspect ratio while filling the element’s entire content box: its concrete object size is resolved as a cover constraint against the element’s used width and height.

iframe background image

Try this:

<iframe scrolling="auto" allowtransparency="true" name="main" style="width:100%;height:90%;background-image:url(img/bg2.jpg)"> </iframe>

if it doesn't work move the background images to the container of the iframe.



Related Topics



Leave a reply



Submit