I have a web view that doesn't take up the full screen. I set it's url to a youtube video to play the video in the web view area. When I change orientation of the device the view resizes but the content doesn't. If I set the scales page to fit flag on the web view it changes orientation properly but there's always white space around the video on the right and bottom regardless of orientation.
How can I get the video to fill the web view, and resize with orientation change without the wasted padding. Alternatively how can I make the video play full screen like it does on iPhone (which would be a viable alternative for me, skipping over the layout issue)
I read this tutorial and was able to solve the problem.
http://webdesignerwall.com/tutorials/css-elastic-videos
basically you can set the size of the containing item to one thing for portrait and another for landscape.
Also set your object embed code to have a height width of 100% instead of a fixed width.
This is my html:
<span class="youtube">
<object type="application/x-shockwave-flash" id="ytPlayer" style="visibility: visible;" allowscriptaccess="always">
</object>
</span>
This is my javascript:
var ytswf = document.getElementById('ytPlayer');
var videoID = 'Nky9omXFZD4';
ytswf.outerHTML = "<object height=\"100%\" width=\"100%\" type=\"application/x-shockwave-flash\" data=\"http://www.youtube.com/v/" + videoID + "&enablejsapi=1&playerapiid=ytplayerObj&rel=0&fs=1&autoplay=0&egm=0\" id=\"ytPlayer\" style=\"visibility: visible;\" ><param name=\"allowFullScreen\" value=\"True\" /><param name=\"allowScriptAccess\" value=\"always\" /></object>";
This is my css:
.youtube{width:432px; height:245px;}
#media only screen and (orientation:portrait)
{
.youtube{width:702px; height:398px;}
}
I use the following code and it works for me
// css
// You can add your own width and height values or insert this values using stringWithFormat
NSString *css = #"<style type=\"text/css\">\
.youtube{width:320px; height:363px;}\
#media only screen and (orientation:portrait) { \
.youtube{width:320px; height:363px;}\
}\
\
#media only screen and (orientation:landscape) {\
.youtube{width:480px; height:203px;}\
}\
</style>\
";
// different format of urls for iOS 5 and iOS 6
NSString *src = ([[[UIDevice currentDevice] systemVersion] compare:#"6" options:NSNumericSearch] == NSOrderedAscending)
? #"http://www.youtube.com/watch?v=%#?autoplay=1" // iOS 5
: #"http://www.youtube.com/v/%#?autoplay=1"; // iOS 6
// inserting css in <head> and inserting src
NSString *youTubeVideoHTML = [NSString stringWithFormat:
(#"<html><head>%#</head>\
<body style=\"margin:0\">\
<embed class=\"youtube\" id=\"yt\" src=\"%#\" type=\"application/x-shockwave-flash\" \
></embed>\
</body></html>") , css , src ];
// setting YouTube video ID
finalHtml = [NSString stringWithFormat: youTubeVideoHTML , videoID ];
[self.webView loadHTMLString:finalHtml baseURL:nil];
Related
I find that if I use WKWebView with
viewport-fit=cover
and
body :{height:100%}
the height of html body still can not reach the bottom of iPhone X and is equal to the height of safeArea, However, the background-color can cover the fullscreen.
https://ue.qzone.qq.com/touch/proj-qzone-app/test.html
I load this page in a fullscreen WKWebView to reproduce the problem.
I was able to fix the issue with (ObjC / Swift):
if (#available(iOS 11.0, *)) {
webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
or
if #available(iOS 11.0, *) {
webView.scrollView.contentInsetAdjustmentBehavior = .never;
}
This setting seems to have the same effect as viewport-fit=cover, thus if you know your content is using the property, you can fix the bug this way.
The env(safe-area-inset-top) CSS declarations still work as expected. WKWebView automatically detects when its viewport intersects with blocked areas and sets the values accordingly.
Documentation for contentInsetAdjustmentBehavior and its parameter values and kudos to #dpogue for the answer where I found the solution.
I found setting height in CSS on the html element to be height: 100vh (rather than height: 100%) worked
In your code, if you add
opacity: 0.5;
to the html and body tags you'll see that the body tag does take the full screen while the html tag height is only as tall as the safe area.
If you just want the html area to reach the edges you can explicitly set:
<html style='height: 812px;'>
This will make the content within the html properly fit the full screen as long as you also add:
<meta name="viewport" content="initial-scale=1.0, viewport-fit=cover">
Not the most elegant solution of course, but it does work.
I cam across this issue in my Cordova app.
Samantha's solution worked for me to an extent but having a height of 812px set in the html tag was causing issues whilst in landscape and with other devices. Eventually I found that targeting just the iPhone X sized screen with css media queries for both landscape and portrait did the trick.
The width and height pixel values needed to be declared as important in order for the iPhone to accept them.
#media only screen
and (device-width : 375px)
and (device-height : 812px)
and (-webkit-device-pixel-ratio : 3)
and (orientation : portrait) {
html {
height: 812px !important;
width: 375px !important;
}
}
#media only screen
and (device-width : 375px)
and (device-height : 812px)
and (-webkit-device-pixel-ratio : 3)
and (orientation : landscape) {
html {
width: 812px !important;
height: 375px !important;
}
}
You need to set UIEdgeInsets for your web view to stretch all the way to bottom (covering the notch).
You can achieve this by creating a subclass of WKWebView!
Check this out.
I have embedded a youtube video in a UIWebView for display in my app.
Here's the code for that:
func loadVideo(){
if let youtubeCode = exerciseYoutubeCode {
guard !youtubeCode.isEmpty else { return }
exerciseVideoWebView.isHidden = false
exerciseVideoWebView.allowsInlineMediaPlayback = true
exerciseVideoWebView.scrollView.isScrollEnabled = false
exerciseVideoWebView.scrollView.bounces = false
exerciseVideoWebView.loadHTMLString("<html><head><style>body{margin:0px}</style></head><body><iframe width=\"\(exerciseVideoWebView.frame.width)\" height=\"\(exerciseVideoWebView.frame.height)\" src=\"https://www.youtube.com/embed/\(youtubeCode)?&playsinline=1\" frameborder=\"0\" allowfullscreen></iframe></body></html>",
baseURL: nil)
}
}
The problem is that the embedded video does not seem to be respecting the width and height of the UIWebView that I am passing in to the iframe. In the simulator, the video is roughly 15-25 pixels larger than the UIWebView. I can live with that, but when running on a physical device, it's rendering 15-25 pixels smaller than the UIWebView, exposing the white of the HTML page on the right and bottom sides of the UIWebView.
The UIWebView has an AutoConstraint to a 16:9 ratio, which matches YouTube's video aspect ratio.
If I put the following script into the HTML, I can see that the width and height of the video iframe is an exact match to the height and width printed to the console for the UIWebView:
<script>setTimeout(function(){
alert(document.getElementsByTagName('iframe')[0].offsetWidth + ' ' + document.getElementsByTagName('iframe')[0].offsetHeight)},10000)
</script>
Clearly there is some sort of scaling happening if the HTML thinks its the same size as the UIWebView, but I can't figure out how to fix it.
In iOS 6 everything works fine. The keyboard opens and moves the input into view. When the keyboard closes everything goes back where it should.
In iOS 7 the keyboard opens fine and the input remains in view. When the keyboard is closed the whole bottom half of the app is gone, though. I've tracked the issue down to the height of the window changing when the keyboard is opened, and not changing back when it's closed.
Right before the keyboard is opened the window height is 568 according to $(window).height() and after it's opened and after it's closed it is 828. The height of the document also changes accordingly.
I've attempted preventing the window from resizing with:
$(window).resize(function(e) {
e.preventDefault();
e.stopPropagation();
window.resizeTo(320,480);
return false;
});
I've also attempted to set the size back after the keyboard closes with no success.
I'm using phonegap 2.7 and have KeyboardShrinksView set to true.
I was seeing this too. After the height changes, some of our absolute positioned elements disappear off the bottom of the screen.
I found that with KeyBoardShrinksView = false in ios7, window.height stayed constant. This was the opposite of ios6 though, so a bit of a catch 22.
Not sure if there's a better way of handling this in Phonegap, but I put this in CDVViewController.m, created to config.xml files for ios < v7 and ios > v6, and my app works the way I want. Seemed a bit hacky, but not too disruptive of the rest of my code.
// read from config.xml in the app bundle
NSString* path = [[NSBundle mainBundle] pathForResource:#"config" ofType:#"xml"];
if (IsAtLeastiOSVersion(#"7.0")) {
path = [[NSBundle mainBundle] pathForResource:#"config_ios7" ofType:#"xml"];
}
(I also tried an app preference plugin at https://github.com/phonegap/phonegap-plugins/tree/master/iPhone/ApplicationPreferences but don't think this was designed for this kind of preference.)
After I upgraded my project to iOS with cordova 3.1 I start having similar problems for the input fields in where I did not have the code listed above. The keyboard pushes things up and the header and footer did not returned to their original positions. I have tested and that solve the problem (maybe not very elegantly but it is a workaround). I just put that code on my pageinit event.
/*************************************************************************************************
* FIX: to avoid the buggy header and footer to jump and stick not
* to the top/bottom of the page after an input or textfield lost focus and the keyboard dissapear *
*************************************************************************************************/
$('input, textarea')
.on('focus', function (e) {
$('header, footer').css('position', 'absolute');
})
.on('blur', function (e) {
$('header, footer').css('position', 'fixed');
//force page redraw to fix incorrectly positioned fixed elements
setTimeout( function() {
window.scrollTo( $.mobile.window.scrollLeft(), $.mobile.window.scrollTop() );
}, 20 );
});
add code into CDVViewController.m
for example it added into webViewDidFinishLoad function
CGRect newFrame = self.webView.bounds;
NSLog(#"%f" , newFrame.size.height);
NSString *JS = [NSString stringWithFormat:#"viewport = document.querySelector('meta[name=viewport]'); viewport.setAttribute('content', 'user-scalable=no, initial-scale=1.0, maximum-scale=0.5, minimum-scale=0.5, width=device-width, height=%d, target-densitydpi=device-dpi');", (int) newFrame.size.height*2 ];
[self.webView stringByEvaluatingJavaScriptFromString:JS];
this code change <meta name="viewport" content="..."> and set height of device
set your viewport meta tag to your html
<meta name="viewport" content="width=device-width,height=**yourheight**, initial-scale=1, maximum-scale=1, user-scalable=0" >
or
<meta name="viewport" content="width=device-width,height=**device-height**, initial-scale=1, maximum-scale=1, user-scalable=0" >
The Petrash's solution worked for me. But I had still problems supporting rotations on iPad.
So, in the same CDVViewController.m I've added this method:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
if (self.webView){
CGRect newFrame = self.webView.bounds;
//NSLog(#"%f" , newFrame.size.height);
NSString *JS = [NSString stringWithFormat:#"viewport = document.querySelector('meta[name=viewport]'); viewport.setAttribute('content', 'user-scalable=no, initial-scale=1.0, maximum-scale=1, minimum-scale=1, width=device-width, height=%d, target-densitydpi=device-dpi');", (int) newFrame.size.height*1 ];
[self.webView stringByEvaluatingJavaScriptFromString:JS];
}
}
and, to support the "non scale" behaviour, edited the Petrash's solution in this way:
CGRect newFrame = self.webView.bounds;
//NSLog(#"%f" , newFrame.size.height);
NSString *JS = [NSString stringWithFormat:#"viewport = document.querySelector('meta[name=viewport]'); viewport.setAttribute('content', 'user-scalable=no, initial-scale=1.0, maximum-scale=1, minimum-scale=1, width=device-width, height=%d, target-densitydpi=device-dpi');", (int) newFrame.size.height*1 ];
[self.webView stringByEvaluatingJavaScriptFromString:JS];
KeyboardShrinksView = false
This is hacky, but it works from 5.1 to 7.0.3. Tested on Cordova 3.0.
After hours of investigating I've managed to get it to work:
My div, that is pushed up and never get's down again,
had the css attribute
position:fixed;
I switched this to
position:absolute;
and everything worked!
The best way I found was to put everything into a div and fix its height via javascript.
Works on modern Versions of both iOS (5, 6, 7) and Android (4.2, ...).
<style>
body {
overflow-y: scroll;
overflow-x: hidden;
webkit-overflow-scrolling: touch;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
body > .viewport{
position: absolute;
top: 0;
left: 0;
right: 0;
}
</style>
<body>
<div class='viewport'>
<!-- Put everything here -->
</div>
</body>
<script type="text/javascript">
$("body > .viewport").height($(document).height());
// WARNING: if your app works in both landscape and portrait modus, then you should reset the height of the container when the app changes orientation
</script>
I had a similar issue that drove me nuts for days. Not sure if this will help anyone else, but this is what solved it for me: (note I'm using jquery finger library to listen to tap events):
$('body').delegate("#send_feedback_button","tap", function(event){
$('textarea').blur();
event.stopImmediatePropagation();
// do my stuff
});
For me calling blur on any textarea in the view was the trick. The stopImmediatePropagation got rid of some other funkiness.
I had the same problem and I managed to track it down to dynamic content.
I had initially an empty div that was filled with text using javascript.
When I pre filled the div with static text the problem was gone.
Looks like this div's height was not counted when resizing.
I am embedding youtube video inside a UIWebView. The Size of the UIWebView is 124x86. And the Code for the same is:
NSString* embedHTML =#"\
<html><head>\
<style type=\"text/css\">\
body {\
background-color: transparent;\
color: white;\
}\
</style>\
</head><body style=\"margin:0\">\
<embed id=\"yt\" src=\"%#\" type=\"application/x-shockwave-flash\" \
width=\"124\" height=\"86\"></embed>\
</body></html>";
When Loaded, the thumbnail doesn't show up properly. its size is way bigger than 124x86 and not fitting into UIWebView. (So now I can see only 1/4th portion of the thumbnail).
I want that thumbnail gets shrinks (or gets generated) to the size of 124x86 and fits into UIWebView.
I'm building a iPhone Web Application and want to lock the orientation to portrait mode. is this possible? Are there any web-kit extensions to do this?
Please note this is an application written in HTML and JavaScript for Mobile Safari, it is NOT a native application written in Objective-C.
This is a pretty hacky solution, but it's at least something(?). The idea is to use a CSS transform to rotate the contents of your page to quasi-portrait mode. Here's JavaScript (expressed in jQuery) code to get you started:
$(document).ready(function () {
function reorient(e) {
var portrait = (window.orientation % 180 == 0);
$("body > div").css("-webkit-transform", !portrait ? "rotate(-90deg)" : "");
}
window.onorientationchange = reorient;
window.setTimeout(reorient, 0);
});
The code expects the entire contents of your page to live inside a div just inside the body element. It rotates that div 90 degrees in landscape mode - back to portrait.
Left as an exercise to the reader: the div rotates around its centerpoint, so its position will probably need to be adjusted unless it's perfectly square.
Also, there's an unappealing visual problem. When you change orientation, Safari rotates slowly, then the top-level div snaps to 90degrees different. For even more fun, add
body > div { -webkit-transition: all 1s ease-in-out; }
to your CSS. When the device rotates, then Safari does, then the content of your page does. Beguiling!
You can specify CSS styles based on viewport orientation:
Target the browser with body[orient="landscape"] or body[orient="portrait"]
http://www.evotech.net/blog/2007/07/web-development-for-the-iphone/
However...
Apple's approach to this issue is to allow the developer to change the CSS based on the orientation change but not to prevent re-orientation completely. I found a similar question elsewhere:
http://ask.metafilter.com/99784/How-can-I-lock-iPhone-orientation-in-Mobile-Safari
The following code was used in our html5 game.
$(document).ready(function () {
$(window)
.bind('orientationchange', function(){
if (window.orientation % 180 == 0){
$(document.body).css("-webkit-transform-origin", "")
.css("-webkit-transform", "");
}
else {
if ( window.orientation > 0) { //clockwise
$(document.body).css("-webkit-transform-origin", "200px 190px")
.css("-webkit-transform", "rotate(-90deg)");
}
else {
$(document.body).css("-webkit-transform-origin", "280px 190px")
.css("-webkit-transform", "rotate(90deg)");
}
}
})
.trigger('orientationchange');
});
I came up with this CSS only method of rotating the screen using media queries. The queries are based on screen sizes that I found here. 480px seemed to be a good as no/few devices had more than 480px width or less than 480px height.
#media (max-height: 480px) and (min-width: 480px) and (max-width: 600px) {
html{
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform: rotate(-90deg);
-webkit-transform-origin: left top;
-moz-transform-origin: left top;
-ms-transform-origin: left top;
-o-transform-origin: left top;
transform-origin: left top;
width: 320px; /*this is the iPhone screen width.*/
position: absolute;
top: 100%;
left: 0
}
}
Screen.lockOrientation() solves this problem, though support is less than universal at the time (April 2017):
https://www.w3.org/TR/screen-orientation/
https://developer.mozilla.org/en-US/docs/Web/API/Screen.lockOrientation
I like the idea of telling the user to put his phone back into portrait mode.
Like it's mentioned here: http://tech.sarathdr.com/featured/prevent-landscape-orientation-of-iphone-web-apps/
...but utilising CSS instead of JavaScript.
Maybe in a new future it will have an out-of-the-box soludion...
As for May 2015,
there is an experimental functionality that does that.
But it only works on Firefox 18+, IE11+, and Chrome 38+.
However, it does not work on Opera or Safari yet.
https://developer.mozilla.org/en-US/docs/Web/API/Screen/lockOrientation#Browser_compatibility
Here is the current code for the compatible browsers:
var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation;
lockOrientation("landscape-primary");
While you cannot prevent orientation change from taking effect you can emulate no change as stated in other answers.
First detect device orientation or reorientation and, using JavaScript, add a class name to your wrapping element (in this example I use the body tag).
function deviceOrientation() {
var body = document.body;
switch(window.orientation) {
case 90:
body.classList = '';
body.classList.add('rotation90');
break;
case -90:
body.classList = '';
body.classList.add('rotation-90');
break;
default:
body.classList = '';
body.classList.add('portrait');
break;
}
}
window.addEventListener('orientationchange', deviceOrientation);
deviceOrientation();
Then if the device is landscape, use CSS to set the body width to the viewport height and the body height to the viewport width. And let’s set the transform origin while we’re at it.
#media screen and (orientation: landscape) {
body {
width: 100vh;
height: 100vw;
transform-origin: 0 0;
}
}
Now, reorient the body element and slide (translate) it into position.
body.rotation-90 {
transform: rotate(90deg) translateY(-100%);
}
body.rotation90 {
transform: rotate(-90deg) translateX(-100%);
}
// CSS hack to prevent layout breaking in landscape
// e.g. screens larger than 320px
html {
width: 320px;
overflow-x: hidden;
}
This, or a similar CSS solution, will at least preserve your layout if that is what you are after.
The root solution is accounting for device's capabilities rather than attempting to limit them. If the device doesn't allow you the appropriate limitation than a simple hack is your best bet since the design is essentially incomplete. The simpler the better.
In coffee if anyone needs it.
$(window).bind 'orientationchange', ->
if window.orientation % 180 == 0
$(document.body).css
"-webkit-transform-origin" : ''
"-webkit-transform" : ''
else
if window.orientation > 0
$(document.body).css
"-webkit-transform-origin" : "200px 190px"
"-webkit-transform" : "rotate(-90deg)"
else
$(document.body).css
"-webkit-transform-origin" : "280px 190px"
"-webkit-transform" : "rotate(90deg)"
Inspired from #Grumdrig's answer, and because some of the used instructions would not work, I suggest the following script if needed by someone else:
$(document).ready(function () {
function reorient(e) {
var orientation = window.screen.orientation.type;
$("body > div").css("-webkit-transform", (orientation == 'landscape-primary' || orientation == 'landscape-secondary') ? "rotate(-90deg)" : "");
}
$(window).on("orientationchange",function(){
reorient();
});
window.setTimeout(reorient, 0);
});
I have a similar issue, but to make landscape... I believe the code below should do the trick:
//This code consider you are using the fullscreen portrait mode
function processOrientation(forceOrientation) {
var orientation = window.orientation;
if (forceOrientation != undefined)
orientation = forceOrientation;
var domElement = document.getElementById('fullscreen-element-div');
switch(orientation) {
case 90:
var width = window.innerHeight;
var height = window.innerWidth;
domElement.style.width = "100vh";
domElement.style.height = "100vw";
domElement.style.transformOrigin="50% 50%";
domElement.style.transform="translate("+(window.innerWidth/2-width/2)+"px, "+(window.innerHeight/2-height/2)+"px) rotate(-90deg)";
break;
case -90:
var width = window.innerHeight;
var height = window.innerWidth;
domElement.style.width = "100vh";
domElement.style.height = "100vw";
domElement.style.transformOrigin="50% 50%";
domElement.style.transform="translate("+(window.innerWidth/2-width/2)+"px, "+(window.innerHeight/2-height/2)+"px) rotate(90deg)";
break;
default:
domElement.style.width = "100vw";
domElement.style.height = "100vh";
domElement.style.transformOrigin="";
domElement.style.transform="";
break;
}
}
window.addEventListener('orientationchange', processOrientation);
processOrientation();
<html>
<head></head>
<body style="margin:0;padding:0;overflow: hidden;">
<div id="fullscreen-element-div" style="background-color:#00ff00;width:100vw;height:100vh;margin:0;padding:0"> Test
<br>
<input type="button" value="force 90" onclick="processOrientation(90);" /><br>
<input type="button" value="force -90" onclick="processOrientation(-90);" /><br>
<input type="button" value="back to normal" onclick="processOrientation();" />
</div>
</body>
</html>
Click here for a tutorial and working example from my website.
You no longer need to use hacks just to look jQuery Mobile Screen Orientation nor should you use PhoneGap anymore, unless you're actually using PhoneGap.
To make this work in the year 2015 we need:
Cordova (any version though anything above 4.0 is better)
PhoneGap (you can even use PhoneGap, plugins are compatible)
And one of these plugins depending on your Cordova version:
net.yoik.cordova.plugins.screenorientation (Cordova < 4)
cordova plugin add net.yoik.cordova.plugins.screenorientation
cordova plugin add cordova-plugin-screen-orientation (Cordova >= 4)
cordova plugin add cordova-plugin-screen-orientation
And to lock screen orientation just use this function:
screen.lockOrientation('landscape');
To unlock it:
screen.unlockOrientation();
Possible orientations:
portrait-primary The orientation is in the primary portrait mode.
portrait-secondary The orientation is in the secondary portrait mode.
landscape-primary The orientation is in the primary landscape mode.
landscape-secondary The orientation is in the secondary landscape mode.
portrait The orientation is either portrait-primary or portrait-secondary (sensor).
landscape The orientation is either landscape-primary or landscape-secondary (sensor).