Responsive sizing is when the player can dynamically change size to fit its container while maintaining the desired aspect ratio. This should be a feature built into video.js and we need to find out the right way to add it. (it's currently possible with additional work or outside libs)
Related issues: #771, #359, #384, #925, #983
Also see the intrinsic ratio example from @baloneysandwiches
Related Links:
http://alistapart.com/article/creating-intrinsic-ratios-for-video/
The intrinsic ratio method seems like the best approach. In order to make that happen, we need to allow the user to supply the ratio some how. Some potential options:
// set a flag and then we calculate the ratio from the width and height
videojs('id', { responsive: true, width: 1600, height: 900 }); // --> ratio = 16:9
// provide a ratio
videojs('id', { aspectRatio: '16:9' });
(specific naming TBD)
Video.js would essentially have 2 layout modes, fixed and responsive, and we would probably apply a different class of styles to the player div depending on which was needed.
Not sure if all of these are valid, but providing possible solutions for each based on the aspectRatio/autoHeight setting.
User wants the video to fill width, and specifies an aspect ratio to calculate height
`videojs({ aspectRatio: '16:9' });`
-> Add width: 100%, padding-bottom: (9/16)%
User wants the video to fill width, and auto adjust height to match source aspect ratio from metadata
`videojs({ aspectRatio: 'auto' });`
Before metadata:
Use a default aspect ratio, like 2:1 or 16:9
-> Add width: 100%, padding-bottom: (9/16)%
After loadedmetadata
-> update padding to match source aspect ratio
User wants the video to fill height, and specifies an aspect ratio to calculate width?
I don't think this is a valid user story, or at least I can't think of a real world use case. Video dimensions are rarely taller than wide (though...iPhone videos). Browser windows have restricted widths not heights.
User wants the video to fill both width and height and the video content to fit inside
This isn't something we need to handle with this story, but we also don't want to get in the way of it
`vjs-fill` or a similar simple class to add. Don't need an option.
--> We would just need to add width: 100%, height: 100%.
User wants the video to fill both width and height and the content to cover the space
See BigVideo.js. Appears to require a good amount of work. Not something we need to get into with this, and probably best handled as a plugin
User wants a fixed width and height
`videojs({ width: 100, height: 100 });`
User wants a fixed width and specifies an aspect ratio to calculate height
`videojs({ width: 100, aspectRatio: '16:9' });
You could just calucalate height here, so this doesn't seem like a priority.
If we don't allow this, we could assume whenever aspectRatio is used that we set width to 100%. Otherwise we would just manually calculate the other value here.
When you do set a width, you can't use the intrinsic ratio, because the height percentage is based on the width of the parent element, not the video player width itself.
User wants a fixed width, and auto adjust height to match source aspect ratio from metadata
The video element does this, so video.js should if possible.
`videojs({ width: 100 });`
We could either have a default aspect ratio that we calculated and set until the metadata is available, or just allow the default height (set on the .video-js class) to be maintained. The former would be cleaner and more inline with the video element, but would take more work.
User wants a fixed height, and auto adjust width to match source aspect ratio from metadata
The video element does this also, so video.js should if possible
`videojs({ height: 100 });`
User wants a video tag with no width or height or aspect ratio settings to be viewable
`videojs({});`
We could have a default width/height on the main .video-js class. That way it would be overrideable through CSS or through javascript style setting.
User wants to use CSS to manually set width/height
`videojs({});` CSS set elsewhere
The main difference between video.js and the video element here is that with the video element, if you set width and height attributes on the tag, they can easily be overridden by CSS. In Video.js we have to take the width/height attributes and apply them through javascript (inline) styles, which makes them only overrideable by using !important. It should atleast be possible to exclude width/height and use CSS manually.
âautoHeightâ might be more descriptive. âResponsiveâ can mean all sorts of things, including calculating width based on height. What weâre talking about here is specifically calculating height based on width, in a typical column-layout. Providing one option is also terser than specifying three:
videojs('id', { autoHeight: '16:9' }); // use provided ratio regardless of metadata
videojs('id', { autoHeight: true}); // derive aspectRatio from metadata
videojs('id', { autoHeight: ''}); // turns off autoHeight
videojs('id', { autoHeight: false}); // turns off autoHeight
videojs('id', { autoHeight: true, height: 300}); // height option ignored in autoHeight mode
videojs('id', { autoHeight: true, width: 500}); // width is respected as usual
Poster sizing should be unaffected.
FWIW, we've been using a variation on the "intrinsic ratio method" with videojs for several months and it's been great. Examples at:
http://www.funnyordie.com/videos/fa1420df1f/green-team-from-will-ferrell-adam-ghost-panther-mckay-and-john-c-reilly
http://www.funnyordie.com/videos/ca8e174a54/between-two-ferns-with-zach-galifianakis-justin-bieber
We played with keeping things in their native aspect ratio but 4:3 videos were just too massive on wider browser widths, so we lock everything down to 16:9.
I'd vote for "aspectRatio" for the config item. Makes the most sense to me.
Thanks @jgubman, that's interesting to know about 4:3 videos.
I agree with @baloneysandwiches that 'responsive' is too vague. I don't love the idea of having both height and autoHeight options. That feels a little confusing.
I created a number of user stories and added them to the body of the issue. It at least helped me wrap my mind around the full problem set better.
There's essentially two things we need to know from the user:
Q1. Are you using this in a fluid/responsive layout?
YES: we'll set the width of the player to 100% and set heights using padding (intrinsic ratio)
NO: we will set width and height in pixels
(we can't use the intrinsic ratio when the width is set in pixels. The percentage used for height is calculated from the width of the parent element of the player, not the width of the player itself)
Q1. Do you have a specific aspect ratio you want?
YES: We'll match that ratio when setting any missing dimension values
NO: We'll provide a default and attempt to read from metadata once it's available
An alternative option I'm consider is fluid. videojs({ fluid: true }); or videojs({ fluid: '16:9' }); If we use aspectRatio/autoHeight, we either assume a fluid layout, or do logic to try to be smart about when it's fixed vs fluid. Since we can't set the height the same between fluid and fixed layouts, it's really important to know first which type of layout we're working with, so that makes me lean towards that as the option name.
I find the use case for calculating width based on fixed height to be somewhat obscure, given current layout patterns in the wild, but since the video element supports that, it agree would be nice to address as well for future layout flexibility. âaspectRatioâ has the advantage of neutrally addressing the fixed height, flexible width use case.
I think it would great if there were a way to avoid the two-layout-modes thing. Thatâs tricky. I think what emerges from the above range of use cases is that âresponsiveâ should not be a specialized mode, but the norm. Can the fixed width cases can be built around a default âfluidâ code structure?
For example in the âfixed height, known aspect ratioâ use case:
videojs('id', { aspectRatio: 16:9, height: 300});
It would be ideal to set a fixed CSS width, based on a little algebra, and still use padding-top to give the player height. In other words, we would never leave âfluidâ mode, because there is _only_ fluid mode.
The big obstacle to this, as you point out, is that percentage padding refers to the parent. So if you want a fixed dimension, you need another wrapping parent element to apply the style too. This was the hiccup all the way back in Thierryâs original demo. Yeah, itâs ugly, div-itis, etc, but it simplifies the problem greatly. Are you willing to consider an additional default wrapping div?
It would make things a little easier if we could default to fluid. Then any time width/height was set you could drop out of fluid mode. But part of the goal of video.js is to work just like the video element. I made this jsbin earlier to see exactly how the element works by default. It would also be a pretty big change from existing versions, so we'd probably have to delay the change until 5.0.
I'd definitely prefer to avoid adding another wrapper div, especially if that would be the default.
One other note is that a fluid width video isn't exactly the best for performance and quality. Increasing or decreasing the size of the video from its actual dimensions makes the decoder do extra work and degrades the quality. This happens all the time with full screen video, but still, it's best to display the video at its actual size, which is what the video element does by default.
If we were to default to fluid, I don't know if there's a good way to auto set the width/height from the metadata. Maybe width=auto height=auto. That's similar to what we have now, and it's not great.
I agree that things look best (and perform best) at their encoded size. Thatâs a good pointer to put in the docs. Also, it should inform how the ânull options objectâ case is handled:
videojs('id', {});
// No supplied height, width, or aspectRatio = handle as a special case.
// Set a default aspectRatio until metadata loads.
// (Essentially, aspectRatio defaults to true.)
// When metadata loads, set width from metadata,
// and set padding-top based on aspectRatio derived from metadata.
Note that this doesnât mean setting up âautoâ keywords for width and height. I agree thatâs bad to expose externally.
If youâre willing to entertain the notion of an extra div, all of your use cases in the initial comment can be handled using intrinsic ratios. I can type up a full rundown if itâs helpful. I agree itâs painful from a markup perspective, but it seems possibly less painful than tracking down and patching every possible bug involving switching back and forth between broadly conceived fluid and fixed modes. That frankly sounds like a nightmare to write and maintain.
There is one tricky use case. Iâll call it âthe stretchâ:
videojs('id', { aspectRatio: '16:9â, width: â500pxâ; height: â500pxâ })
// The author wants to stretch a widescreen video into a square.
// It doesnât matter for this case whether aspectRatio is supplied, or comes from metadata.
This genuinely requires a âfixedâ mode, because negative height or negative padding would be needed to compensate in certain cases, and those values arenât allowed. While legitimate, this use case seems to be nicely isolated. Maybe add a âstretchâ class when all three options are supplied and the math doesn't line up?
Is stretch similar to background: cover and the BigVideo.js example? If so I don't think we need to try to fit that use case into this API, but still good to be aware of.
There might be an opportunity to avoid the second div and instead set the tech element to position:relative, and add the padding height to that, but as is that would create a flash of zero height when switching between techs (e.g. playing ads). And so far we've relied on everything being position:absolute in the player, so that would take some serious testing.
Defaulting to fluid is too big of a change and detraction from the spec to do before 5.0, and I'd like to get something in sooner, so I could see this going in two steps either way.
If there's potential for defaulting to fluid in the future, then aspectRatio might be the better option name than fluid. But in the first step we'd still be better off assuming that if the user uses aspectRatio that they want a fluid layout support. With that being the case, I think the user stories in the issue body hold up and we could start working on those.
âIs stretch similar to background: cover and the BigVideo.js example?â
âStretchâ and âcoverâ are completely different use cases. Stretch shows all of the video, at a tweaked proportion. Kind of like when you resize an img in photoshop with the âconstrain proportionsâ checkbox unchecked. You get the same thing in a browser for an img when you write:
<img src=âmypic.jpgâ width=â1000â height=â500â style=âwidth:2000pxâ>
(The height will stay fixed at 500px, and not bump up to 1000px unless you add in height: auto!important.)
if aspectRatioVideo <= aspectRatioContainer {
videoHeight = containerHeight;
videoMarginLeft = -1 * ( videoWidth - containerWidth ) / 2;
} else {
videoWidth = containerWidth;
videoMarginTop = -1 * ( videoHeight - containerHeight ) / 2;
}
and set the container CSS to overflow:hidden.
âThere might be an opportunity to avoid the second div and instead set the tech element to position:relative, and add the padding height to that."
That wonât work as youâve described it. The intrinsic ratios padding-top solution and the âput the player in-flowâ solution I argued for in #359 are different solutions. You canât apply both simultaneously without pushing the container div height taller than the tech height, which is just wrong. Conceivably you could use padding-top to give the box height before the metadata has loaded, then turn off the padding, change the display of the tech to static to put it in-flow. But that sounds needlessly complicated.
â but as is that would create a flash of zero height when switching between techs (e.g. playing ads).â
Well, you could write it so that for consecutive videos, the previous video's padding-top stays in place until the next video's metadata loads, to avoid a FOZHâ˘.
"Defaulting to fluid is too big of a change and detraction from the spec."
Well, as far as the spec, itâs actually closer to how the video element behaves. Also, Iâm not suggesting defaulting to fluid per se, Iâm suggesting defaulting to any fixed width supplied by the author, and if no width or height is supplied by the author, defaulting to the width (and thus also height) in metadata. That isnât exactly fluid, itâs actually fixed, at least until author CSS (e.g. container max-width) gets involved. In my understanding, that is how the video element works. What I am suggesting is relying on padding-top to give the player height across the board, in all cases except stretch.
Just curious what the status is with this feature. Would be very useful.
Just haven't had a chance to implement it yet. Feel free to try if you're interested.
A possible implementation (not by me): http://coolestguidesontheplanet.com/videodrome/videojs/
<video... width="auto" height="auto" ...>
.video-js {padding-top: 56.25%}
.vjs-fullscreen {padding-top: 0px}
+1 This would really be a great feature to have!
I would love to see this happen.
Still working on this one, but the implementation @ernsheong referenced is a great starting point for something looking for a stopgap solution.
For anyone else that's implementing the workaround @ernsheong mentioned, you'll need to absolutely position the poster image in order to see it. It's currently set to fill 100% of the parent element, which doesn't work when using this workaround.
.vjs-poster {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
+1
+1
To support Responsive Design, I used http://coolestguidesontheplanet.com/videodrome/videojs/
Thanks for the feedback, everyone. This definitely something we're targeting to fix by 5.0 (at latest). I don't want to lock the issue because feedback on implementation would be fantastic, but no more +1s are needed at this point.
I too tried the snippet by coolestguyontheplanet for a project once, but as it turned out, it had many not so cool side effects. Not just moving the Poster Image out of the way but messing with the Flash fallback and all sorts of elements attached to the video frame. Giving the wrapping div a top padding over the full supposed height of the video may not be a good idea after all.
Heres my shot at responsiveness in videojs, with a placeholder that I move out of the way:
.video-js {
width: 100% !important;
height: auto !important;
}
.video-js:after {
content: '.';
display: block;
position: relative;
padding: 40.1% 0 0 0; /* (height/width)*100%, eg. 56.25% for 16:9 75% for 4:3 */
margin: 0 0 0 -100%;
visibility: hidden;
height: 0;
}
Demo: http://andreassauer.name/experimente/video-js/demo.html
In Internet Explorer 7 for the :after pseudo element to work, a shim is required.
Even more convenient, of course, would be, if video js inserted the the placeholder and took care of setting the padding via a given aspect ratio.
The tip above from @j4k3 works great except the suggestion from @mmcc
.vjs-poster {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
still needs to be included in order to see the poster when Flash is being used to play the video. I've tested responsivness on the latest Mac OS X:
Thank you for the testing, @Shaun-Dychko. It shouldn't be any different, but any chance you've been able to test this in IE? Particularly IE8...I don't see any reason why it would break there, but it would be nice to verify.
I can add that I've also tested on an iPod Touch running iOS 5.1.1, but IE8 is old news for me so I don't have a setup for testing it.
@Shaun-Dychko Totally understandable. I got sick of using a VM just for testing IE, so I actually commandeered an old windows laptop that was lying around the office. If you have a reduced test case online somewhere that implements the combined solution so far I can give it a test.
@mmcc here's a test case, but I wouldn't call it "reduced" since it's surrounded by Twitter Bootstrap, but if it works here, maybe it works anywhere?
Edit: the link expired, and it looks others have provided test URL's.
@Shaun-Dychko Confirmed. Absolute positioning makes the Poster Image behave with the Flash fallback. Updated that in my code.
Heres a screenshot in Internet Explorer 8: http://andreassauer.name/experimente/video-js-ie8.png
edit: The screenshot is made with the outdated demo code, but it seemed to work as expected.
Great, thanks for the help @Shaun-Dychko and @j4k3. I think we've got a good idea how we want to implement this technically, but work still needs to be done for the interface (see @heff's first post on this thread). Anyone want to tackle some of this work and get a PR together?
i am not sure if i right here, but here is my solution: (testen on iPad with bootstrap3)
var $videotemplate = '
$('#elem').append($videotemplate);
// calculate video ratio 16:9 at a given width from 100%
var $thevideo = $('#thevideo'),
$video_width = $thevideo.width(),
$video_height = ($video_width / 16 * 9);
setTimeout(function () {
$thevideo.animate({"height" : $video_height},200);
}, 500);
$(window).resize(function () {
setTimeout(function(){
$thevideo.animate({"height" : $video_height},200);
}, 500);
});
@MattOpen Not sure what you are trying to accomplish. We were just elaborating that no Javascript at all is required to make video js responsive.
@mmcc I agree with the user story draft. Not sure how soon I'll find the time, but I hope I can fork and try to implement on the weekend.
@j4k3 that would be so awesome I can't even begin to describe.
From my experience you can do responsive video resizing with CSS but you need to know the aspect ratio in order to specify the appropriate padding. Is there a way to get and preserve the aspect ratio of the video with just CSS?
For most implementations I've worked on I use a derivative of the following (apologies for the jQuery):
// The element that is fluid width
var $allVideos = $(".video-js");
$fluidEl = $(".your-responsive-container");
// Figure out and save aspect ratio for each video
$allVideos.each(function() {
$(this).data('aspectRatio', this.height / this.width).removeAttr('height').removeAttr('width');
});
$(window).resize(function() {
var newWidth = Math.floor($fluidEl.width());
// Resize all videos according to their own aspect ratio
if(newWidth > 0){
$allVideos.each(function() {
var $el = $(this);
$el.width(newWidth).height(Math.floor(newWidth * $el.data('aspectRatio')));
});
}
}).resize();
Originally pilfered from this post: http://css-tricks.com/NetMag/FluidWidthVideo/Article-FluidWidthVideo.php
@justinlevi Not to be short, but most of the solutions in this thread are pure CSS.
@mmcc - Apologies, I'm probably missing something as I'm definitely not a CSS expert.
For my own clarification though, don't all of the CSS solutions above require you to set a specific aspect ratio for your player? If that's the case then wouldn't you run into a issues if you needed different aspect ratios for different videos on the same page without creating specific styles for each?
Wondering why a CSS solution is preferred to a JS solution here?
CSS solutions for things like that are always prefered to JS solutions. Specifically, it's generally a lot more performant than doing similar things in JS.
It's possible that some js will be required to figuring out the aspect ratio of the video (if not supplied) and then apply the right CSS to the video.
This makes me think that we should have at least 2 classes that we can add to the vjs div that would apply correct styles doing the chain: vjs-16-9 and vjs-4-3 (or whatever want to actually call it). Then if we do need js, the js could set the appropriate class.
No worries @justinlevi, sorry about the quick response I was just getting up from my laptop when that came in.
I think the solution will ultimately be a setup option. We can't guarantee that we'll ever be able to get a reliable aspect ratio from JS, so although we might be able to make a best guess in some scenarios, I think the preferred route should always be explicitly setting the aspect ratio and a reasonable default.
@mmcc @gkatsev - Thanks for the info. Makes total sense. This will definitely be a highly used feature and I'm for one looking forward to using this a bunch. Cheers.
Hi all,
I implemented the css solution for the resposinve design, and it works fine as long as you keep the aspect ration using the width.
However it is not alwas the case, sometimes I have to upscale or downscale the video.
In some case, I need to rotate the video and I'm unable to addapt the videojs-rotatezoom plugin in a responsive design, https://github.com/xbgmsharp/videojs-rotatezoom.
The responsive design require an additional div and break the layout when rotated.
I created this plugin to display correctely a video recorded sideway by smartphone. It use only CSS.
I implemented all this feature for a webgallery to play video nicely and smoothly from different source (GoPro, IOS, Android). https://github.com/xbgmsharp/piwigo-videojs
This lead me to 3 questions:
What is best way to calculate the resize video, using the height or the witdh?
How to upscale and downscale a video in a resposive way?
How to display correctly (rotate and zoom) a rotated video from smartphone?
To allow an easy implementation, it would be great if I could something like that.
On this sample the video would be upscale or downscale to match the specific height.
videojs('id', { aspectRatio: 16:9, height: 300});
A sample using plugin
videojs('id', { aspectRatio: 4:3, height: 150, "plugins": { "zoomrotate": { "rotate": "90", "zoom": "1.5" } }});
Any suggestion?
It sounds like there's two different solutions here, both of which are valid and could be added to the player to support their specific use case.
vjs-16-9, vjs-4-3 class names that a video.js user can add to the video tag to override default layout behavior and create a responsive video that fills the horizontal space and maintains the specific aspect ratio vertically. The requirement is that the user knows the specific aspect ratio they want ahead of time, and that it's one of the provided classes. They can also create their own class for a more specific aspect ratio, but they still need to know it ahead of time.
This would be relatively easy to add by just creating those specific classes. At the same time we'd need to make sure that the existing width/height function don't override those classes, since they set inline styles.
Solution 1 should be relatively easy to put together, so if someone wants to give it a shot, please do. Solution 2 will take a little be more javascript work and understanding of how width/height are currently set up to work, but still very doable if someone wants a bigger challenge or excuse to get more familiar with the video.js codebase.
I'm happy to help and give feedback on either.
Agreed that the custom aspect-ratio classes case is quick and easy when the content is known in advance. This is what lots of us have been using for awhile now, and it works as is.
I think a good next step is that fluid width should still be possible with videos of unknown aspect ratio. I like your earlier idea of setting a default aspect ratio class for videos that have opted in to âfluid modeâ but have no author-supplied aspect ratio. That default class (probably 16:9) is replaced or overridden if the aspect ratio in the video metadata is different from the default. (This âdefaultAspectRatioâ could ideally also be exposed as an option for those with special requirements, like square videos, etc.) One idea here is still to use prebuilt classes in the stylesheet for the main ratios (16:9 and 4:3), but busting out into inline CSS for any oddball aspect ratios. Defaulting to classes generally improves caching, speeds render, and it also works around any draconian Content Security Policies that disallow inline CSS. How do we you want to ask for ratios to be supplied? Exclusively as strings containing colons? â16:9â â4:3â etc? @heff if we can converge on an approach I will take a whack at this. Pointers on overall architecture and specifics on listening for metadata load?
Looking past this, the harder ânext levelâ step after that is harmonizing the above with the width/height API. Because intrinsic ratios let height be generated as the product of a width and a CSS value, getting the width API alone to work as expected is straightforward. The height changes on arbitrary width changes. But getting the height API to work has the wrinkle that you essentially need to do the CSS math in JS, finding the computedWidth that will give you the height youâre declaring, given the aspect ratio. Thatâs somewhat counterintuitive: (the height API sets a CSS width?) but I think thatâs how itâs got to be in fluid mode.
Then thereâs what I see to be the final, trickiest step, of codifying the conditions and behaviors when the video image distorts, "fits", or "covers". E.g. generally when both height and width are supplied via the API, and their ratio doesnât match the ratio derived from the video metadata. Not the first concern, but something to keep in mind in the process.
Awesome. Yeah, I think we can attack the problems in the order you lay out there, and not try to take them all on at once.
I think the user stories still hold up as far as I'd expect it to work from an API perspective.
For handling the aspectRatio setting you can probably start in the player init and add any css classes needed like in this example. (though it would be options.aspectRatio)
https://github.com/videojs/video.js/blob/7f4e6eb4320fe6dc51ed6d337da5e46c3f4c7f3c/src/js/player.js#L274
For listening for meta data you can create loadedmetadata listener in the same pattern as some of the existing player listeners here:
https://github.com/videojs/video.js/blob/7f4e6eb4320fe6dc51ed6d337da5e46c3f4c7f3c/src/js/player.js#L274
Is that enough to get you started?
@heff thanks, yes, working on it. Hopefully a PR soon!
I haven't added any tests or documentation yet because I want to make sure we're on the same page for all this. I think this satisfies the vast majority of common single-column-layout use cases as written.
One issue that's come up is that I'm realizing specified aspect ratios and intrinsic ratios are often ever so slightly different in the real world. For a close-to-home example, the seagulls vid has 640 x 264 listed as dimension attributes in the sandboxed example. But getting intrinsic dimensions from actual metadata yields 634 x 264. Six pixels is in my experience just enough to drive a designer absolutely crazy. :)
My approach to this is to _always_ overwrite the author specified aspect ratio with the intrinsic aspect ratio, for a few reasons: It serves the content more accurately, because it's less resampling in some cases. It's also truer to the spec, the latest draft of which says:
NOTE: The dimension attributes are not intended to be used to stretch the image.
User agent requirements: User agents are expected to use these attributes
as hints for the rendering.
The spec is frustratingly silent, however, on what exactly is supposed to happen when the specified and intrinsic ratios are different. It could be totally annoying to an author to specify an exact ratio and have some slightly-off video content load, and break his/her design slightly. Slight stretching is an legitimate use case! Maybe the spec authors are just suggesting that stretching be done with CSS rather than dimension attributes? One option is to expose yet another option, something like a boolean "preserveIntrinsicRatio" defaulting to true that would allow authors to force/block any re-render on metadata load. I'd like feedback on this.
Also in the CSS, per @mmcc comments above, note that I've made the poster absolutely positioned in all cases. I didn't see any reason not to, and it didn't seem to break anything.
Lastly, another to-do, per our chat on IRC, is to add methods for getting height and width metadata to the flash player (and other techs). This implementation is currently HTML5 only.
Yeah, the oceans clip isn't the best example for this. The AR there is kind of off to begin with, and we need to reencode it. You'd think we'd have a way to do that. :)
The way the video element works with width/height is if you set a width/height the browser will respect that setting and not override it. It will only use the video metadata if you haven't set a width and height. In that case it will default to 300x150, and then once it has the metadata it will resize to that.
I think we should be doing the same with aspect ratio. If the user puts a specific aspect ratio, we shouldn't override it with the video metadata. If there's no aspect ratio set, we should have a default, but then change it when we get the video metadata.
Does that make sense and help solve the issue here? In your PR specifically, I think we'd drop the default 16:9 in the aspectRatio option, and instead default to 16:9 internally if no aspectRatio option is provided.
I don't think it's that simple. Here's a test:
I just tried in Chrome Canary and FF Aurora and the sizing behavior basically the same between the two browsers. If the author forces a false (in this case square) aspect ratio on the video tag using the dimension attributes (example 1), it doesn't distort the video image to be square. So the browser is most definitely looking at metadata to determine the visual height of the video image, in this case because of the auto keyword on height.
The more peculiar thing happens in example 2, where the simple absence of height: auto in the CSS causes the video element to take up the declared amount of vertical CSS pixels, but the video image is still being painted in the aspect ratio from metadata. The video image is centered horizontally in the element's box. Do we really want to match this exactly?
In fiddle example 3, there are no dimension attributes, no CSS, and Chrome && FF just match the video metadata . This is contrary to spec AFAICT. 300 x 150px doesn't play into it at all, it seems! Has the spec just been left behind at this point?
In fiddle part 4, the video gets width and height from CSS, but still there is no stretching.
I think we're naively expecting the <video> element to stretch like an <img>, which apparently just isn't the case. The WHATWG spec for video spells this out a bit more clearly:
In the absence of style rules to the contrary, video content should be rendered inside the element's playback area such that the video content is shown centered in the playback area at the largest possible size that fits completely within it, with the video content's aspect ratio being preserved. Thus, if the aspect ratio of the playback area does not match the aspect ratio of the video, the video will be shown letterboxed or pillarboxed. Areas of the element's playback area that do not contain the video represent nothing.
The only way to get stretching on the video element is to use CSS transforms, which obviously don't work on ancient browsers. Try:
which is just a chaos of bug behaviors. Based on this, I suggest we steer completely around _stretch_.
I also suggest that the logic in my original PR (in which intrinsic ratio clobbers any specified ratio) is a fairly correct mapping of the native element.
That would leave the question of whether we want to pillarbox/letterbox the video image inside a non-auto specified playback area. And does the playback bar hug the bottom of the playback area or the bottom of the video image? Etc. This adds a mountain of complexity, and I'm not sure it's worth it. Authors wanting content of unknown aspect ratio centered in a responsive box can add their own wrapper div and CSS centering. Do we really want to take this on internally?
SIDEBAR: The video element is natively an inline element, and vjs wraps the tech in a block-level div. Is that a vjs bug or a design feature? Inline video is probably fairly rare in the wild. But how would you feel about replacing the wrapper div with an inline-block span to align better with native? Note however that assigning display:block doesn't change any of the above layout behaviors:
I think there's a few issues with fiddle example.
Adding CSS complicates the issue. As far as the video.js API goes, we're just concerned about making it act like the video element width/height API, which just adjusts the element properties/attributes, not CSS. We currently are using CSS internally to force it to work correctly since div width/height attributes do nothing. See #983 for how we can improve on that specifically. The goal would be that if someone does use CSS to style the player, it would override our internal width/height settings, just like it would with the video element.
When it comes to the player width/height, I'm not referring to the displayed video pixels width/height. As you found, the browser will always display the video pixels at the correct aspect ratio. The video element itself can be set to any size and the browser will make the displayed video fit within those dimensions. If you put a background on the video element you can see that it does match the dimensions you give it on the video tag, even if the video pixels don't fill those dimensions.
As far as the metadata and 300x150 settings, try setting preload=none. The browser will use 300x150 if it doesn't have the metadata.
I've got to run out right now but will dig more into this later.
Here's an example of what I was talking about a few comments ago, about how the metadata dimensions are only used if there are no user-defined dimensions, and the 300x150 default is only used if there are no user-defined dimensions and no metadata dimensions.
http://jsbin.com/kunoru/2/edit
So basically I still think we shouldn't be overriding user-defined aspect ratios with metadata aspect ratios.
how would you feel about replacing the wrapper div with an inline-block span
I'd be interested in exploring using an in-line block, though that change would have to wait for v5.0 since it's a pretty big skin change. I don't think changing the tag to a span is actually necessary.
Also, agreed we should avoid trying to do stretch. :)
For what it's worth, I was able to get around the aspect ratio thing by applying object-fit: initial; to the video element. The downside is the browser support for this property, so that solution only worked in Chrome. _Thanks, Obama!_
However, I got around that using this polyfill.
Example (coffeescript):
objectFit.polyfill
selector: '.video-thumbnail .video-player video'
fittype: 'fill'
@brandonaaskov object-fit is gamechanging. Tab Atkins' idea to generalize SVG's preserveAspectRatio to CSS is brilliant. But it's still years away from production. First, we would have to include the polyfill, not very light at 12k minified. Also the polyfill author warns ominously about 'unexpected behaviors.' I'm sure! The core problem is that CSS layout in general has to respond to arbitrary DOM and CSS changes, and not just window resize or mutation of the one element under consideration. Polyfilling that and polling for all possible changes to CSS and the DOM is basically impossible, and out of scope here. Cool experiment though!
So basically I still think we shouldn't be overriding user-defined aspect ratios with metadata aspect ratios.
Got it!
As a step towards a test bed for dimension issues, I created this gist:
https://gist.github.com/baloneysandwiches/4e3e88b3b88ee767db97
Basically, the problems are so intertwined that separate, incremental feature adds might be tricky. Even just handling "the basics" immediately raises a hairball of not-so-edge cases. I think it will be actually easier in the long run to do this in one big push, if possible, and get it close-to-right the first time. If we can get solid agreement all around on all these scenarios, and add a few more that people are concerned about, then we can visualize a decision tree, code the tests, and get to code that passes these tests.
So I am able to get this working quite well with adjusting the width dynamically if the browser window is too narrow(and it's height in relation to the aspect ratio). However, when the browser window is shorter, it does not adjust the height or the width accordingly and part of the video may be offstreen.
I have tried using the code at
http://coolestguidesontheplanet.com/videodrome/videojs/
&
http://andreassauer.name/experimente/video-js/demo.html
which both work great for dynamic width, but not height.
Basically, I have a page that is nothing but the video player. And I want the video to play at 1280x720, some low resolution and/or widescreen monitors will not fill the entire 720 pixels in browser.
Is there a way to do this? Any help appreciated.
We were able to factor in the height of the browser window by setting the width of an outer container using vh units (width: 124vh;). You can see a demo on our video player pages:
http://www.funnyordie.com/videos/18e820ec3f/between-two-ferns-with-zach-galifianakis-president-barack-obama
I see that it works, but I am sorry I am kind of a novice with this sort of this and the source code of your site is completely overwhelming to me lol.
Even when I crtl+f I couldn't find anything referencing "vh" units
vh is a viewport height unit, here are a few good overviews:
http://css-tricks.com/viewport-sized-typography/ http://css-tricks.com/viewport-sized-typography/
http://demosthenes.info/blog/660/Using-vw-and-vh-Measurements-In-Modern-Site-Design http://demosthenes.info/blog/660/Using-vw-and-vh-Measurements-In-Modern-Site-Design
On Sep 29, 2014, at 1:45 PM, cbt3 [email protected] wrote:
I see that it works, but I am sorry I am kind of a novice with this sort of this and the source code of your site is completely overwhelming to me lol.
Even when I crtl+f I couldn't find anything referencing "vh" unitsâ
Reply to this email directly or view it on GitHub https://github.com/videojs/video.js/issues/982#issuecomment-57226718.
If I create "div { height: 50vh; } code, i end up with this
http://live-uat.plma.net/pre/test.png
The height will be responsive, but only by adding black and losing the locked aspec ratio of the video player (although the video itself remains 16x9)
This results in the video being cut off at the bottom and needing to scroll.
div { height: 50vh; }
.wrapper{padding:1% 1%;border:solid 2rem #fff;}
.videocontent{max-width:1280px;max-height:720px;margin:0 auto;}
.video-js{padding-top:56.25%;}.vjs-fullscreen{padding-top:0px;}
Reducing the value of the vh only reduces how much extra black is present.
If I try putting height: 50vh; in the .wrapper or .videocontent, nothing happens, also if i try doing it inline in the
Like I said, I am pretty dumb with this stuff, thank you guys for trying to help.
Donât wrap a div w/ height: 50vh, instead keep the settings you already have in .videocontent and add a "width: 125vh;" declaration.
Also, if you need help w/ CSS, you should take the discussion to stackoverflow or somewhere. The github issues isnât a very appropriate place to have this discussion.
On Sep 30, 2014, at 8:45 AM, cbt3 [email protected] wrote:
If I create "div { height: 50vh; } code, i end up with this
http://live-uat.plma.net/pre/test.png http://live-uat.plma.net/pre/test.png
The height will be responsive, but only by adding black and losing the locked aspec ratio of the video player (although the video itself remains 16x9)
This results in the video being cut off at the bottom and needing to scroll.div { height: 50vh; }
.wrapper{padding:1% 1%;border:solid 2rem #fff;}
.videocontent{max-width:1280px;max-height:720px;margin:0 auto;}
.video-js{padding-top:56.25%;}.vjs-fullscreen{padding-top:0px;}
Reducing the value of the vh only reduces how much extra black is present.
If I try putting height: 50vh; in the .wrapper or .videocontent, nothing happens, also if i try doing it inline in the
still nothing happens
Like I said, I am pretty dumb with this stuff, thank you guys for trying to help.â
Reply to this email directly or view it on GitHub https://github.com/videojs/video.js/issues/982#issuecomment-57334694.
Sorry, I thought it was relevant to the responsive sizing discussion.
This works now for the height, which is great, but the width no longer is responsive.
I have tried using the CSS only solution mentioned by @j4k3 on Aug 2. In general, this worked well for me. However, the aspect ratio was somehow thrown off just enough to create extra "space" above/below the video. Could not figure out how to fix that.
The CSS solution is basically the same as outlined in the css-tricks article (as well as other places): Fluid Width Video. In there they put height: 0; in the wrapper, which in this case is the .video-js:after block. Adding this closed up the extra space.
.video-js {
width: 100% !important;
height: auto !important;
}
.video-js:after {
content: '.';
display: block;
position: relative;
padding: 40.1% 0 0 0; /* (height/width)*100%, eg. 56.25% for 16:9 75% for 4:3 */
margin: 0 0 0 -100%;
visibility: hidden;
height: 0;
}
Just posting in case someone else runs into this problem...
this is css u can use for responsive
body .video-js .vjs-tech {
position: static;
max-width: 100%;
height: auto;
}
I would say that CSS transform is the best implementation choice. Ancient browsers are pre-mobile, and we usually want responsive for mobile environment. I would rather develop a good rock-solid solution using CSS transform, and offer a best-effort solution fallback for stone age browsers.
.video-js-responsive-container.vjs-hd {
padding-top: 56.25%;
}
.video-js-responsive-container.vjs-sd {
padding-top: 75%;
}
.video-js-responsive-container {
width: 100%;
position: relative;
}
.video-js-responsive-container .video-js {
height: 100% !important;
width: 100% !important;
position: absolute;
top: 0;
left: 0;
}
hd = 16:9, sd=4:3
<div class="video-js-responsive-container vjs-hd">
<video .... standard videojs code ... >
... sources ...
</video>
</div>
http://stackoverflow.com/a/24413783 (Adapted from: http://css-tricks.com/NetMag/FluidWidthVideo/Article-FluidWidthVideo.php)
That css code works great: http://rmshow.tk/ (example video.js resizing)
Responsive Sizing
https://github.com/videojs/video.js/issues/982
@digitalmoksha commented on 14 Oct 2014
I have tried using the CSS only solution mentioned by @j4k3 on Aug 2. In general, this worked well for me. However, the aspect ratio was somehow thrown off just enough to create extra "space" above/below the video. Could not figure out how to fix that.
The CSS solution is basically the same as outlined in the css-tricks article (as well as other places): Fluid Width Video. In there they put height: 0; in the wrapper, which in this case is the .video-js:afterblock. Adding this closed up the extra space.
.video-js { width:100%!important; height: auto!important; }
.video-js:after { content:'.'; display:block; position:relative; padding:40.1% 0 0; margin:0 0 0 -100%; visibility:hidden; height:0; }
Example:
Closed thanks to #1952.
To save people from reading this enormous thread, can something be added to the README that explains how to implement fluid/responsive sizing?
@SimonEast wanna help put one together?
If base video is 1903x965 ...
adding the same to jQuery(window).resize() makes it even responsiver :D
var windowWidth = $(window).innerWidth();
var sizeRatio = windowWidth/1903;
var videoHeight = 965*sizeRatio;
$(".videocontent").height(videoHeight);
yes @SimonEast : I am missing some real documentation. There isn't a chapter on how to use data-setup properly and what options are available.
I love the performance of videojs but getting the videos to stay within the my containers is becoming a hassle
Not really documentation but I wrote a bit about fluid mode here: http://videojs.github.io/blog/Video-js-5-s-fluid-mode-and-playlist-picker/
I also plan on tackling docs soon.
I tried another player but I'm going to give video.js another attempt. Hope I can get it playing nicely
What am I missing? I feel like such a noob atm.
I'm including screenshots of the code and result between videojs with & without fluid.
But also one of JWplayer
The html
<div class="screen" >
<video>
</video>
</div>
The css for ".screen"
width:24%;
margin:2px;
VideoJS { fluid :false }

VideoJS { fluid :true}

JWplayer

Do you include css of video-js, for example http://vjs.zencdn.net/5.10.7/video-js.min.css ?
I'm almost sad that I did include it ;)
Thanks for the suggestion.
A friend came to the rescue. Hopefully I will have time soon to add it to your codebase as a setup option "responsive : true".
Init:
videojs(....).addClass("video-js");
css:
.video-js {
height: 0px !important;
width: 100% !important;
padding-top: 62.5%; // or find aspect ratio of video, e.g. 16:9 and do calc(B/(A/100) = aspectRatio -> calc(9/(16/100) = 56.25%
}

you probably also want to call player.aspectRatio with 16:9 or something like that or add the vjs-16-9 class to the player.
Most helpful comment
To save people from reading this enormous thread, can something be added to the README that explains how to implement fluid/responsive sizing?