Hide address bar not working - bulletproof approach needed - javascript

At the moment I am writing some kind of web app and I want to hide the address bar on iOS devices and preferably also on Android devices.
Normally I do this with
window.addEventListener( 'load', function () {
setTimeout( function () {
window.scrollTo( 0, 1 );
}, 0 );
});
but this won't work now because the page hasn't enough content to scroll.
Now I know this is a common problem and I know that there are multiple solutions, but I would prefer a small, bulletproof solution.
Actually I was quite happy when I found this question: http://stackoverflow.com/questions/9678194/cross-platform-method-for-removing-the-address-bar-in-a-mobile-web-app
where this code was posted:
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 );
Unfortunately, this doesn't work for me. I see that something happens because some elements that have padding-top set in percentages move down, but the address bar stays.
Of course I also did a Google search and tried many snippets I found. Some did nothing, some just moved the elements with padding-top down a bit.
The only working code I found is this:
var page = document.getElementById('page'),
ua = navigator.userAgent,
iphone = ~ua.indexOf('iPhone') || ~ua.indexOf('iPod'),
ipad = ~ua.indexOf('iPad'),
ios = iphone || ipad,
// Detect if this is running as a fullscreen app from the homescreen
fullscreen = window.navigator.standalone,
android = ~ua.indexOf('Android'),
lastWidth = 0;
if (android) {
// Android's browser adds the scroll position to the innerHeight, just to
// make this really difficult. Thus, once we are scrolled, the
// page height value needs to be corrected in case the page is loaded
// when already scrolled down. The pageYOffset is of no use, since it always
// returns 0 while the address bar is displayed.
window.onscroll = function() {
page.style.height = window.innerHeight + 'px'
}
}
var setupScroll = window.onload = function() {
// Start out by adding the height of the location bar to the width, so that
// we can scroll past it
if (ios) {
// iOS reliably returns the innerWindow size for documentElement.clientHeight
// but window.innerHeight is sometimes the wrong value after rotating
// the orientation
var height = document.documentElement.clientHeight;
// Only add extra padding to the height on iphone / ipod, since the ipad
// browser doesn't scroll off the location bar.
if (iphone && !fullscreen) height += 60;
page.style.height = height + 'px';
} else if (android) {
// The stock Android browser has a location bar height of 56 pixels, but
// this very likely could be broken in other Android browsers.
page.style.height = (window.innerHeight + 56) + 'px'
}
// Scroll after a timeout, since iOS will scroll to the top of the page
// after it fires the onload event
setTimeout(scrollTo, 0, 0, 1);
};
(window.onresize = function() {
var pageWidth = page.offsetWidth;
// Android doesn't support orientation change, so check for when the width
// changes to figure out when the orientation changes
if (lastWidth == pageWidth) return;
lastWidth = pageWidth;
setupScroll();
})();
Source
But I am not really happy with this solution as I am not a friend of UA sniffing.
Do you have any suggestions what I could try to make it work without UA sniffing? Can it be my HTML that causes problems with some scripts I posted?

Don't know if it's bulletproof, but it works on a bunch of devices. If you find caveat, let me know.
if (((/iphone/gi).test(navigator.userAgent) || (/ipod/gi).test(navigator.userAgent)) &&
(!("standalone" in window.navigator) && !window.navigator.standalone)) {
offset = 60;
$('body').css('min-height', (window.innerHeight + offset) + 'px');
setTimeout( function(){ window.scrollTo(0, 1); }, 1 );
}
if ((/android/gi).test(navigator.userAgent)) {
offset = 56;
$('html').css('min-height', (window.innerHeight + offset) + 'px');
setTimeout( function(){ window.scrollTo(0, 1); }, 0 );
}

Related

How does this page detect movement of a desktop browser window?

In messing around with some DeviceOrientation stuff, I came across this page.
When you shake the browser, the site reacts! What API is being used here where the browser movement is detected? I notice it works in the latest versions of Safari, Firefox and Chrome.
I don't see any mention of this in the DeviceOrientation docs, nor on three.js...
They use the window.screenX/screenY properties to get browser window position and window.innerWidth/innerHeight to get window's size.
The Window.screenX read-only property returns the horizontal distance, in CSS pixels, of the left border of the user's browser viewport to the left side of the screen.
The below function is used in that code:
function getBrowserDimensions() {
var changed = false;
if (stage[0] != window.screenX) {
delta[0] = (window.screenX - stage[0]) * 50;
stage[0] = window.screenX;
changed = true;
}
if (stage[1] != window.screenY) {
delta[1] = (window.screenY - stage[1]) * 50;
stage[1] = window.screenY;
changed = true;
}
if (stage[2] != window.innerWidth) {
stage[2] = window.innerWidth;
changed = true;
}
if (stage[3] != window.innerHeight) {
stage[3] = window.innerHeight;
changed = true;
}
return changed;
}
use screen.orientation property.
reference

ScrollMagic and GSAP on mobile only

You can see from my codepen that I have a logo on my website that fades out as you scroll down the page, which is triggered after a certain trigger has been fired. This is working the way I want it, except I only want this to fire on mobile browsers and mobile screen sizes.
I'm using scrollmagic.js with this also.
Does anyone know how to set this up so the effect will only work on mobile and screen sizes < 768px.
I'm fairly new to JS and so would appreciate baby steps.
thanks
// When the DOM is ready
$(window).on('load', function() {
// Init ScrollMagic Controller
var scrollMagicController = new ScrollMagic();
// Create Animation for 0.5s
var tween = TweenMax.to('#animation', 0.5, {
opacity: 0
});
// Create the Scene and trigger when visible
var scene = new ScrollScene({
triggerElement: '.scene',
offset: 150 /* offset the trigger 150px below #scene's top */
})
.setTween(tween)
.addTo(scrollMagicController);
// Add debug indicators fixed on right side
scene.addIndicators();
});
Codepen of what I currently have
I would wrap the scrollMagic block on an if statement that checks if it is a touch device or if it has a minimum with, depending on which behaviour you are interested in.
With Modernzr:
var agent = navigator.userAgent.toLowerCase();
var onlyTaps = Modernizr.touch ||
(agent.match(/(iphone|ipod|ipad)/) ||
agent.match(/(android)/) ||
agent.match(/(iemobile)/) ||
agent.match(/iphone/i) ||
agent.match(/ipad/i) ||
agent.match(/ipod/i) ||
agent.match(/blackberry/i) ||
agent.match(/bada/i));
if (onlyTaps) {
//magicScroll block here
} else {
//something else here
}
Now, if you are only interested on the device width then you can use screen.width:
if (screen.width < 480) {
//magicScroll block here
} else {
//something else here
}
The only caveat is that screen.width might return real pixels or not on some high density devices. It works as expected on iPhones and Macbook Pro w/retina displays.

How to detect iOS7 Safari height change on scrolling - JavaScript

In Safari on iPhone iOS7 a scroll down will show the menus at the top and bottom and a scroll up will hide them - effectively changing the height of the screen.
How do I listen for this slight change in height?
I have an element that changes height depending on the height of the screen, but in iOS7 it's not really behaving well.
To listen to window resize events we can use window.addEventListener("resize", myFunction);
or using jQuery $(window).resize(myFunction());
I had a related problem but reversed -- a small window resize that happens on-scroll on iOS devices was unnecessarily triggering my on-resize logic.
One workaround can be just ignoring a small vertical resize (approx 40px should be ok)
An example solution (using jQuery)
const ignoreVerticalResizeTreshold= 40;
let vpHeight= 0;
let vpWidth= 0;
$(window).resize(function() {
// Do stuff (on any window resize event)
// return if no horizontal resize happened and vertical resize is below the set treshold
if ($(window).innerWidth() === vpWidth && (($(window).innerHeight() >= (vpHeight - ignoreVerticalResizeTreshold / 2)) || ($(window).innerHeight() <= (vpHeight + ignoreVerticalResizeTreshold / 2)))) {
return;
}
// Do more stuff
vpHeight = $(window).innerHeight();
vpWidth = $(window).innerWidth();
});
In a recent React project I set a CSS var to the window.innerHeight on resize.
const setAppHeight = (): void => {
const doc = document.documentElement;
doc.style.setProperty('--app-height', `${window.innerHeight}px`);
};
const debouncedEventHandler = useMemo(
() => debounce(setAppHeight, 300),
[],
);
useEffect(() => {
window.addEventListener('resize', debouncedEventHandler);
setAppHeight();
return () => {
debouncedEventHandler.cancel();
};
}, []);
That var was set normally in CSS and used whenever something needed
:root {
--app-height: 100%;
}
.whatever {
height: var(--app-height);
}

Native Android browser not showing div at jquery.mobile

On the Chrome browser, I get everything working, but, if I want to make it work at the native Android Browser, I can't see the div I want to show. Instead, it shows me the first span with the class leftscroller.
How could this be? I tried Android 4.1.2 and 4.1.3 browsers.
This is the JS code:
$('.navigation-block').on('click', function(){
$(this).parents('#navigation.small').toggleClass('open');
});
/* Scrollable */
var showScrollIndicators = function() {
var subnav = $('#navigation.small .subnav')
if (subnav.length > 0) {
var scrollLeft = subnav.scrollLeft();
var viewportWidth = subnav.innerWidth();
var scrollWidth = subnav[0].scrollWidth;
var leftScroller = $('#navigation.small').find('.leftscroller'),
rightScroller = $('#navigation.small').find('.rightscroller');
leftScroller.addClass('enabled');
rightScroller.addClass('enabled');
if (scrollLeft === 0) {
// we've reached the far left part of the scroll area
leftScroller.removeClass('enabled');
}
if (scrollWidth - scrollLeft <= viewportWidth) {
// we've reached the far right part
rightScroller.removeClass('enabled');
}
}
};
/* Add scroll indicators */
$('#navigation.small .ph_subnav').append(
'<span class="leftscroller">You can scroll to the left</span>' +
'<span class="rightscroller">You can scroll to the right</span>'
);
showScrollIndicators();
$('#navigation.small .subnav').scroll(function() {
showScrollIndicators();
});
What am I doing wrong? So the whole area which falls beneath /Scrollable/ is not shown.

How to get and set the current web page scroll position?

How can I get and set the current web page scroll position?
I have a long form which needs to be refreshed based on user actions/input. When this happens, the page resets to the very top, which is annoying to the users, because they have to scroll back down to the point they were at.
If I could capture the current scroll position (in a hidden input) before the page reloads, I could then set it back after it reloads.
The currently accepted answer is incorrect - document.documentElement.scrollTop always returns 0 on Chrome. This is because WebKit uses body for keeping track of scrolling, whereas Firefox and IE use html.
To get the current position, you want:
document.documentElement.scrollTop || document.body.scrollTop
You can set the current position to 1000px down the page like so:
document.documentElement.scrollTop = document.body.scrollTop = 1000;
Or, using jQuery (animate it while you're at it!):
$("html, body").animate({ scrollTop: "1000px" });
You're looking for the document.documentElement.scrollTop property.
Update 2021: browsers inconsistencies with scrollTop seem to have disappeared.
There are some inconsistencies in how browsers expose the current window scrolling coordinates. Google Chrome on Mac and iOS seems to always return 0 when using document.documentElement.scrollTop or jQuery's $(window).scrollTop().
However, it works consistently with:
// horizontal scrolling amount
window.pageXOffset
// vertical scrolling amount
window.pageYOffset
I went with the HTML5 local storage solution... All my links call a function which sets this before changing window.location:
localStorage.topper = document.body.scrollTop;
and each page has this in the body's onLoad:
if(localStorage.topper > 0){
window.scrollTo(0,localStorage.topper);
}
this will give you the px value of scroll from top
document.documentElement.scrollTop
Nowadays it seems like the get is working with: window.scrollX and window.scrollY. This could be an alternative way to solve it.
var stop = true;
addEventListener('drag', (event) => {
if (event.clientY < 150) {
stop = false;
scroll(-1)
}
if (event.clientY > ($(window).height() - 150)) {
stop = false;
scroll(1)
}
if (document.body.getBoundingClientRect().y === 0){
stop = true;
}
if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
stop = true;
}
});
addEventListener('dragend', (event) => {
stop = true;
});
var scroll = function (step) {
var scrollY = $(window).scrollTop();
$(window).scrollTop(scrollY + step);
if (!stop) {
setTimeout(function () { scroll(step) }, 20);
}
}
Now you can also use window.scrollTo({ top: 0, behavior: 'smooth' }); instead of using that jQuery solution above for the animation. Here is the documentation: https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo

Categories

Resources