Simulate Background-Size:Cover on <Video> or <Img>

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 allowed

var vid_w_orig; // original video dimensions

var 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>

Is there an equivalent to background-size: cover and contain for image elements?

Solution #1 - The object-fit property (Lacks IE support)

Just set object-fit: cover; on the img .

body {
margin: 0;
}
img {
display: block;
width: 100vw;
height: 100vh;
object-fit: cover; /* or object-fit: contain; */
}
<img src="https://loremflickr.com/1500/1000" alt="A random image from Flickr" />

Simulation background-size: cover in canvas

It's a bit more complicated to get a cover functionality, though here is one solution for this:

Updated 2016-04-03 to address special cases. Also see @Yousef's comment below.

/**
* By Ken Fyrstenberg Nilsen
*
* drawImageProp(context, image [, x, y, width, height [,offsetX, offsetY]])
*
* If image and context are only arguments rectangle will equal canvas
*/
function drawImageProp(ctx, img, x, y, w, h, offsetX, offsetY) {

if (arguments.length === 2) {
x = y = 0;
w = ctx.canvas.width;
h = ctx.canvas.height;
}

// default offset is center
offsetX = typeof offsetX === "number" ? offsetX : 0.5;
offsetY = typeof offsetY === "number" ? offsetY : 0.5;

// keep bounds [0.0, 1.0]
if (offsetX < 0) offsetX = 0;
if (offsetY < 0) offsetY = 0;
if (offsetX > 1) offsetX = 1;
if (offsetY > 1) offsetY = 1;

var iw = img.width,
ih = img.height,
r = Math.min(w / iw, h / ih),
nw = iw * r, // new prop. width
nh = ih * r, // new prop. height
cx, cy, cw, ch, ar = 1;

// decide which gap to fill
if (nw < w) ar = w / nw;
if (Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh; // updated
nw *= ar;
nh *= ar;

// calc source rectangle
cw = iw / (nw / w);
ch = ih / (nh / h);

cx = (iw - cw) * offsetX;
cy = (ih - ch) * offsetY;

// make sure source rectangle is valid
if (cx < 0) cx = 0;
if (cy < 0) cy = 0;
if (cw > iw) cw = iw;
if (ch > ih) ch = ih;

// fill image in dest. rectangle
ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h);
}

Now you can call it like this:

drawImageProp(ctx, image, 0, 0, width, height);

and it will scale the image proportionally to fit inside in that container.

Use the two last parameters to offset the image:

var offsetX = 0.5;   // center x
var offsetY = 0.5; // center y
drawImageProp(ctx, image, 0, 0, width, height, offsetX, offsetY);

Hope this helps!

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>

YouTube video: fit content on non 16:9 father (as background-size: cover)

Assuming the source video is at least horizontal, this should work.

  1. Check the height of the container
  2. Calculate the aspect ratio of the video
  3. Set the height of the iframe to be equal to the height of the container and set the width by multiplying the (reversed) aspect ratio to the container width.
  4. Position the video absolutely within the container to make sure it's centered.

HTML:

<div class="container">
<iframe src="https://www.youtube.com/embed/ilxhlnDo7_M" frameborder="0"></iframe>
</div>

CSS:

.container {
position: relative;
overflow: hidden;
height: 400px; /* whatever you want */
width: 100%; /* whatever you want */
}

.container iframe {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}

JS:

const container = document.querySelector('.container')
const video = container.querySelector('iframe')
const videoAspectRatio = video.clientWidth / video.clientHeight

video.style.height = `${container.clientHeight}px`
video.style.width = `${container.clientWidth * videoAspectRatio}px`

Seems SO embeds don't support YouTube embedding so I've broken the example out into a fiddle: https://jsfiddle.net/e5bxpuzf/4/

An unfortunate drawback is the "flash of unstyled content" you'll get while the video resizes, I'd suggest fading the video in after it loads to avoid the FOUC.

Here's a fiddle with some different containers as examples. The video will be 100% height of the container and centered horizontally: https://jsfiddle.net/e5bxpuzf/2/

NOTE: I chose not to write a conditional to check if the video height is greater than the width because it seems like it'd be a fringe case. If you need, I can update the fiddle to accommodate.

DIV with video background and image sticking to its bottom doesn't work as expected

The video isn't covering the entire div because it is keeping its aspect-ratio. If you'd prefer to stretch it, you can use CSS's object-fit . As for the image that needs to be cut off 50%, you can use translateY(50%)

CSS:

body {
margin: 0px;
}
#ccontainer {
position:relative;
width:100%;
height:550px;
background: url("http://i.imgur.com/X3mb6AD.jpg");
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
}
#cvideo, #videooverlays {
position:absolute;
top:0;
left:0;
}
#cvideo, #videooverlays, video {
width:100%;
height:100%;
}
video {
image-fit:fill;
object-fit:fill;
}
#vid_top {
position:relative;
top:50px;
width:100%;
height: auto;
}
#vt_logo {float:left; margin-left:50px;}
#vt_url {float:right; margin-right:50px;}
#slogan {position:relative; top:70px; width:100%; height:auto; text-align:center;}
#slogan img {
width:50%;
}
#slogan2 {position:relative; top:70px; width:100%; height:auto; text-align:center;}
#slogan2 img {
width:50%;
}
#icons {position:absolute; bottom:0; width:100%; height:auto; text-align:center;}
#icons img {width:70%;transform:translateY(50%);}
#lipsum {width: 60%; margin: 0 auto;}

HTML:

<div id="ccontainer">
<div id="cvideo">
<video preload="preload" autoplay="autoplay" loop="loop" muted poster="http://i.imgur.com/X3mb6AD.jpg">
<source src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
Your browser does not support HTML5 video.
</video>
</div>
<div id="videooverlays">
<div id="vid_top">
<div id="vt_logo">
<img src="http://i.imgur.com/Od0DZBj.png">
</div>
<div id="vt_url">
<img src="http://i.imgur.com/ns80hYp.png">
</div>
<div style="clear:both;"></div>
<div id="slogan">
<img src="http://i.imgur.com/JrOXRf2.png">
</div>
<div id="slogan2">
<img src="http://i.imgur.com/7mRLS9s.png">
</div>
</div>
<div id="icons">
<img src="http://i.imgur.com/XEEAcQx.png">
</div>
</div>
</div>
<div id="lipsum">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut eu tortor mi. Etiam bibendum pellentesque dignissim. Cras eu massa elit. Ut sit amet metus porta, hendrerit mauris at, elementum massa. Duis malesuada ac odio id faucibus. Mauris malesuada elementum dui luctus tempor. Integer in lacus vel risus dignissim vehicula eget vel purus. Sed non sollicitudin arcu. Cras ac ligula at nisl vulputate fringilla et non est. Etiam placerat volutpat eros id facilisis. Nunc sollicitudin ipsum ipsum, vestibulum rutrum sem dapibus quis.
</p>
<p>
Mauris interdum erat id posuere tempor. Vivamus suscipit nisi nec laoreet pulvinar. Vestibulum luctus libero vel tortor blandit maximus. Proin consequat massa id eros convallis rhoncus. Curabitur et erat finibus, sollicitudin mi ac, suscipit eros. Duis gravida velit elit, vel tempus elit malesuada in. Cras viverra, sapien sed tincidunt bibendum, mauris ligula tempor sem, vitae placerat libero mauris ut neque. Nullam ullamcorper erat est, at laoreet metus imperdiet nec. Nam sit amet gravida quam, nec hendrerit ante. Vestibulum eros ex, lacinia ut tincidunt quis, hendrerit ut felis. Suspendisse in orci sodales, tincidunt leo nec, lobortis dui. Integer ac magna purus. Praesent porta a dolor ut rutrum.
</p>
<p>
Curabitur ac sodales enim, vitae luctus eros. Mauris ac accumsan leo. Vestibulum tristique pretium nibh vel interdum. Duis vitae velit vel neque pretium condimentum. Vestibulum id lacus a nisl rhoncus tempus. Nullam varius quis tellus eget pharetra. Aliquam vitae purus id ex sodales bibendum sed quis dui. Ut bibendum neque turpis, ut vehicula massa egestas eget. Ut maximus sapien a leo porttitor dignissim. Suspendisse varius iaculis turpis non pulvinar. Morbi sit amet pellentesque nulla. Ut non ipsum quis mauris rhoncus luctus. Praesent posuere tincidunt nisl, at rutrum magna aliquet ac. Praesent et ex id sapien rhoncus ultricies non at orci. Donec vel iaculis metus. Donec convallis sit amet nisi id faucibus.
</p>
<p>
Phasellus id commodo risus, ut faucibus elit. Integer ornare blandit magna, ac pharetra neque porta nec. Maecenas consectetur, odio ac maximus fringilla, libero tellus egestas leo, in vulputate elit risus non nulla. Maecenas ac tempor sem. Phasellus placerat sollicitudin orci. Nunc sit amet tellus at sapien semper consequat at quis libero. Duis auctor in tortor sit amet congue.
</p>
<p>
Nunc at venenatis felis. Maecenas in lobortis tortor. Aenean id metus mattis, sodales dui non, ornare est. Donec nec condimentum lorem. Nullam ac nisi consequat, venenatis lorem quis, suscipit tortor. Cras a posuere ex, sodales pellentesque leo. Nulla nibh lectus, tincidunt non metus sit amet, rutrum fringilla quam. Cras id condimentum lectus. Donec et nulla turpis. Duis et nisi iaculis, aliquet orci sit amet, porta massa. Donec finibus vulputate lacus et mattis. Integer laoreet eros ut cursus porta. Proin id lectus elit. Proin imperdiet nec arcu at imperdiet.
</p></div>

Cover-Video in banner element: always centered and full-width and height

Just remove the opacity from the banner and add max-height:100% to make sure that there's no vertical scroll

DEMO

html,

body {

margin: 0;

height: 100%;

}

#banner {

position: relative;

height: 710px;

border: 5px solid tomato;

overflow: hidden;

max-height: 100%;

box-sizing: border-box;

}

#banner .video {

min-width: 100%;

min-height: 100%;

}
<div id="banner">

<video class="video" autoplay>

<source src="http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4" type="video/mp4" />

</video>

</div>


Related Topics



Leave a reply



Submit