I have a website that uses jquery mobile for it's mobile version. I have a problem when I am changing it from portrait to landscape it zooms in correctly, but when I flip to portrait, it stays same zoom level and is wider then the view which breaks user experience.
I use regular:
<meta name="viewport" content="width=device-width, initial-scale=1">
from all the search I did, this should do. Unfortunately it isn't working for me.
Here is my question, I can use onorientationchange event to trigger resizing of the page, I am just not sure how to go about it. Can you help please?
P.S. website is here if you would like to take a peek http://tmg.dev.dakic.com/mobile
Thank you,
Zeljko
Try this, I had a similar issue:
$(window).bind('orientationchange', function(event) {
if (window.orientation == 90 || window.orientation == -90 || window.orientation == 270) {
$('meta[name="viewport"]').attr('content', 'height=device-width,width=device-height,initial-scale=1.0,maximum-scale=1.0');
$(window).resize();
$('meta[name="viewport"]').attr('content', 'height=device-width,width=device-height,initial-scale=1.0,maximum-scale=2.0');
$(window).resize();
} else {
$('meta[name="viewport"]').attr('content', 'height=device-height,width=device-width,initial-scale=1.0,maximum-scale=1.0');
$(window).resize();
$('meta[name="viewport"]').attr('content', 'height=device-height,width=device-width,initial-scale=1.0,maximum-scale=2.0');
$(window).resize();
}
}).trigger('orientationchange');
Try otherwise using the resize() function at certain events:
$(window).resize();
I typically use the orientationchangeevent to add / remove CSS classes to the content, and go from there, rather than re-size the viewport. Apple provide some stand-alone example code, although from memory I think that it only includes 90° and 0° orientations—you need -90° and 180° too, as in #zyrex comment.
iPhoneOrientation sample code (developer.apple.com)
Update per comment:
To clarify, I don't re-size HTML entities themselves, rather change the classes being used, and rely on CSS to style accordingly. To take a simplistic example, say I want to switch between two classes on the body element, depending on device orientation, I would do something like this in my Javascript:
window.onorientationchange = updateOrientation;
// (Might want to do this onload too)
function updateOrientation(){
var o = window.orientation, body = document.querySelector('body');
switch(o){
case 0: case 180:
body.className = 'portrait';
break;
case 90: case -90:
body.className = 'landscape';
break;
}
}
… and something like this in the default mark-up:
<body class="portrait">
<!-- stuff here -->
… and then CSS which does whatever is required—e.g. a different position for the body element's background:
body {background: url('images/something.png') no-repeat}
body.portrait {background-position: 30% 50%}
body.landscape {background-position: 10% 25%}
Update #2
You may also need to tinker with the maximum-scale directive in your meta tag. Mobile Safari typically does a zoom when changing from portrait to landscape, instead of re-doing the page layout, and that may be what you're seeing.
The maximum-scale value prevents this, but you should note that this also means users can't do the normal pinch-to-zoom thing. Here's how the tag would look:
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
Be sure to check the answers here too:
How do I reset the scale/zoom of a web app on an orientation change on the iPhone?
It seems no-one knows. From what I could see, content on the page somewhere is wider then device-width and this is where the problem originates. However, how to go about solving this is still not quite clear.
Related
I have created an unpublished website using HTML, CSS & JavaScript and I would like to ensure that when you click onto another page, it will always load at 100% zoom (or at least 100% in chrome).
I have attempted this by using the constantly recommended feature 'initial-scale':
<meta name="viewport" content="width=device-width, initial-scale=1">
This works fine when a page is first loaded, but if you zoom in (e.g. to 50%) then leave that page then return to it, the zoom is still at 50% rather than resetting to 100%.
I would like the zoom to become 100% every time a page is visited independent of previous visits.
Thanks in advance!
You can do the following on page load:
(function() {
var scale = 'scale(1)';
document.body.style.webkitTransform = scale; // Chrome, Opera, Safari
document.body.style.msTransform = scale; // IE 9
document.body.style.transform = scale; // General
})();
The above function() format is a short-hand form of jQuery's $(document).ready().
Refer to this post on Stackoverflow: Force page zoom at 100% with JS
Hope this answers your question!
How to get the dimensions of the fullscreen (minimal-ui) view when not in fullscreen?
This is what the screen properties report:
window.screen.height; // 568 (Thats the screen height)
window.screen.availHeight; // 548 (???; Unknown dimension. Note, that is it not reporting the available space as per the spec.)
window.document.documentElement.clientHeight; // 460 (Thats the window size when not in fullscreen.)
When in fullscreen, the window.innerHeight is 529, which is the number I am trying to derive prior to entering the fullscreen mode.
Image illustrates the state of the screen I am referring to:
In iOS 8, it is entered with a "touch-drag down" gesture.
To clarify, the window.screen.availHeight reflects the maximum height the browser window, including all the toolbars, can have. If you look at the picture below, you see that 548 is just the height of the whole browser, without the iOS menubar. So, the availHeight property is not supposed to show the available space for the content, but the whole browser. It's used for desktop browsers, to detect things like the browser is maximized or not, by checking window.outerHeight against window.screen.availHeight.
But about getting the minimal UI height, right before getting into it. There's no standard property in the spec for it, as it's just a iOS only behavior. Apple could have put some non-standard properties to expose these information. But as I have checked the window and window.screen objects, there's nothing related. That's for the feasiblity, for now.
As a sidenote, what is the difference between knowing the new viewport size with resize event and knowing the would-be size in advance? The amount of work that can be done, prior to the resize event, should always be minimal, and if a layout change should happen, it should happen after the resize. So, knowing the numbers in advance, shouldn't help that much.
Consider this scenario that a user opens a webpage, and starts scrolling immediately. If we know the numbers before, there's nothing that we can do for the initial render of the screen, as it's not a minimal UI. Whatever that should be done, must begin rightaway after the user starts scrolling.
Now besides this, there's one other resize event that just looks like the minimal ui. On the iPad, when you have more than one tab, the height shrinks a bit more, to show the tabs. So, when the user closes the only other tab, the current page, gets a bit taller, and triggers a resize event too. But this new height is different from the height of the minimal UI. This suggests that this minimal ui, is just another boost in the height, not a Fullscreen-API-like mode.
So, if a page is dependent on the height, there's just too many possible changes to bear in mind. Hard-coding would be just a short-term solution, one day you won't be able to test all those devices.
But, I also should say that there's a downside to the resize event, it triggers after getting into the minimal ui, which may be too late. So, when the height starts to grow, there's no event to know about it. That's where I believe some custom fluid UIs may need to start an animation to change the sizes. In this case, to know about the beginning of this event, one may use an interval checking on the innerHeight, which will start to change immediately.
Anyway, if there is a necessary usecase for knowing the numbers beforehand any scrolling, I believe it's not available through the CSSOM, yet.
Edit:
Detecting minimal-ui is another thing, that still knowing the dimensions is not needed. Using Touch events, you can detect if the view has entered the minimal UI or not.
Checking the innerHeight in touchstart, touchmove and touchend events can help to detect the minimal ui. The naive approach is to check if at the end of the touch the innerHeight has increased or not. This will work for most of the cases, but it has a problem, if the user stops touching right in the middle of minimal-ui transition, we cannot be sure if we will enter the minimal UI. Checking against the last reported height by touchmove can help to check if we will revert to the default view.
Anyway, You may check the code below to see how it works. It has bugs and can be improved, but you'll get the idea. I didn't put it on codepen, as you couldn't scroll the entire page there.
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no">
<style>
div {
position: fixed;
left: 10px;
}
#dd1 {
top: 10px;
}
#dd2 {
top:30px;
}
#dd3 {
top: 50px;
}
</style>
<body>
<div id="dd1">Start: <span id="d1"></span></div>
<div id="dd2">Move: <span id="d2"></span></div>
<div id="dd3">End: <span id="d3"></span></div>
<section style="position:relative;height:3000px;"></section>
<script>
var d1 = document.querySelector("#d1");
var d2 = document.querySelector("#d2");
var d3 = document.querySelector("#d3");
var start_height=window.innerHeight;
var cur_height;
var end_height;
var normal_state=true;
var entered_minimal_ui=false;
//window.addEventListener("touchstart", start_handler, false);
window.addEventListener("touchmove", move_handler, false);
window.addEventListener("touchend", end_handler, false);
document.ontouchstart = control_touching;
d1.textContent=start_height;
function move_handler() {
if(cur_height>start_height) {
// we *may* enter the minimal-ui, but it's not final yet
d2.textContent="I detected minimal-ui faster. (Current: "+cur_height+")";
normal_state=false;
}
cur_height=window.innerHeight;
}
function end_handler() {
end_height=window.innerHeight;
if(end_height>start_height && end_height>=cur_height) {
d3.textContent="Hello minimal-ui. (End: "+end_height+")";
normal_state=false;
entered_minimal_ui=true;
}
else if(!entered_minimal_ui) {
d3.textContent="We didn't enter minimal-ui. Reverting.";
normal_state=true;
}
}
function control_touching() {
document.ontouchstart = function(e){
if(normal_state) {
return true;
}
else // just for testing
e.preventDefault();
}
}
</script>
</body>
</html>
References:
Illustration is from iPhone 5 Display Size and Web Design Tips article by Kyle Larson.
I just upgraded from cordova 3.0 to 3.1 and I'm still experiencing a very disturbing issue (which still exists when playing with KeyboardShrinksView preference).
Whenever I'm focusing an element (input/textarea) which triggers the keyboard opening, the element gets hidden behind the keyboard and I need to scroll down (using webkit-overflow-scrolling for scrolling by the way) in order to see the element and its content.
When KeyboardShrinksView is set to true the page won't even scroll, making it even worse.
Any solutions in order to fix this issue? I've seen a few questions and bug reports but with no working solutions (or solutions at all).
Playing with the "fullscreen" preference won't solve the problem.
Just had a very similar problem to this. Some of the hacks found on this site did work, but had nasty side effects (such as making a mess of scrolling or CSS layout). Finally came up with a brand new stupid hack.
Viewport meta tag:
<meta name="viewport" content="initial-scale=1, maximum-scale=1, width=device-width" />
JavaScript run after load:
document.body.style.height = screen.availHeight + 'px';
And that's it. Works on iOS 7 and I have no idea why.
Finally fixed the problem with the help of the following plugin: jQuery scrollTo plugin
Whenever i'm focusing on an element i'm triggering a focus event which does the following calculations and updates the scroll position:
updateScroll: function(e){
var el = $(e.currentTarget);
var offset = -$(".scrollerWrap").height() + $(el).height();
$(".scrollerWrap").scrollTo(el,{offset: offset});
}
Sticks the bottom of the input/textarea to the top of the keyboard. Works like a charm, even if the solution needs to go through that bit of JavaScript.
Well, logically the view should move up when the keyboard opens. I have faced a similar issue with iOS7 and to fix it I have applied few css tweaks.
Tweaks were applied on the wrapper class/id which is containing the content of the app.
position: relative;
overflow: hidden;
height: 460px;
width: 320px;
Note - Height and width are judged dynamically depending on the device height and width
height = window.innerHeight
width = window.innerWidth
By using jQuery selectors height and width are appended to wrapping class/id.
Works for me.
document.body.style.height = (screen.availHeight - 100) + 'px';
I think the issue here originates from Framework7.
document.body.style.height = window.outerHeight + 'px';
The above code placed in my index.js file worked like charm.
I've encountered similar problems before and could never really understand the workarounds, and so I ended up relying on plugins like iScroll. This is such simple task that I refuse to include a plugin for it - what I want is to prevent horizontal scroll in iOS. This includes the rubber band effect for any content that might be on the page but that isn't visible.
From what I understand I need to disable the rubber band altogether first and then apply the touch scroll to a container element (which I've given the id "touch"). Not sure if this is the right approach?
$(document).bind('touchmove', function(e) {
if (!e.target == '#touch') {
e.preventDefault();
}
});
Style for #touch
-webkit-overflow-scrolling: touch;
overflow: hidden;
height: 100%;
#media only screen and (max-width: 768px) {
width: 768px;
}
This doesn't prevent the horizontal width from staying at 728px however, the user is still able to scroll and see the hidden content. Ideas?
Well, the above metas are useful as such:
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta content="minimum-scale=1.0, width=device-width, maximum-scale=1, user-scalable=no" name="viewport" />
They prevent that bug in Safari that happens when the user rotates the screen. However, the most proper way to accomplish the desired functionality is:
Use a parent div with overflow hidden and make sure the height of this div is limited according to the viewport and a child div with overflow:auto or the css 3 overflow-y:scroll. So basically if the size of the content inside the child div exceeds the default size of the child, you can vertically/horizontally scroll through it. Because the parent has overflow:hidden, the content outside of the child will not be displayed, so you get a proper scroll effect. ** Also, if you use overflow: hidden and prevent default for all touchEvents, there will be no scrolling or weird browser behavior**
With the help of JavaScript, make sure that every element in the DOM is scaled according to the viewport, so avoid using static sizes for as many elements as possible.
Bind the touchStart, touchMove and touchEnd events. Safari doesn't always fire a touchEnd event unless a touchMove event is listened for as well. Even if it's just a placeholder, put it there to avoid the inconsistent behavior in Safari.
Horizontal sliding is possible in two ways: load new content in the same div after you detect the slide direction or populate that child div with all the elements and you are good to go and actually shifting the margins/position of the child inside it's parent to 'scroll'. Animation can be used for a slicker interface.
Bind your touch event listeners. I don't know what library or event management system you are using, but it doesn't matter. Just call the respective function for the respective task.
Get the slide direction(left/right):
var slideBeginX;
function touchStart(event){event.preventDefault();//always prevent default Safari actions
slideBeginX = event.targetTouches[0].pageX;
};
function touchMove(event) {
event.preventDefault();
// whatever you want to add here
};
function touchEnd(event) {
event.preventDefault();
var slideEndX = event.changedTouches[0].pageX;
// Now add a minimum slide distance so that the links on the page are still clickable
if (Math.abs(slideEndX - slideBeginX) > 200) {
if (slideEndX - slideBeginX > 0) {
// It means the user has scrolled from left to right
} else {
// It means the user has scrolled from right to left.
};
};
};
This work for me on Android, iPhone and iPad.
<!doctype html>
<html>
<head>
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta content="minimum-scale=1.0, width=device-width, maximum-scale=1, user-scalable=no" name="viewport" />
<title>Main</title>
</head>
<body>
...
</body>
</html>
Following link might be useful to you, here vertical is disabled and horizontal enabled, you just need to tweak the code a little for your purpose.
jquery-tools-touch-horizontal-only-disable-vertical-touch
In case you aren't concerned about vertical sliding, you can try the following code also -
document.ontouchmove = function(e){
e.preventDefault();
}
Hope it helps.
If you dont use the meta you will always get a rubber band effect.
<meta name="viewport" content="width=device-width" />
Even if the page fitted exactly the user would still be able to stretch the page wider than it should be able to go, you must use the view port to prevent this, there is no other way...
I am trying to implement a mobile website with the following appearance:
a fixed header
scrollable, zoomable content
content zoomed out when page is first loaded
I have been experimenting with IScroll 4 and the results seem good but there is one problem that I can't find a way around. The contents of my pages are user-generated html tables which are often wider than the screen. I would like the full width of the table to be visible when the user lands on the page. They can then zoom in if they want to.
If you look at the IScroll zoom demo in a mobile browser it demonstrates the problem. The page content is wider than the screen and it's not possible to zoom out, only zoom in.
Changing the initial-scale in the viewport meta tag doesn't help as the whole page, including the header, gets zoomed out:
<meta name="viewport" content="width=device-width, initial-scale=0.5, user-scalable=yes, minimum-scale=0.5, maximum-scale=1.0">
(the header will eventually be a JQueryMobile element which I don't want to mess with).
And modifying the zoomMin setting in iscroll.js (v4.2.2, line 119) from 1 to something smaller (e.g. 0.5) breaks things:
// Zoom
zoom: false,
zoomMin: 1,
zoomMax: 4,
You can zoom out further but the content then gets stuck and you can't resize it without reloading the page.
Does anyone know a way around this? I'm happy to try other frameworks if necessary.
To allow zooming out, you can use the zoomMin and zoomMax that you identified, but do it when you instantiate iscroll, rather than modifying iscroll.js:
<script type="text/javascript">
var myScroll;
function loaded() {
myScroll = new iScroll('wrapper',
{ zoom:true, onBeforeScrollStart: null,
zoomMin:0.5, zoomMax: 6 });
}
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
document.addEventListener('DOMContentLoaded', loaded, false);
</script>
I also found I needed to explicitly set the width of the 'scroller' div, like so:
$('#scroller').width(your_width);