I use preventDefault() on touchstart on the document to prevent scrolling on a page. Unfortunately this prevents too much. The user can no longer give focus to an input (and open the soft keyboard). Using jQuery focus(), I can give the focus to the input on a touchstart. This opens the soft keyboard on iOS (most of the time), but never on Android.
Background:
I have a webpage that I want to make as much like a mobile app as possible. I'm only really concerned with Android and iOS, but any form factor. I start by making the content in the page exactly the same size as the screen size. This is nice until the user puts their finger on the page. I need to prevent user scrolling. The following code accomplishes this, but in slightly different ways on the two operating systems.
$(document).on('touchstart', function(e) {
e.preventDefault();
});
On iOS, this prevents the elastic scrolling: where a user can reveal a texture behind the webpage by attempting to scroll off the page. The feature is nice for a regular webpage, but in my case it detracts from the UX.
On Android, prevents the revelation of a handy hack that I use to hide the address bar. Android browsers start with the address bar visible, but as the user scrolls down the page, it disappears. To programmatically force the browser hide the address bar, simply add this line of code to your function called at load.
$('html, body').scrollTop(1);
This is a hacky (but also the only) way to tell the android browser that we have scrolled, and the address bar is no longer necessary.
Without the preventDefault on the document, the Android browser will allow scrolling and the address bar can be revealed.
So, both OS's have a good reason to have this preventDefault() called on every touchstart on the document, but it prevents too much. Tapping on an input field does nothing. Using a call to jQuery focus() can help, but only opens the soft keyboard on iOS, not Android.
$('input').on('touchstart', function() {
$(this).focus();
});
How can I prevent the page from scrolling, but use the browser native functionality for giving focus to input fields?
Note:
This code
$(document).on('touchstart', function(e) {
if (e.target.nodeName !== 'INPUT') {
e.preventDefault();
}
});
is flawed because the user can still scroll the page as long as the initial touch originates from within the input field.
I actually solved this problem on another project, forgot about it, and remembered it most of the way through typing this up.
They key is to just do it on touchmove.
$(document).on('touchmove', function(e) {
e.preventDefault();
});
However, preventDefault on touchstart does all kinds of nice things like preventing the image save menu on a gesture enabled slideshow. My projects also include this.
$(document).on('touchstart', function(e) {
if (e.target.nodeName !== 'INPUT') {
e.preventDefault();
}
});
If anyone has some suggestions on additional content or how to reformat this so that it can reach a greater audience that would be great. I haven't ever seen the content I have here all in one place, so I felt that it needed to be on SO.
Combine the two!
// prevent scrolling from outside of input field
$(document).on('touchstart', function(e) {
if (e.target.nodeName !== 'INPUT') {
e.preventDefault();
}
});
// prevent scrolling from within input field
$(document).on('touchmove', function(e) {
if (e.target.nodeName == 'INPUT') {
e.preventDefault();
}
});
This probably isn't perfect either, and I am especially worried that the first function will prevent following links, but I'll leave it to others to do extensive tests.
The simple answer to your question is don't use "preventDefault" instead use pointer-events css property to disable the scrolling on the element that scrolls.
CSS for your inputs:
input {
pointer-events: auto !important;
}
touchstart event listener:
document.body.addEventListener('touchstart', function(e) {
if (e.target.nodeName === 'INPUT') {
this.style.pointerEvents = 'none';
}
});
You will need to reset the pointer-events when you blur the input.
document.body.pointerEvents = 'auto';
+1 Good Question
Related
I need to show my pop-up when the mouse leaves the <body>, this identifies an exit intention.
So when my clients are typing their emails, the popup just appears at the exact moment their pointer is over the suggestion and it should not have happened. But it happens because this part is not in the DOM, so it triggers the mouse leave
however, this event is triggered when the mouse is over a native input suggestion on browsers (I tested on Firefox and Chrome).
So, any ideas how can I skip this fake trigger?
document.body.onmouseleave = function(e) {
console.log("mouse leave was trigged")
}
Take a look what is happen:
I've encountered the same issue, solved it by looking at what exactly triggered the mouseleave event. So if it was not an input field from your form, you could proceed and show your popup
$('body').on('mouseleave', function (e) {
if ('INPUT' !== e.target.nodeName) {
// do your stuff
}
});
My web app has keyboard shortcuts that involve holding the space bar. The problem is that the mouse cursor disappears when the space bar is held. I think what's happening is that the browser is trying to scroll down (even though in my case there's never anything to scroll down to). If the user moves the mouse cursor while holding the space bar, the cursor flickers into view, only to disappear again when the mouse has stopped moving. Once the user releases the space bar, the mouse cursor stay hidden, until the mouse is moved again, after which the cursor stays visible. This happens in Chrome, Safari, Opera (webkit/blink).
Among many things, I've tried the canonical solution of preventDefault() on the event, which doesn't work, regardless of where I listen. Clearly, this is possible, because I've used apps before that employ the space bar to do something other than scroll down.
var html = document.documentElement;
var body = document.getElementsByTagName('body')[0];
document.addEventListener("keydown", function(e) {
console.log("document keydown");
e.preventDefault();
e.stopPropagation();
});
window.addEventListener("keydown", function(e) {
console.log("window keydown");
e.preventDefault();
e.stopPropagation();
});
html.addEventListener("keydown", function(e) {
console.log("html keydown");
e.preventDefault();
e.stopPropagation();
});
body.addEventListener("keydown", function(e) {
console.log("body keydown");
e.preventDefault();
e.stopPropagation();
});
document.addEventListener("keypress", function(e) {
console.log("document keypress");
e.preventDefault();
e.stopPropagation();
});
window.addEventListener("keypress", function(e) {
console.log("window keypress");
e.preventDefault();
e.stopPropagation();
});
html.addEventListener("keypress", function(e) {
console.log("html keypress");
e.preventDefault();
e.stopPropagation();
});
body.addEventListener("keypress", function(e) {
console.log("body keypress");
e.preventDefault();
e.stopPropagation();
});
Note: My app is always exactly 100% of the viewport. There is never any reason to scroll, which is why I am comfortable with the idea of overriding the convention.
Any help very appreciated.
TL/DR: apply overflow: hidden style on document.body.
I just found this unanswered (!!) question here after same problem, but in 5 min found my solution.
Several years of no answer so I'll explain my own situation too since it must be a rare context.
My scenario: Developing full-page graphic app using PIXI, along with overlaid HTML DOM elements. Using Safari on MacBook Pro.
Interest: press spacebar to interact with PIXI content
Approach: use a state tracking variable using keydown and keyup listeners. Press spacebar, in keydown update the cursor style when the event target is the document.body. Likewise revert cursor style in keyup.
Problem: the browser wants to scroll. Even when using event.preventDefault.
I never use spacebar to scroll a page, so I was entirely blind to the existing browser behaviour.
Discovery: Experimenting on other pages, including here on the SO question, I found the cursor ceases to be hidden on spacebar press when at bottom of the page. So I know the browser is considering the body length...
Solution: apply overflow: hidden style on document.body.
Now I know for various applications this may not suffice, but it DOES SOLVE THIS PROBLEM for me. The browser knows there is zero overflow processing on the body, so spacebar is inert for scrolling.
After applying this, overflow elsewhere still works: other divs of the web app can still scroll, with assigned dimensions.
I need to disable the default iPAD scrolling (via capturing touchmove on the body) but still allow a list on my page to scroll.
I tried:
$('body').on('touchmove', function(e) { e.preventDefault(); });
$('itemList').on('touchmove', function(e) { alert('hi'); e.stopPropagation(); });
But it seems that itemList's touchmove is not being called at all. on the iPAD nothing gets scrolled.
see http://jsfiddle.net/e8dcJ
Any ideas how to solve this ?
Thanks!
maybe don't apply the event to the body, which covers everything. Instead, apply the event to a the various elements you want to prevent scrolling. Alternately, wrap everything in a DIV except the list and then set the position to fixed and add the event.
I have some custom web components in my mobile web app, whereas I need to manually fire 'focus' events on a field, to simulate the 'NEXT' functionality in the Android soft keyboard feature. ( using Galaxy S3 native browser ).
However, when I manually fire a focus event on a 'select' field, the native soft keyboard does not show. I have to subsequently click on the field to get it to show. (In IOS, of course, it works just fine).
So I'm wondering, if a 'focus' event doesn't trigger the soft keyboard to open, what JS event will ???
I am not using phonegap so I'm hoping there's a way without it.
Thanks for any help!!!
Here's a link from StackOverflow:
Showing Android's soft keyboard when a field is .focus()'d using javascript
Just focussing without an event doesnt seem to work. - you DO need a
click event triggering this.
$(document).ready(function() {
$('#field').click(function(e){
$(this).focus();
});
$('#button').click(function(e) {
$('#field').trigger('click');
});
});
You can do this by calling focus() then click() on the input. No need for jquery. Beware of endless loops if your script is triggered by an onclick() on a containing element. Make sure as well that this script is triggered by some user interaction. It won't work from document.onload(), or from a setTimeout(). It's also fragile with things like simultaneous style changes on the elements. The script below is working for me on Chrome for android 58 and Safari mobile 602.1.
var target = document.getElementsByTagName("input")[0];
if (event.target != target) {
target.focus();
target.click();
}
Vanilla JS solution:
let button = document.getElementById("b");
let input = document.getElementById("i");
// Keyboard opens when focusing the input from a click listener
button.addEventListener("click", () => {
input.focus();
});
// Input field gets focus but keyboard doesn't open.
setTimeout(() => {
input.focus();
}, 1000);
I'm looking for an event which will fire whenever the user switches away from the page to another tab, and another event which fires when the user switches back to the tab again.
window.onblur and window.onfocus don't seem to work correctly across all browsers
Is there a proxy I could look at in order to synthesize this event?
You can also try and use VisibilityAPI.
document.addEventListener("visibilitychange", function() {
if (document.hidden){
console.log("Browser tab is hidden")
} else {
console.log("Browser tab is visible")
}
});
See also here on Stackoverflow (possible duplicate)
You might try using a framework, such as MooTools or jQuery which provide cross-browser support. They should be able to detect with more reliability the blur and focus events for the browser window.
I personally have used jQuery with much success:
$(window).blur(function(e) {
// Do Blur Actions Here
});
$(window).focus(function(e) {
// Do Focus Actions Here
});