Hiding URL AddressBar on Android in Landscape Mode - javascript

Using JavaScript, how do I scroll past the URL bar in Landscape mode. On Portrait mode, you just do window.scrollTo(0,1) and that works, but not in Landscape mode. It goes part-way on the URL bar.
Any suggestions on what to try?

There is two ways of doing this. Depending on what kind of page you are displaying.
One thing to be aware of is that the mobile browser needs to have some content to scroll on. And by content to scroll on I mean that the content in the page needs to be higher then the window height. If not it's not going to scroll down at all.
Option1
Go for this if you know that your page content is more then the window height.
(function removeAddressBar(){
// Make sure it really scrolls down.
window.scrollTo(0, 10);
// Set a timeout to check that it has scrolled down.
setTimeout(function() {
if(window.scrollY == 0) {
removeAddressBar();
}else{
window.scrollTo(0, 1);
//launch();
}
}, 500);
})(this)
Option2
Go for this if you dont know if your content is more then the window height.
<div id='scroller' style='position:absolute;height:2000px;'></div>
(function removeAddressBar(){
window.scrollTo(0, 10);
setTimeout(function() {
if(window.scrollY == 0) {
removeAddressBar();
}else{
window.scrollTo(0, 1);
document.getElementById('scroller').style.height = window.innerHeight+'px';
//launch();
}
}, 500);
})(this)
This might look like a lot for such a simple thing. But I think this is the most reliable way so far.. I have tested this on iOS and Android in both orientations.

This is what worked for me:
window.screen.orientation.onchange = function() {
if (this.type.startsWith('landscape')) {
document.querySelector('#container').webkitRequestFullscreen();
} else {
document.webkitExitFullscreen();
}
};
Found that code snippet here:
https://mounirlamouri.github.io/sandbox/fullscreen-orientation.html
This works at least for Android Chrome Browsers.
It seems that that script would throw an error on IOS-Devices since they don't support the Fullscreen API. So the function should be wrapped in an if statement for checking if it's an IOS device:
var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;

Related

OrientationChange acts weird

I have a website which should show an image when the browser is in portrait mode, and hide it again when in landscape. I have tested this feature with chrome responsive mode and there it acts fine, but when trying to run the site on iphone or ipad the feature acts up. Code looks like this
let mql = window.matchMedia("(orientation: portrait)")
window.onorientationchange = rotate;
function rotate() {
if(mql.matches) {
document.querySelector("#rotation").classList.remove("hide");
document.querySelector("#game").classList.add("hide");
} else {
document.querySelector("#rotation").classList.add("hide");
document.querySelector("#game").classList.remove("hide");
}
}
The way it acts on iphone and ipad is that #rotation shows when in landscape and hides when in portrait, which is basically the total opposite of the code, as I read it.
Is anyone familiar with this issue, and anyone know of a fix for it?
thanks in advance
I think instead calling that function window.onorientationchange = rotate;
you should do following
let mql = window.matchMedia("(orientation: portrait)")
function rotate(event) {
if(event.matches) {
document.querySelector("#rotation").classList.remove("hide");
document.querySelector("#game").classList.add("hide");
} else {
document.querySelector("#rotation").classList.add("hide");
document.querySelector("#game").classList.remove("hide");
}
}
// this addListner is going to deprecate soon
mql.addListner(rotate);
// you can use below if you don't want to support <= iOS 13 browsers
// Ref: https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList
mql.addEventListner("change", rotate);

On iOS Safari, window.scrollTo doesn't work after orientation change

In short:
In iOS Safari, window.scrollTo method doesn't do anything if called from orientationchange event handler. It seems like a certain amount of time (500-1000ms) must pass before you can modify scroll position after orientation change.
Is there a workaround to change scroll position immediately and avoid the problem when user can see old scroll position for a moment after orientation change?
Detailed problem description:
I need to implement the following feature for mobile browsers:
When the user switches to landscape mode, he should see fullscreen video. When he switches back to portrait, he should be returned to exact same place where he left off.
The second part is the problem. Both iOS and Android will keep scroll position if you switch orientation back and forth, but only if you dont scroll the screen and dont make any adjustments to DOM. So if you just switch from portrait to landscape and back, everything works as expected. If you switch from portrait to landscape, adjust scroll position even by 1 pixel or make any changes to DOM, you will return to a different scroll position.
So I'm trying to pragmatically restore scroll position once the user returns to portrait orientation. Here's the simplified code I use:
var scrollPosition;
var savedScrollPosition;
window.addEventListener('scroll', function() {
scrollPosition = window.scrollY;
});
window.addEventListener('orientationchange', function(event) {
if (Math.abs(window.orientation) === 90) {
// This line will correctly save last scroll position for portrait orientation
savedScrollPosition = scrollPosition;
} else {
// This line will correctly try to restore previously saved scroll position
window.scrollTo(0, savedScrollPosition);
}
});
This works on android, but on iOS it doesn't. The problem is, window.scrollTo just doesn't seem to do anything until the certain time after orientation change has passed.
So if I change
window.scrollTo(0, savedScrollPosition);
to
setTimeout(function() {
window.scrollTo(0, savedScrollPosition);
}, 1000);
it works on iOS, but the user can see wrong portion of the page for a few moments, which leads to a poor user experience.
I was hoping that somebody knows a way to change scroll position on iOS immediately after orientationchage event.
Thank you.
In the end, I was forced to go with the following code:
var scrollPosition;
var savedScrollPosition;
window.addEventListener('scroll', function() {
scrollPosition = window.scrollY;
});
window.addEventListener('orientationchange', function(event) {
if (Math.abs(window.orientation) === 90) {
savedScrollPosition = scrollPosition;
} else {
if (isIOS()) {
var retryScroll = setInterval(function () {
if (window.scrollX === 0 && window.scrollY == savedScrollPosition) {
clearInterval(retryScroll);
} else {
window.scrollTo(0, savedScrollPosition);
}
}, 10 );
} else {
window.scrollTo(0, savedScrollPosition);
}
}
});
The user will see a small visual glitch, but it's still the best solution.

Horizontal One-Page Site: Mobile-Webkit Scrolling & Swiping Issues

Here is a basic demo of what I'm working with: http://jsfiddle.net/3N8wY/9/
Issue #1
If you view that link from a stock Android browser, or (more importantly) an iOS device, the website will not scroll. It does this odd fidgety/pulse thing and goes no where. It will sometimes scroll if you choose a link way on down the line, but it never ends up in the right spot.
I believe this has to do with the JS. When I tried it on my phone, I noticed it wasn't hashing the new value of the selected link.
JS
$(document).ready(function () {
$('.main-nav').on('click', function (e) {
e.preventDefault();
var toTarget = $(this).attr('href');
history.pushState(null, null, toTarget);
$(window).triggerHandler('hashchange');
});
});
$(window).on('hashchange', function () {
if(!window.location.hash) return;
var $target = $(window.location.hash);
console.log($target);
$('html, body').stop().animate({
scrollLeft: $target.offset().left,
scrollTop: $target.offset().top
}, 900, 'swing');
});
CREDIT FOR JS - Horizontal One-Page site won't go "backwards" to previous DIV
Issue #2
If you swipe a little left or right, it moves the page. I do not want that. Setting the overflow to hidden has not helped with swiping.
Ideally, if the user swiped enough right or left, it would "snap" the page in the desired direction, and then push the correct hash value. If they didn't swipe enough, it would snap back to the current page.
Having said that, I will be quite happy with it if it just doesn't move at all. I had envisioned that the user would use the menu to navigate, and only be able to scroll up and down.
Somewhat off-topic
Does anyone have a suggestion for a desktop browser that closely emulates the browser in an iOS device? I believe that webkit driving the stock Android browser is very similar, so I think I'd kill two birds here if I could get a hold of that for testing. On another project, I noticed that my desktop version of Safari seemed to deliver very different results than what I'd find on an iOS device (absolutely positioned elements behaved differently with respect to "top/margin-top" in each respective browser).
Thank you very much in advance for reading and contributing! I am extremely appreciative and grateful.
Issue #1
Turns out that I didn't have Modernizr installed correctly (hadn't included the no-js class in the html tag), which once rectified, solved the hashing issue I was running into on some stock Android browsers.
After that was fixed, I still ran into the odd scrolling behavior. Often, the page would scroll to the desired location, but then jump back. Upon further research, I came across this:
Jquery Animate ScrollLeft doesnt work on ipad.
That seemed to fix the undesired scrolling behavior for some of the poor performers, but not on iOS devices. This could have something to do with it, ScrollLeft and ScrollTop on Ipad using animate chain (jQuery), but I've figured out something else that works (will post below).
So far as I can tell, iOS devices (7+) automatically scroll to top BEFORE any scrollLeft animation. I don't have access to any physical devices, but I do have access to an iMac, where I was able to get ahold of the iOS Simulator and observed the unwanted scrolling behavior. I tried unlinking the two scrolling actions (left & top, as most posts will suggest you try), but that didn't make a difference.
It might have had something to do with what I was scrolling (ie the body or the html), I read that in a few posts, but messing with that rendered no useful results.
As I was testing, I realized that by only scrolling left, my script finally functioned "properly".
The interesting bit is that I noticed that the browser would scroll to top AUTOMATICALLY BEFORE horizontally scrolling to my target. So, if they update their code to make scrollLeft function properly, I'll have to go back and add a scrollTop function. For the the time being...
Not exactly a "fix" (the browser behaving inappropriately working to my "benefit", worrisome), but I'll take it.
Issue #2
Just to clarify, it was especially tricky to tackle this one because the page NEEDS to be able to scroll left and right (what with the horizontal layout and all), but only when I want it to.
As far as attempting to disable swiping, I really came up short. The closest I got there was with a plugin called touchSwipe; however, that broke too much (CSS-layout in some mobile browsers), and I couldn't seem to re-enable the tapping of non-link('a') assets.
What I ended up doing is creating a function that would monitor the horizontal scroll position of the window, and reposition the window if it changed. Seems a little buggy in some browsers, but it seems like I'm close to making 'everybody' happy.
EDIT: Changed the function to the much more compliant window.scrollTo(), just had to fetch positions before I fired it. Haven't tested a browser that didn't like it (so far, fingers crossed).
Side note
Lastly, when I got to RWD testing...
I was spoiled with the 'Resize Window' plugin for Chrome, and didn't realize the lackluster availability of working plugins for other browsers. So, I created a testbed full of 20 or so iframes of differing proportions, set to match the most popular device dimensions.
When I got down to mobile device dimensions, I realized that the browser's scrollbar was skewing my proportions. I'd looked into custom scrollbars before, so I delved back into it to attempt to equalize the variable all across the field.
After trying many different plugins, 'nicescroll' was the only one I could get working properly (http://nicescroll.areaaperta.com/). If you're going to use it, be sure to run a mobile test (http://www.detectmobilebrowsers.com/), and only run it on non-mobile devices (admittedly, this script seems to fail at picking up some mobile browsers, but it's better than nothing). All the mobile browsers I tested already had a similar scrollbar in place (by default), so it's completely unnecessary (plus it breaks some mobile browsers).
Working JS
$(document).ready(function() {
var loadedTarget = $(window.location.hash);
function unbindWindow() { $(window).unbind('scroll'); }
function repositionWin() {
unbindWindow();
var targetPosLeft = loadedTarget.offset().left;
$(window).on('scroll', function(e) {
var alteredPosLeft = $(window).scrollLeft();
var alteredPosTop = $(window).scrollTop();
if (alteredPosLeft != targetPosLeft) {
window.scrollTo(targetPosLeft, alteredPosTop),
unbindWindow(), // MAY BE UNNECESSARY, IOS SCARED ME INTO IT, SAME AS BELOW
repositionWin();
}
});
}
function browserResult() {
if (jQuery.browser.mobile === true) {
$('body').css({"overflow-x":"hidden","overflow-y":"scroll"});
repositionWin();
}
else {
setTimeout ((function(){
$("html").niceScroll({
cursorcolor: '#231f20',
cursoropacitymax: '0.5',
scrollspeed: '100',
mousescrollstep: '50'
});
}), 300);
setTimeout (repositionWin, 300);
}
}
browserResult();
$('.main-nav-link').click(function(e) {
e.preventDefault();
var toTarget = $(this).attr('href');
history.pushState(null, null, toTarget);
// CODE SPECIFIC TO PROJECT (NAMELY FLEXSLIDER PAUSE/PLAY STUFF) OMITTED
$(window).triggerHandler('hashchange');
});
});
$(window).on('hashchange', function () {
if(!window.location.hash) return;
var target = $(window.location.hash);
var targetHash = window.location.hash;
var iOS = ( navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false );
var currentPosition = $(window).scrollLeft();
var targetPosLeft = target.offset().left;
var targetPosTop = target.offset().top;
function unbindWindow() { $(window).unbind('scroll'); }
function repositionWin() {
unbindWindow();
$(window).on('scroll', function() {
var alteredPosLeft = $(window).scrollLeft();
var alteredPosTop = $(window).scrollTop();
if (alteredPosLeft != targetPosLeft) {
window.scrollTo(targetPosLeft, alteredPosTop),
unbindWindow(),
repositionWin();
}
});
}
function fadePages() {
if (targetPosLeft == currentPosition) {
}
else {
function fadePageOut() {
$('.page-container').stop(true,false).animate({
opacity: "0.25",
transition: "opacity 0.1s 0.0s ease"
});
}
function fadePageIn() {
$('.page-container').stop(true,false).animate({
opacity: "1.0",
transition: "opacity 0.3s 0.0s ease"
});
}
fadePageOut();
setTimeout (fadePageIn, 900);
}
}
function pageChange() {
if (jQuery.browser.mobile === true) {
if (iOS === true) {
unbindWindow();
$('html,body').stop(true,false).animate({
scrollLeft: targetPosLeft}, 1400);
setTimeout (repositionWin, 1500);
}
else {
unbindWindow();
$('html,body').stop(true,false).animate({
scrollLeft: targetPosLeft}, 1200, function() {
$(this).stop(true,false).animate({
scrollTop: targetPosTop
}, 200, repositionWin);
});
}
}
else {
fadePages();
unbindWindow();
$('html,body').stop(true,false).delay(100).animate({
scrollLeft: targetPosLeft,
scrollTop: targetPosTop
}, 1300, repositionWin);
}
}
// WAITING FOR OTHER ANIMATIONS TO COMPLETE SO THAT MOBILE DEVICES AREN'T TOO OVERLOADED
if ($('#mini-site-menu-button-container').is(':visible') === true && $('#main-menu-wrapper').hasClass('show-main-menu') === true) {
setTimeout (pageChange, 300)
}
if ($('.footer-container').is(':visible') === true) {
setTimeout (pageChange, 500)
}
if ($('.form-instructions-wrapper').hasClass('expand-form-instruct') === true) {
setTimeout (pageChange, 500)
}
if ($('.quick-quote-container').hasClass('toggle-open') === true) {
setTimeout (pageChange, 500)
}
if ($('#mini-site-menu-button-container').is(':visible') === false && $('.footer-container').is(':visible') === false && $('.form-instructions-wrapper').hasClass('expand-form-instruct') === false && $('.quick-quote-container').hasClass('toggle-open') === false) {
pageChange();
}
if ($('#main-menu-wrapper').hasClass('show-main-menu') === false && $('.footer-container').is(':visible') === false && $('.form-instructions-wrapper').hasClass('expand-form-instruct') === false && $('.quick-quote-container').hasClass('toggle-open') === false) {
pageChange();
}
});
Cheers.
I'll update as time goes on, or if I find a better solution to either of the issues. I had zero programming experience actually writing any of my own code (and this isn't all "mine") before this (changing selectors was pretty much the extent of my "skills"), so please excuse any glaring mistakes.

Cross-platform method for removing the address bar in a mobile web app

I am working on a mobile web app and am trying to remove the address bar. Its easy enough, unless the <body>'s natural height is not tall enough to allow for scrolling. Try as I might I cannot find a reliable iphone/android, cross device method of insuring that the <body> is tall enough to allow the address bar to disappear. Many of the methods I've seen rely on screen.height which makes the page TALLER than it needs to be. It should be EXACTLY tall enough to allow the address bar to go away and no taller!
Does anyone have a script that handles this perfectly? I all I need to to determine the height of the page minus the address bar for iphone and android.
I've tried:
screen.height //too tall
window.innerHeight //too short
document.documentElement.clientHeight //too short
document.body.clientHeight //almost but too short
JQUERY allowed.
This site also has a few other suggestions, but this no-nonsense, no-worry one is available in a github:gist and answers your question (pasted here for convenience):
function hideAddressBar()
{
if(!window.location.hash)
{
if(document.height < window.outerHeight)
{
document.body.style.height = (window.outerHeight + 50) + 'px';
}
setTimeout( function(){ window.scrollTo(0, 1); }, 50 );
}
}
window.addEventListener("load", function(){ if(!window.pageYOffset){ hideAddressBar(); } } );
window.addEventListener("orientationchange", hideAddressBar );
As far as I can tell, the combination of extra height added to the page (which caused problems for you) and the scrollTo() statement make the address bar disappear.
From the same site the 'simplest' solution to hiding the address bar is using the scrollTo() method:
window.addEventListener("load", function() { window.scrollTo(0, 1); });
This will hide the address bar until the user scrolls.
This site places the same method inside a timeout function (the justification is not explained, but it claims the code doesn't work well without it):
// When ready...
window.addEventListener("load",function() {
// Set a timeout...
setTimeout(function(){
// Hide the address bar!
window.scrollTo(0, 1);
}, 0);
});
I think the way it works is the address bar is hidden when the page wouldn't fit. So you want a page exactly the height of the window including the address bar, i.e. window.outerHeight, no?

How to stop Androids' Browser from scrolling back

I'm working on a jquery-mobile app and have run into a bit of an issue; I'd like to use jquery's animate() for a gentle scroll "back to top" of my app's pages.
The following code snippet works great in all but one of my test browsers. Chrome & Firefox on desktop, Safari on iPhone, and Firefox Beta on Android are all good. The default Android Browser (webkit-mobile IIRC) scrolls back to the anchor when the animation is complete.
$("a[href='#top']").live('click', function() {
$("body").animate({ scrollTop: 0 }, "slow", function() {
// anim complete
setTimeout(function() { // not needed, attempt to brute-force
window.scrollTo(0,0);
alert('foo'); // <- Android scrolls back to anchor after showing alert
}, 50);
});
});
Can anyone suggest a) what's causing the Android Browser to scroll back and/or b) suggest a workaround? If it makes a difference the device I'm testing with at the moment is running Android 2.3.2.
Reading through the documentation on an unrelated issue, I stumbled upon the $.mobile.silentScroll() method - designed apparently for just this situation.
Here's my initial brain-dead workaround:
function scrollToTop() {
var scrollPos = $(document).scrollTop();
scrollPos -= 60;
if (scrollPos < 1) { scrollPos = 1; }
$.mobile.silentScroll(scrollPos);
if (scrollPos > 1) { setTimeout(scrollToTop, 60); }
}
$("a[href='#top']").live('vclick', function() {
scrollToTop();
return false;
});
Still curious as to why Android Browser wants to scroll back to the anchor in the original form.

Categories

Resources