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]"
Related
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.
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.
What would be your fastest, shortest (best) way to detect browser which is IE and version less than 9 in JavaScript, without using jQuery or any add-on libraries?
Javascript
var ie = (function(){
var undef,
v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');
while (
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
);
return v > 4 ? v : undef;
}());
You can then do:
ie < 9
By James Panolsey from here: http://james.padolsey.com/javascript/detect-ie-in-js-using-conditional-comments
for what it's worth:
if( document.addEventListener ){
alert("you got IE9 or greater");
}
This successfully targets IE 9+ because the addEventListener method was supported very early on for every major browser but IE. (Chrome, Firefox, Opera, and Safari) MDN Reference. It is supported currently in IE9 and we can expect it to continue to be supported here on out.
Using conditional comments, you can create a script block that will only get executed in IE less than 9.
<!--[if lt IE 9 ]>
<script>
var is_ie_lt9 = true;
</script>
<![endif]-->
Of course, you could precede this block with a universal block that declares var is_ie_lt9=false, which this would override for IE less than 9. (In that case, you'd want to remove the var declaration, as it would be repetitive).
EDIT: Here's a version that doesn't rely on in-line script blocks (can be run from an external file), but doesn't use user agent sniffing:
Via #cowboy:
with(document.createElement("b")){id=4;while(innerHTML="<!--[if gt IE "+ ++id+"]>1<![endif]-->",innerHTML>0);var ie=id>5?+id:0}
bah to conditional comments! Conditional code all the way!!! (silly IE)
<script type="text/javascript">
/*#cc_on
var IE_LT_9 = (#_jscript_version < 9);
#*/
</script>
Seriously though, just throwing this out there in case it suits you better... they're the same thing, this can just be in a .js file instead of inline HTML
Note: it is entirely coincidental that the jscript_version check is "9" here. Setting it to 8, 7, etc will NOT check "is IE8", you'd need to lookup the jscript versions for those browsers.
Below is an improvement over James Padolsey's solution:
1) It doesn't pollute memory (James' snippet creates 7 unremoved document fragments when detecting IE11, for example).
2) It's faster since it checks for a documentMode value before generating markup.
3) It's far more legible, especially to beginning JavaScript programmers.
Gist link: https://gist.github.com/julianshapiro/9098609
/*
- Behavior: For IE8+, we detect the documentMode value provided by Microsoft.
- Behavior: For <IE8, we inject conditional comments until we detect a match.
- Results: In IE, the version is returned. In other browsers, false is returned.
- Tip: To check for a range of IE versions, use if (!IE || IE < MAX_VERSION)...
*/
var IE = (function() {
if (document.documentMode) {
return document.documentMode;
} else {
for (var i = 7; i > 0; i--) {
var div = document.createElement("div");
div.innerHTML = "<!--[if IE " + i + "]><span></span><![endif]-->";
if (div.getElementsByTagName("span").length) {
return i;
}
}
}
return undefined;
})();
var ie = !-[1,]; // true if IE less than 9
This hack is supported in ie5,6,7,8. It is fixed in ie9+ (so it suits demands of this question). This hack works in all IE compatibility modes.
How it works: ie engine treat array with empty element (like this [,1]) as array with two elements, instead other browsers think that there is only one element. So when we convert this array to number with + operator we do something like that: (',1' in ie / '1' in others)*1 and we get NaN in ie and 1 in others. Than we transform it to boolean and reverse value with !. Simple. By the way we can use shorter version without ! sign, but value will be reversed.
This is the shortest hack by now. And I am the author ;)
I've decided to go with object detection instead.
After reading this:
http://www.quirksmode.org/js/support.html
and this:
http://diveintohtml5.ep.io/detect.html#canvas
I'd use something like
if(!!document.createElement('canvas').getContext) alert('what is needed, supported');
This link contains relevant information on detecting versions of Internet Explorer:
http://tanalin.com/en/articles/ie-version-js/
Example:
if (document.all && !document.addEventListener) {
alert('IE8 or older.');
}
You could do it in a quick and dirty fashion with a regular expression and .match():
if (navigator.userAgent.match(/MSIE\s(?!9.0)/)) {
// ie less than version 9
}
If I were you I would use conditional compilation or feature detection.
Here's another alternative:
<!--[if lt IE 9]><!-->
<script>
var LTEIE8 = true;
</script>
<!--<![endif]-->
I liked Mike Lewis' answer but the code did not pass jslint and I could not understand the funky while loop. My use case is to put up a browser not supported message if less than or equal to IE8.
Here is a jslint free version based on Mike Lewis':
/*jslint browser: true */
/*global jQuery */
(function () {
"use strict";
var browserNotSupported = (function () {
var div = document.createElement('DIV');
// http://msdn.microsoft.com/en-us/library/ms537512(v=vs.85).aspx
div.innerHTML = '<!--[if lte IE 8]><I></I><![endif]-->';
return div.getElementsByTagName('I').length > 0;
}());
if (browserNotSupported) {
jQuery("html").addClass("browserNotSupported").data("browserNotSupported", browserNotSupported);
}
}());
Does it need to be done in JavaScript?
If not then you can use the IE-specific conditional comment syntax:
<!--[if lt IE 9]><h1>Using IE 8 or lower</h1><![endif]-->
if (+(/MSIE\s(\d+)/.exec(navigator.userAgent)||0)[1] < 9) {
// IE8 or less
}
extract IE version with: /MSIE\s(\d+)/.exec(navigator.userAgent)
if it's non-IE browser this will return null so in that case ||0 will switch that null to 0
[1] will get major version of IE or undefined if it was not an IE browser
leading + will convert it into a number, undefined will be converted to NaN
comparing NaN with a number will always return false
You are all trying to overcomplicate such simple things. Just use a plain and simple JScript conditional comment. It is the fastest because it adds zero code to non-IE browsers for the detection, and it has compatibility dating back to versions of IE before HTML conditional comments were supported. In short,
var IE_version=(-1/*#cc_on,#_jscript_version#*/);
Beware of minifiers: most (if not all) will mistake the special conditional comment for a regular comment, and remove it
Basically, then above code sets the value of IE_version to the version of IE you are using, or -1 f you are not using IE. A live demonstration:
var IE_version=(-1/*#cc_on,#_jscript_version#*/);
if (IE_version!==-1){
document.write("<h1>You are using Internet Explorer " + IE_version + "</h1>");
} else {
document.write("<h1>You are not using a version of Internet Explorer less than 11</h1>");
}
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 :)