I am trying to detect opera mini so that I can put a workaround for my position:fixed drawer navigation. I'm using the following bit of code for the browser detection (taken from dev.Opera) :
var isOperaMini = Object.prototype.toString.call(window.operamini) === '[object OperaMini]';
(function() {
if(navigator.userAgent.indexOf('Opera Mini') > -1){
$('HTML').addClass('opera');
console.log('opera')
}else{
document.getElementsByTagName('body').className+=' no-opera';
console.log('nuh-uh')
}
})();
but it is not working. the user agent become true for mozilla also. How can I detect the browser so that I can put in the hack?
** The hack is just to use position:absolute, I'll lose the stickiness, but without the hack my site is unusable.
*** I know why mozilla is true - according to this article, user agent is a mess!
Related
Please check this CodePen. The problem is described there. There is also a demo. I've tested it on Mac and Windows.
There is the same behavior in Chrome (on Mac and Windows).
Meanwhile, other browsers (even Safari and Opera which are on WebKit too) do not jump to the nearest snap point instantly.
It is a bug?
If so, what is the correct place where I can report it? Or what is the correct place (WebKit related) where I can ask about it?
// Snippet of code required by Stack Overflow to post a question
slider.addEventListener("scroll", _.debounce((e) => {
const currentHeight = parseFloat(e.target.style["height"]);
e.target.style["height"] = currentHeight + (flag ? 5 : -5) + "px";
flag = !flag;
}, 50));
"Chrome introduced auto-snap after layout changes in M81." (from Scroll snapping after layout changes)
Issue 1181843: Scroll-snap jumps to the nearest snap position on repaint in Chrome
This behavior is intentional in Chrome, unfortunately.
I am facing an issue. I am trying to detect if an OS x user has "natural scroll direction" enabled when using chrome or FF. Currently, I am able to detect it if the user is on Safari using the following code.
$("html, body").bind({'mousewheel DOMMouseScroll onmousewheel touchmove scroll': function(e, delta) {
if(Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0) {
if(e.originalEvent.webkitDirectionInvertedFromDevice) {
this.scrollTop += (delta);
e.preventDefault();
}
}}});
This stackoverflow page helped me with the above solution for safari only. Javascript: detect OS X "natural scroll" settings
Is there a possibility to detect it using chrome & FF. The reason I need it is because I want to force the user to scroll in "Inverse scroll direction", in other words when the user scroll downwards, I need the page to go do down.
Help is much appreciated! :)
I'm showing a notification bar on my website, and frankly, it doesn't work well when its on a mobile device. I'd like to show the bar ONLY for desktop users.
What is the easiest way to determine if a user is on desktop or on mobile?
A user agent check is the "easiest", though you could easily employ CSS3 media queries
Here is an example that checks iphone, android and blackberry; you could easily add other mobile browsers.
var is_mobile = !!navigator.userAgent.match(/iphone|android|blackberry/ig) || false;
Check this http://detectmobilebrowsers.com/
Work for Javascript, jQuery etc.
I find that it's best to use feature detection. Use Modernizr to detect if it's a touch device. You can do things like:
var mousedown = 'mousedown';
if (Modernizr.touch) {
mousedown = 'touchstart';
}
$('.foo').on(mousedown, handleMouseDown);
And then use CSS Media Queries for handling screen width (and it's also easy to detect screen width with javascript). That way you can correctly handle touch devices with large screens, or non-touch devices with small screens.
If you use modernizr. a "no-touch" class will be added to the element. You could hide the bar by default and add a css rule to show the bar if the "no-touch" class exists. Example:
default:
.bar{display:none;}
desktop:
.no-touch .bar{display:block;}
If the user is on a mobile device this javascript 'if' will return true.
if (navigator.userAgent.indexOf('Mobile') !== -1) { ...
See also: https://deviceatlas.com/blog/list-of-user-agent-strings
The easiest way to differentiate between touch and non-touch devices is using media queries.
1) CSS to target Mobile/Touch Devices can be written using media query,
#media (hover: none), (pointer: coarse) {}
2) CSS to target Desktop/Non-Touch Devices (only) can be written using media query,
#media not all and (pointer: coarse) {}
On Few latest mobile devices (Eg: IOS 10+, one plus etc.,.) hover is detected hence we use, the (2) to identify non-touch devices.
const is_mobile = navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/BlackBerry/i);
if (is_mobile != null){
popup.modal('show');
}
If you are reading this post 2021, there is an even easier way to find this out.
let isMobile = window.navigator.userAgentData.mobile;
console.log(isMobile);
The above method simply returns a boolean value.
I have a surface web app that uses touch panning (container divs have "overflow: auto" style) and I'm using the built-in paging scroll styles:
-ms-scroll-snap-points-x: snapInterval(0px, 1366px);
-ms-scroll-snap-type: mandatory;
My app has a 300% width child container resulting in 3 pages that snap on page boundaries.
This works great for high-performance paging scrolling, except when the user is on the first page and they swipe to the right, which activates the browser's built-in back gesture, exiting my web app and going into the user's IE10 history.
I'm able to disable the back gesture using:
-ms-touch-action: none;
But that also disables touch scrolling so the page is no longer draggable. If I use:
-ms-touch-action: pan-x;
Then the scrolling works again but the browser back gesture reappears which is a really annoying user experience. Is there a way to allow panning but not the history gesture?
The solution is simple, you just need to add a CSS style that prevents scroll behavior from bubbling up from child elements that have reached their scroll limit, to parent elements (where the scroll eventually turns into a top-level history navigation).
The docs (http://msdn.microsoft.com/en-us/library/windows/apps/hh466007.aspx) state that the default is:
-ms-scroll-chaining: none;
However the default appears to really be:
-ms-scroll-chaining: chained;
I set that style to none by default and chained on the elements in my carousel that really should be chained, which disabled history navigation gestures in my app:
* {
-ms-scroll-chaining: none;
}
.carousel * {
-ms-scroll-chaining: chained;
}
You need to set -ms-touch-action: none; on all elements.
This will instead fire events to your JavaScript handlers, (if there are any), but will prevent ALL new actions including: panning, zooming, and sliding. This is best if you'd like to custom tailor how your app utilizes touch.
Not an ideal or elegant solution, but can you use the MSPointerDown, MSPointerMove and MSPointerUp event listeners to detect a swipe and preventDefault?
// Touch events
target.addEventListener('MSPointerDown', callback);
target.addEventListener('MSPointerMove', callback);
target.addEventListener('MSPointerUp', callback);
Edit: The following doesn't prevent swipe causing navigation on Windows Phone 8.1, although it does prevent swipe navigation for me on a windows 8.1 tablet. Leaving answer here, since it might be partially useful to someone.
If your page is larger than the viewport (touch to pan), then the following CSS works (edit: only on 8.1 tablet):
html {
-ms-scroll-chaining: none;
}
If your page is smaller than then viewport (i.e. the page is not scrollable/pannable e.g. zoomed out) then the above doesn't work.
However code similar to the following works (edit: only on 8.1 tablet) for me:
CSS:
html.disable-ie-back-swipe {
overflow: scroll;
-ms-scroll-chaining: none;
}
JavaScript:
if (navigator.msMaxTouchPoints) {
if (/Windows Phone/.test(navigator.userAgent)) {
document.documentElement.classList.add('disable-ie-back-swipe');
} else {
try {
var metroTestElement = document.createElement('div');
metroTestElement.style.cssText = 'position:absolute;z-index:-1;top:0;right:0;bottom:-10px;width:1px';
document.body.appendChild(metroTestElement);
if (Math.round(window.outerWidth - metroTestElement.offsetLeft) === 1) {
document.documentElement.classList.add('disable-ie-back-swipe');
}
document.body.removeChild(metroTestElement);
} catch (e) { // window.outerWidth throws error if in IE showModalDialog
}
}
}
Notes on the JavaScript:
Testing navigator.msMaxTouchPoints checks that this is IE10/IE11 and that the device uses touch.
Edit: detects Windows Phone and sets disable-ie-back-swipe however the CSS doesn't actually disable the feature on Windows Phone 8.1 ARRRGH.
The metroTestElement tests for modern (modern doesn't have scrollbars so right is 1 pixel, whereas desktop has scrollbars so right is 18 pixels or so depending on scrollbar width).
The code only disables the back swipe if IE11 and modern is used.
It seems that either html or body can be used for the CSS rules, and I am unsure which is actually better (IMHO I usually think of the body as the page and not scrollable, and html as the viewport/window, but actually depends upon IE implementation details).
Edit 2: This IE feature is called "flip ahead". Corporates may be able to disable it using group policy - see http://www.thewindowsclub.com/enable-disable-flip-feature-internet-explorer-10
On a project I was working on needed exactly this but needed to scroll in certain areas (not just general scrolling but overflow). Seems the following does work, tested on IE11 (Metro) Surface 2 and IE11 WinPhone on Lumia 930. Also with touch mouse which does the horizontal scrolling too.
Please see this demo here: http://jsbin.com/fediha/1/edit?html,css,output
The trick to disable history back/forward) seems to be to disable "pan-x" on any element except the ones you want to scroll horizontally. Excerpt from CSS:
* {
/* disallow pan-x! */
touch-action: pan-y pinch-zoom double-tap-zoom;
/* maybe add cross-slide-x cross-slide-y? */
}
.scroller-x,
.scroller-x * {
/* horizontal scrolling only */
touch-action: pan-x;
}
.scroller-y,
.scroller-y * {
/* vertical scrolling only */
touch-action: pan-y;
}
On rare instances history back is still triggered but that is really rare (could only do this by wildly flicking on the tablet and even then not it does only happen sometimes).
touch-action is IE11 only, on IE10 you'd need -ms-touch-action but IE10 is not used that much anymore and I have no test device with it.
I am trying to find a script that detects if a device places position: fixed elements relative to the ViewPort and not to the entire document.
Currently, standard desktop browsers and Mobile Safari (for iOS 5) do so, whereas Android devices place the fixed elements relative to the entire document.
I have found a couple of tests to detect this, but none of the seem to work:
http://kangax.github.com/cft/ Gives me a false positive when I pass it from an Android device.
https://gist.github.com/1221602 Gives me a false negative when I pass it in an iPhone with iOS 5.
Does anybody know where to find / how to write a test that actually detects that? I don't want to rely on browser sniffing.
According to the contributors at Modernizr, you cannot do this without detecting the browser in use. The contributors are quite well-established in the field.
Testing for position: fixed on iOS and Android devices is listed under the Undetectables wiki page in the Modernizr project.
The MobileHTML5 website lists the support for position:fixed. http://mobilehtml5.org/
Actually, the guys from the Filament Group did a smart thing with their Fixedfixed putting the user agent string of known false positives in their test.
Check it # http://github.com/filamentgroup/fixed-fixed
Someone could complete it with some false negatives too, and make it a modernizr aditional featur test.
I've created another check if position:fixed is really supported in browser. It creates fixed div and try to scroll and check if the position of div changed.
function isPositionFixedSupported(){
var el = jQuery("<div id='fixed_test' style='position:fixed;top:1px;width:1px;height:1px;'></div>");
el.appendTo("body");
var prevScrollTop = jQuery(document).scrollTop();
var expectedResult = 1+prevScrollTop;
var scrollChanged = false;
//simulate scrolling
if (prevScrollTop === 0) {
window.scrollTo(0, 1);
expectedResult = 2;
scrollChanged = true;
}
//check position of div
suppoorted = (el.offset().top === expectedResult);
if (scrollChanged) {
window.scrollTo(0, prevScrollTop);
}
el.remove();
return suppoorted;
}
This function was tested in Firefox 22, Chrome 28, IE 7-10, Android Browser 2.3.