I don't usually do this and do not support this approach myself. However, my current use case concerns work with MS Sharepoint, and I need to discover if a user is in any version of MSIE or not.
There does seem to be some native Sharepoint functionality that only works in MSIE but I am unable to find how it works - and of course browser sniffing is not a good approach either. I came across this snippet (reference to author at bottom) which looks like an ok test to use:
if(window.ActiveXObject || "ActiveXObject" in window){
// Always true if browser is Internet Explorer
}
Can anyone offer comment on the long term validity of this test. I also thought about testing if the CSS3 selector prefix '-ms-' is supported, but this will of course only work on more modern versions of IE.
Any comments/advice/suggestions much appreciated.
Reference to source of
proposed solution author.
I suggest looking at http://browserhacks.com/
they have a list of several methods to test for IE11 and below.
Ones I personally use are,
// IE <= 10
var ieVersion = (function() { if (new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) != null) { return parseFloat( RegExp.$1 ); } else { return false; } })();
// IE 11
var isIE = '-ms-scroll-limit' in document.documentElement.style && '-ms-ime-align' in document.documentElement.style;
ieVersion returns a number if true, false if not true. isIE evaluates to true or false
If you decide to go with a solution involving the user agent string, it's a safe bet that every IE version from 8 through 11 will include the Trident token:
/Trident/.test(navigator.userAgent)
This is the approach I'd use if I couldn't figure out what feature actually needed to be tested for.
Related
We have a website working in IE 8 now and we need to make it work in IE 11 (Non comparability mode). When I make changes to work in IE 11 it is not working in IE8(JavaScript issue like tag-name giving different value, create srcelement,document.all and many more issues).
I tried creating two java script files one for IE8 and one for IE 11 and loaded based on IE version for couple of pages but seems its not practical. What is the best way to deal with this type of situation?
This will return the IE Browser version else return false. The cool part about basing your logic on choosing which JS file to use is, that you will not have a bunch of IF statements in your JS code like,
IF IE11
run all this JS code
ELSE IF IE 8
run all this JS code
ELSE
hopefully this JS will work
But on the other side of the argument by doing it this way you will not have a ton of JS files with mostly duplicate code in them.
function msieversion() {
var ua = window.navigator.userAgent;
var msie = ua.indexOf("MSIE ");
if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) // If Internet Explorer, return version number
alert(parseInt(ua.substring(msie + 5, ua.indexOf(".", msie))));
else // If another browser, return 0
alert('otherbrowser');
return false;
}
I read an article about Test for Internet Explorer in JavaScript which states that a quick test is :
var isMSIE = /*#cc_on!#*/0;
if (isMSIE) {
// do IE-specific things
} else {
// do non IE-specific things
}
But one of the comments showed another way : ( and I have to say , it works)
if (-[1,]) {
// do non IE-specific things
} else {
// do IE-specific things
}
And so I ask :
What is so special with -[1,] that IE doesn't recognize it while others do ?
p.s.
found another quick falsy-truthy trick
IE='\v'=='v'
[1,].toString() in IE prior to recent versions was 1, which when prefixed with arithmetic - would output falsey NaN whereas other browsers would return [1,].toString() === 1 for a truthy -1.
Its a horrid sniffing technique, avoid it entirely and as other have commented detect support for specific features.
This question is quite simple, but I want to ask it anyway.
This code tell us that user's browser is a famous Opera Mini
var isOperaMini = (navigator.userAgent.indexOf('Opera Mini') > -1);
So I can use it in this way:
if (navigator.userAgent.indexOf('Opera Mini') > -1)
alert('hey! your browser is buggy');
This is if Opera Mini, then conditional.
How do I make a right short conditional for if not Opera mini, then?
I'm not sure how should I play with -1 integer.
You can simply change it to
if (navigator.userAgent.indexOf('Opera Mini') == -1)
That will return true if it does NOT find 'Opera Mini' in the user agent string
From the Opera doc:
Detecting Opera Mini:
2 approaches: You can:
Examine the user agent string
Check for the presence of the operamini object
i.e. If not Opera Mini is:
if (!window.operamini){}
Short, easy and reliable. Unlike the spoof-able user-agent.
Another options (maybe less readable) using ~ operator:
if (~navigator.userAgent.indexOf('Opera Mini')) {
// opera mini
}
if (!~navigator.userAgent.indexOf('Opera Mini')) {
// not opera mini
}
However it's probably better for you to compare with -1, until you are familiar with syntax.
https://dev.opera.com/articles/opera-mini-and-javascript/
var isOperaMini = Object.prototype.toString.call(window.operamini) === "[object OperaMini]"
Is there a better way then using jQuery.browser, or equivalents, for determining css 3 prefixes (-moz, -webkit, etc), as it is disencouraged? Since the css is dynamic (the user can do anything with it on runtime), css hacks and style tag hacks can't be considered.
I don't see the issue with using the navigator.userAgent to determine if you need to cater for Webkit / Gecko CSS3 prefixes. Or better yet, just stick with CSS2 until CSS3 becomes a W3C Recommendation.
The reason use of the navigator object is discouraged is because it was used over Object detection when (java)scripting for different browsers, your situation is one where it is fine to use user agent detection, because your'e specifically targeting certain quirks with different rendering engines.
Edit:
Picking up from where cy left off, you can use javascript object detection to detect whether a prefix is used, I made some quick code to do so:
window.onload = function ()
{
CSS3 = {
supported: false,
prefix: ""
};
if (typeof(document.body.style.borderRadius) != 'undefined') {
CSS3.supported = true;
CSS3.prefix = "";
} else if (typeof(document.body.style.MozBorderRadius) != 'undefined') {
CSS3.supported = true;
CSS3.prefix = "-moz-";
} else if (typeof(document.body.style.webkitBorderRadius) != 'undefined') {
CSS3.supported = true;
CSS3.prefix = "-webkit-";
}
if (CSS3.supported)
if (CSS3.prefix == "")
alert("CSS3 is supported in this browser with no prefix required.");
else
alert("CSS3 is supported in this browser with the prefix: '"+CSS3.prefix+"'.");
else
alert("CSS3 is NOT supported in this browser.");
};
Remember to watch out for strange quirks such as -moz-opacity which is only supported in older versions of Firefox but has now been deprecated in favour of opacity, while it still uses the -moz- prefix for other new CSS3 styles.
Array.prototype.slice.call(
document.defaultView.getComputedStyle(document.body, "")
)
.join("")
.match(/(?:-(moz|webkit|ms|khtml)-)/);
Will return an array with two elements. One with dashes and one without dashes, both lowercase, for your convenience.
Array.prototype.slice.call(
document.defaultView.getComputedStyle(document.body, "")
);
Without the browser check will return an array of nearly all the css properties the browser understands. Since it's computed style it won't display shorthand versions, but otherwise I think it gets all of them. It's a quick hop skip and a jump to auto detect whatever you need as only vendor prefixed stuff starts with a dash.
IE9, Chrome, Safari, FF. Opera won't let you slice CSSStyleDeclaration for you can still use the same getComputedStyle code and loop through the properties or test for a specific one. Opera also wanted to be the odd man out and not report the vendor prefix dasherized. Thanks Opera.
Object.keys(CSSStyleDeclaration.prototype)
Works in IE9 and FF and reports the TitleCased (JavaScript) version of the vendor property names. Doesn't work in WebKit as the prototype only reports the methods.
Here's an interesting and very dangerous function I just wrote along these lines:
(function(vp,np){
Object.keys(this).filter(function(p){return vp=vp||p.match(/^(Moz|ms)/)}).forEach(function(op){
this.__defineGetter__(np=op.replace(vp[0], ""), function() { return this[op] });
this.__defineSetter__(np, function(val) { this[op] = val.toString() });
}, this);
}).call(CSSStyleDeclaration.prototype);
I didn't test anything Konquerer.
It's adding in another library, but would Modernizr work for you? It adds CSS classes to the <html> tag that can tell you what the browser supports.
It does muddy up the code a bit, but can certainly be helpful in appropriate situations.
Speculatively: Yes. You can try adding a vendor prefix css rule (that's what they're called), and then test to see if that rule exists. Those vendor-specific rules won't be added to the DOM in browsers in which they're not supported in some cases.
For example, if you try adding a -moz rule in webkit, it won't add to the DOM, and thus jQuery won't be able to detect it.
so,
$('#blah').css('-moz-border-radius','1px');
$('#blah').css('-moz-border-radius') //null in Chrome
Conversely,
$('#blah').css('-webkit-border-radius','1px');
$('#blah').css('-webkit-border-radius'); //returns "" in Chrome
This method works in WebKit browsers; I'm testing to see if it works in others. Pending.
Edit: Sadly, this isn't working in Firefox or Opera, which just returns "" no matter compatibility. Thinking of ways to do this cross-browser...
Final Edit: Andrew Dunn's answer does this in a way that works (at least in FF and Webkit, which is better than my method).
I use ternary operator to have it only in 1 line. If it's not webkit nor gecko, I'll just use the standard property. If it has no support, who really cares then?
var prefix = ('webkitAnimation' in document.body.style) ? '-webkit-' : ('MozAnimation' in document.body.style? '-moz-' : '');
Basically I found Animation is one of the properties never changed. As soon as the browser starts supporting the Draft / Candidate Recommendation of a CSS3 property, it drops the prefix on JS side. So you will need to be careful and take in mind that, before copy-pasting.
I would like to use feature detection to tell whether the user's version of Firefox supports the CSS style value -moz-linear-gradient. (This was added in Gecko 1.9.2. Version 3.6 of Firefox uses this.)
I can't use document.body.style.mozLinearGradient (or something similar) because -moz-linear-gradient is not a style property but a style value.
Does anyone know how to test for this without using version numbers?
I'm not sure how, but Modernizr (a nice little feature-detection script) appears to do it.
I guess you could create an (offscreen?) element, set that as it's style, and then poke around in the DOM to see if the browser successfully applied it?
Just assign it as style value and check afterwards if it is there.
Kickoff example:
function supportsMozLinearGradient() {
var element = document.getElementsByTagName('script')[0]; // Just grab an "invisible" element.
var oldstyle = element.style.background; // Backup old style.
try {
element.style.background = '-moz-linear-gradient(top, black, white)';
} catch(e) {
// Ignore failures.
}
var supports = element.style.background.indexOf('-moz-linear-gradient') > -1; // Did it accept?
element.style.background = oldstyle; // Restore old style.
return supports;
}
You should check for -moz-background-size (which was introduced in Firefox v3.6). The inference won't be picked up by other browsers since the property is prefixed.
if ('MozBackgroundSize' in document.body.style)
This is how MooTools detects Gecko (Firefox) engine (I'm "paraphrasing" slightly)
gecko = (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18)
So if it's FF it'll return 19 or 18, I believe 19 is 3.x and 18 is 2.x
And apparently FF3.6 stopped supporting document.getBoxObjectFor, so to detect 3.6 I basically do
isFF36 = gecko && !document.getBoxObjectFor
Works like a charm from a few tests I did.
If you're not using MooTools you can probably combine the two into one statement that would return something like false or 'ff' or 'f36' but I'm too lazy to work through that logic :)