I would like to have my element keep its aspect ratio but act as a 'full-bleed' or rather full browser experience. The video should up or down to accommodate the new browser window dimensions, but also be centered in the browser window. At times, some video will get cropped – that's ok with me. I am trying to recreate the background cover CSS property for the video element using pure JS, if that helps you to imagine it. For those who do not know what that is, heres the following:
.bkgdCover{
background: no-repeat center center;
-webkit-background-size: 100% 100%;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
The following is my attempt to do the same in pure javascript:
function getWinSize(){
var wid = 0, hei = 0;
if (document.documentElement && document.documentElement.clientHeight){
wid = parseInt(window.innerWidth,10);
hei = parseInt(window.innerHeight,10);
} else if (document.body){
wid = parseInt(document.body.offsetWidth,10);
hei = parseInt(document.body.offsetHeight,10);
}
return [wid,hei];
}
this.resize2 = function(){
fullBleedVideoPlayer();
};
function fullBleedVideoPlayer() {
var viewport=getWinSize();
var videoRatio = 1080 / 1920;
var browserHeight = viewport[0];
var browserWidth = viewport[1];
var tmp_windowRatio = viewport[1] / viewport[0];
if (videoRatio > tmp_windowRatio) {
tmp_height = Math.round(browserWidth * videoRatio);
_player.style.width= browserWidth+ "px";
_player.style.height= tmp_height+ "px";
_player.style.marginLeft = 0 + 'px';
_player.style.marginTop = -Math.round((tmp_height - browserHeight) / 2) + 'px';
} else {
tmp_width = Math.round(browserHeight * (1 / videoRatio));
_player.style.width= tmp_width+ "px";
_player.style.height= browserHeight+ "px";
_player.style.marginLeft = -Math.round((tmp_width - browserWidth) / 2) + 'px';
_player.style.marginTop = 0 + 'px';
}
}
Unfortunately, this does not reproduce CSS cover. If you can see where I made a mistake or have done the same yourself, I'd love to hear from you. Only pure JS solutions please.
I just did something like this except it wasn't completely full screen, it was the background video of a page header which had a height of 450px'ish'. I say ish because I'm using 25vw and it's changing height based on viewport width. I basically wanted the video to stay centered, but how?
HTML
<section id="homepage--hero">
<div class="fullpage-video-wrapper">
<video id="video_background" preload="auto" autoplay="true" loop="loop" muted="muted" volume="0">
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm">
<!-- doesnt support video -->
<img src="#" style="width: 100%; height: auto;" />
</video>
</div>
</section>
CSS
#homepage-hero {
display: block;
height: 35vw;
width: 100%;
position:
relative;
overflow: hidden;
}
.fullpage-video-wrapper {
position: absolute;
bottom: 0px;
left: 0px;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
z-index: -1000;
overflow: hidden;
}
.fullpage-video-wrapper {
min-height: 100%;
min-width: 100%;
}
JS
if( $('.fullpage-video-wrapper').length > 0 ) {
var videoWrapper = $('.fullpage-video-wrapper'),
videoParentWrapper = $(videoWrapper).parent();
if($(videoWrapper).height() > $(videoParentWrapper).height() ) {
var difference = ($(videoWrapper).height() - $(videoParentWrapper).height()) / 4
$(videoWrapper).css({
bottom: -parseInt(difference)
});
}
$(window).resize(function(){
if($(videoWrapper).height() > $(videoParentWrapper).height() ) {
var difference = ($(videoWrapper).height() - $(videoParentWrapper).height()) / 4
$(videoWrapper).css({
bottom: -parseInt(difference)
});
}
});
}
What this does is makes the video stay the same aspect ratio even when resizing window, positions it to the bottom of the homepage-hero, which this caused it to respond well without causing you to see the background color of the video-wrapper, but obviously not centered.
The jQuery is just setting the videowrapper to be offset the difference in height of the video wrapper element height and it's parent elements height. allowing the aspect ratio to stay the same, bleeding the video when needed but allowing it to be centered in it's parents element vertically.
This was super rough, since I was just working on this about an hour ago, so I'm sure theres plenty I need to rework through and get dialed in, but hopefully this helps you along your path, should be the same solution except your doing your height checks on the video element or video wrap element outerHeight and the viewport height.
Related
Hello everyone~ I have a problem but my English is not good. I will try my best to express it completely! If the explanation is not clear enough, everyone is welcome to tell me~ The
problem is like this, today there is a block for users to upload photos !
The width and height of this photo after uploading by the user
cannot exceed 360px, the minimum cannot be less than 100px, the
maximum height cannot exceed 200px, and the minimum cannot be less than 100px
.
What I want to ask everyone here is, can this requirement be accomplished only by CSS?
Or can it be accomplished by using JavaScript? But if I use JavaScript, I don't know how to start, because my JavaScript is very poor. I hope I can get your valuable suggestions here, thank you.
I wrote an example. The original picture size is only 50PX in height. How can the height of the photo reach 100PX without affecting the ratio?
.photo{
width: 360px;
height: 200px;
object-fit:contain;
object-position:left center
}
<div class="demo">
<img class="photo" src="https://upload.cc/i1/2021/09/30/s73jb5.jpg" alt="">
</div>
I think this is what you want to do.
Image should have maximum-width to be 360px and minimum height should be 100px.
And also if you want to add min-width and max-height you can add in imageSettings variable in javascript.
If you have multiple images, simply add imageContainerForJS class to img parent element.
(()=>{
let imgContainers = Array.from(document.querySelectorAll('.imageContainerForJS'));
const imageSettings = {
"max-width": 360,
"min-height": 100,
}
for(let imgContainer of imgContainers) {
let img = imgContainer.querySelector('img');
if(!img) continue;
let imageSource = img.src;
let image = new Image();
let maxWidth = imageSettings['max-width'] || null;
let minWidth = imageSettings['min-width'] || 0;
let maxHeight = imageSettings['max-height'] || null;
let minHeight = imageSettings['min-height'] || 0;
image.onload = function() {
let width = this.width;
let height = this.height;
if(maxWidth && width > maxWidth) width = maxWidth;
if(minWidth && width < minWidth) width = minWidth;
if(minHeight && height < minHeight) height = minHeight;
if(maxHeight && height > maxHeight) height = maxHeight;
imgContainer.style.width = width+'px';
imgContainer.style.height = height+'px';
}
image.src = imageSource;
}
})();
.photo{
object-fit: cover;
object-position: center;
width: 100%;
height: 100%;
}
<div class="demo imageContainerForJS">
<img class="photo" src="https://upload.cc/i1/2021/09/30/s73jb5.jpg" alt="">
</div>
You can use object-fit:cover to make your image proportionally expand to fill its container.
Set the container to the dimensions you want, then have the image fill it by setting its width and height be 100%.
By default cover will position the image in the centre.
.demo {
width: 360px;
height: 200px;
}
.demo .photo {
width: 100%;
height: 100%;
object-fit: cover;
/*object-position: left center;*/
}
<div class="demo">
<img class="photo" src="https://upload.cc/i1/2021/09/30/s73jb5.jpg" alt="">
</div>
The width=100% height="auto" scales my videos to fit the whole width of the browser window, but if the height of the window is lower than the aspect ratio the video gets cropped in height.
I want the video to scale to fit either width or height so that I can always see the whole video without crop, filling the closest ratio (adding empty space to sides if window ratio is lower).
I can't figure out how to do this however.
First any height value, % or px, seems to be disregarded, I can't set the size at all using height, only width. Same for min-width/height.
How can this be done?
My code:
<video id="video" width=100% height="auto" onclick=playPause()></video>
Video is loaded by javascript where v is a video link from an array:
video.addEventListener('play', function() { v.play();}, false);
Try wrapping the value inside quotes
<div class="videoContainer">
<video id="video" width="100%" height="auto" onclick="playPause();"></video>
</div>
you can add these class
.videoContainer
{
position:absolute;
height:100%;
width:100%;
overflow: hidden;
}
.videoContainer video
{
min-width: 100%;
min-height: 100%;
}
Or alternatively use this
video {
object-fit: cover;
}
Solved it myself with a javascript function:
window.addEventListener('resize', resize, false);
video.height = 100; /* to get an initial width to work with*/
resize();
function resize() {
videoRatio = video.height / video.width;
windowRatio = window.innerHeight / window.innerWidth; /* browser size */
if (windowRatio < videoRatio) {
if (window.innerHeight > 50) { /* smallest video height */
video.height = window.innerHeight;
} else {
video.height = 50;
}
} else {
video.width = window.innerWidth;
}
};
There's a great auto width/height trick called intrinsic ratios that can be used on images/videos and the likes! The trick is to have your desired element in a wrapper that then has a percentage-valued padding applied to it.
Your markup would then be:
<div class="video-wrapper">
<video class="video" id="video" onclick=playPause()></video>
</div>
And your CSS:
.video-wrapper {
position: relative;
padding-bottom: 20%;
height: 0;
}
.video {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #ccc; /* Random BG colour for unloaded video elements */
}
You can limit the dimensions of your video container by playing with min-width or max-width of the .video-wrapper styles.
Hope this helps!
I had a similar problem. I have made a `slideshow' with various objects as slides, some of them are videos of various sizes. I did not found any conceptual solution, so I have found a trick.
I have explicitely specified all real video sizes in tags and collected the information of all of them:
var vids = document.getElementsByClassName("vid"); // videos
var vidl = vids.length;
var vidH = [ ];
var vidW = [ ];
// Get original widths and heights of videos
for (i=0; i<vidl; i++) { // >
vidH.push(vids[i].height);
vidW.push(vids[i].width);
}
Then (when necessary) I define the window size as follows:
// Current inner height of the browser window (in pixels)
var iH = window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
// Current inner width of the browser window (in pixels)
var iW = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
To rescale a rectangle into another rectangle we have to find a minimal scale:
var r, rh, rw;
// Scale videos to fit window
for (i=0; i<vidl; i++) { // >
rh=iH / vidH[i]; rw=iW / vidW[i]; r=Math.min(rh, rw);
if (rh>rw) {
vids[i].height=Math.floor(vidH[i]*r);
vids[i].width=iW;
}
else {
vids[i].height=iH-5;
vids[i].width=Math.floor(vidW[i]*r);
}
}
Unfotunately, here appeared some extra space; in FireFox I have found its minimal value as 5 that I negate form windows height value (iH) as the new video size.
Duplicate issue on the height posted at HTML5 Video dimensions in Safari IOS
Pure CSS solution provided in: https://stackoverflow.com/a/60878701/2486998
You can add style:
object-fit: contain;
In Angular if video player (shaka player in my case) is a separate component, this works perfectly (either height or width of container will cause resize of the player)
HTML
<div id="videoContainer"
class="videoContainer">
<video id="videoPlayer"></video>
</div>
CSS
.videoContainer
{
height:100%;
width:100%;
}
.videoContainer video
{
width: 100%;
height: auto;
max-width: 100%;
max-height: 100%;
}
I have 2 images, one of them has a Mask area. And the other image can be seen through the Masked area of the above image. I want to centre the second image within the Mask area of the first image.
Currently I'm do scale the image to mach with the mask area using below function (It has 3 lines of code that I tried to with alignment - didnt work though),
function scaleimage(img){
img.style.height = 'auto';
img.style.width = 'auto';
//Getting the image hight and width
var imgW = img.clientWidth;
var imgH = img.clientHeight;
//Getting the mask hight and width
var maskH = data.result.mask.maskhight;
var maskW = data.result.mask.maskwidth;
var scaleH = maskH / imgH;
var scaleW = maskW / imgW;
// Scaling
if (scaleH < scaleW) {
img.style.height = maskH + "px";
img.style.width = Math.round(imgW * scaleH) + "px";
} else {
img.style.width = maskW + "px";
img.style.height = Math.round(imgH * scaleW) + "px";
}
//Align image - commented below code since it didnt work
/*img.style.top = Math.round((mask1H - imgH) / 2) + 'px';
img.style.left = '50%';
img.style.marginLeft = Math.round(imgW/2) + 'px'; */
}
Current and Expected result as an Illustration. IMAGE 1 has a Mask area that can see through, and IMAGE 2 is behind IMAGE 1, but align its top left to the Mask Area's Top left. What I want is, IMAGE 2 centre = Mask Area Centre
I tried few things and didn't get any of them quite right, any feedback would be really helpful
If I understand correctly from your code. You want to resize image to fix into your mask. I have write a demo using your function here. Because I dont know your real HTML, I use my own code with a predefined value of maskW and maskH.
Another thing to note: you should set the position property of the image style to another value than the default static value if you want to layout it manually. In the demo, I set the position value of img element to absolute.
There is a css solution for this if you'd like to try:
Html:
<div>
<img class="image" src="http://dummyimage.com/300x200/0000ff/ffffff&text=image" alt="image">
</div>
Css:
div {
width: 150px;
height: 100px;
margin: 50px auto 0;
position: relative;
background: url(http://dummyimage.com/150x100/000/fff&text=mask) no-repeat center center;
}
.image {
width: 80%;
top: 50%;
left: 50%;
position: absolute;
margin: -27% 0 0 -40%;
}
Fiddle
I see at least two approaches here:
use negative left margin of second image
<img id="img"/><img id="mask"/>
<script>
mask.style.marginLeft = (imgW + maskW) / -2;
mask.style.marginTop = (imgH - maskH) / 2;
</script>
show images as background of two divs (one embeds another). Set their width and height same values (of bigger image) and use center alignment of inner background. But then, if you're getting images by AJAX, you should retrieve also sizes of the images.
<div id="img">
<div id="mask"></div>
</div>
<style>
#img {
background-position: top left;
background-repeat: no-repeat;
}
#mask {
width: inherit;
height: inherit;
background-position: center center;
background-repeat: no-repeat;
}
</style>
<script>
var imgDiv = document.getElementsById('img'),
maskDiv = document.getElementById('mask');
imgDiv.style.width = imgW + 'px'; // from AJAX
imgDiv.style.height = imgH + 'px';
imgDiv.style.backgroundImage = "url('img.jpg')"';
maskDiv.style.backgroundImage = "url('mask.jpg')";
</script>
This is juts an idea and should work with fixes
I've got a background video playing on a web page, and this CSS;
#video_background {
position: fixed;
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
top: 0px;
left: 0px;
z-index: -1000;
overflow: hidden;
}
..is keeping it centered, like I want it to, but it's keeping all of the edges within the browser window, rather than always being full-bleed. I'm trying to replicate what this site is doing;
http://marisapassos.com/#home
This site appears to have two sets of rules, one on a div that contains the video, and one on the video itself. Could someone explain to me why that works and what I'm doing doesn't? Is there also js working to keep the video on the linked site centered?
Yes, look at the video_background.js in the source of the website you linked to, specifically at the $(window).resize function:
$(window).resize(function() {
var windowWidth = $(window).width();
var windowHeight = $(window).height();
var width;
var height;
//size
width = windowWidth;
height = width*formH/formW;
if(height<windowHeight){
height = windowHeight;
width = formW*height/formH;
}
$div_holder.css("width", width);
$div_holder.css("height", height);
$div_holder.css("left", windowWidth/2-width/2);
$div_holder.css("top", windowHeight/2-height/2);
});
Left and top are defined in terms of both the windowWidth and (video) width which keeps the video centered.
I have centered (position: absolute; left: 50%; margin: -50px;) 100px width div (container).
It has absolutely positioned child div with overflow: hidden, its size is 100x2000 px (such height is for test purposes, as described below).
There is an image in child div, it is absolutely positioned.
The image is 3100x100 px, it contains frames of animation.
I am animating this image by changing its style.left from 0 to -1100px, step is 100px.
Everything is fine, but I encounter weird issue when body width is not even.
It can happen if there is scrollbar and the scrollbar has odd width (it happens for me on Chrome/Win32 for example).
In this case image visually shifts by 1 pixel horizontally as soon as animated image goes through screen edge (for 1920x1080 it happens roughly at 9-10 frame of animation).
I can't find workaround for this behavior.
Working example reproducing the problem can be found here
Child div height is set to 2000px to make sure scrollbar is visible.
If your scrollbar has even width, you can reproduce the problem by resizing your browser window to odd width.
That happens because of the browsers rounding engines. Webkit apparently has some problems with 50% on even and odd widths.
One way to overcome the issue - re-position the .outer element based on window width
document.getElementById( 'outer' ).style.left = Math.floor( window.innerWidth / 2 ) + 'px';
DEMO
You need to change .inner img position to relative and update your javascript. I made changes for you, so here is your solved code:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<style>
body {
background-color: #000000;
}
.outer {
position: absolute;
left: 50%;
margin-left: -50px;
}
.inner {
position: absolute;
width: 100px;
height: 2000px;
overflow: hidden;
}
.inner img {
position: relative;
top: 0;
left: 0;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
<img src="http://lorgame.ru/test.png" id="img">
</div>
</div>
<script language="JavaScript">
var framesCount = 30;
var framesCurrent = 0;
var framesMoveLeft = true;
var img = document.getElementById('img');
var interval = setInterval(function() {
if(framesMoveLeft == true){
framesCurrent++;
img.style.left = (img.offsetLeft - 100) + 'px';
if(framesCurrent == framesCount) framesMoveLeft = false;
} else { // Move right
framesCurrent--;
img.style.left = (img.offsetLeft + 100) + 'px';
if(framesCurrent == 0) framesMoveLeft = true;
}
}, 100);
</script>
</body>
</html>
To me this seems like a bug in Chrome. When percentages are defined in integers, they behave rather unexpectedly. Try to define the position as a decimal instead:
.outer {
position: absolute;
left: 49.99999%;
margin-left: -50px;
}
I tested this on the fiddle and it seems to do the trick.