My site is http://www.thetruenorth.co.uk/
I can't get JQuery to work on my site in IE9 down. It works fine in every other browser.
I've realised that it is the code below, which detects if it's a small screen (mobile), that stops it from working. If I remove this bit, everything works. I use this because I don't know how else I'd disable JS for mobiles, but keep it for desktop. Suggestions welcome.
$(document).ready(function(){
if(matchMedia('only screen and (max-width: 1023px)').matches)
{}
else {
CODE HERE
}
});
I have a feeling there's a bug or something that I'm not aware of. Please could someone put me out of my misery?
Thanks
Simple Debugging in IE9
Open IE9
Press F12 to open the Developer window
Click the 'Script' tab
Click 'Console' on the right pane
Attempt to load your page
You will see the following error:
SCRIPT5009: 'matchMedia' is undefined
scripts.js, line 2 character 2
IE9 does not support the 'matchMedia' function and thus does not define it. Attempting to reference it in code stops the execution of the JavaScript completely at that point because it doesn't know what to do with a reference to something that is undefined.
What is going on
jQuery is loading on your page. You can confirm this by typing '$' into the text input line below the console output and press enter. The console will output some data about how $ is defined. This is a very good sign that jQuery loaded. It isn't conclusive in all situations, but for this one we are set.
What is happening is that your callback that is running onDomReady (via $(document).ready(...)), but it is erroring on the very first line. This error causes the rest of the callback to not execute.
Verifying Functionality Support
You can use caniuse.com to check to see what browsers support functionality (JS, CSS, etc). In this case: http://caniuse.com/matchmedia. You will note that IE10 is the first version that supports the matchMedia function. You can assume that in any earlier version you will not have matchMedia by default and referencing it will cause errors.
What You Can Do Now
On the caniuse.com site, at the top is a horizontal list titled "Resources". In this area you will generally find ways to patch browsers that do not support specific functionality.
In the case of matchMedia there is a link to a 'polyfill' which will use custom js to emulate the functionality of matchMedia. The url is: https://github.com/paulirish/matchMedia.js/.
Polyfills sometimes have limitations or catches to using them so be careful. It is also interesting to note that the matchMedia polyfill was written by Paul Irish, who is a very public figure for web technologies.
A Note On Conditional IE Includes
IE supports conditional comments, so you can include the polyfill defined above only for specific versions of IE; in your case anything < IE10. This is documented on the MDN here: http://msdn.microsoft.com/library/ms537512.aspx
<!--[if lte IE 10]]>
<script src="polyfill.js"></script>
<![endif]-->
This is done so that we can use the browser's implementation when possible (generally faster and potentially with more functionality) and polyfill only when needed.
j08691 found the problem you have.
If you need matchMedia to work with IE9 and down, or Firefox 6 and down or Safari 5.1 and down you must shim it. Here is a polyfill for matchMedia which will let you use it on older browsers.
Note, this is not a jQuery issue, this issue is with matchMedia browser support
That's because matchMedia only works with IE10.
Ref: https://developer.mozilla.org/en-US/docs/DOM/window.matchMedia
You may be better off doing this with PHP. ie probably isn't able to run matchMedia correctly. I always keep things like that on the server side because that'll run the same for any client. If you're using PHP try get_browser(). Really easy to write a quick if statement. Check the examples if you need help.
Andrew Martinez's answer is fairly thorough and correct, and I personally found it to be very useful.
The markup for getting the matchMedia method in IE9 would look as follows
<![if lt IE 10]>
<script src="scripts/matchMedia.js"></script>
<![endif]>
I just check if the browser is Chrome or not and then add the matchMedia code from github, have a look below:
$(document).ready(function() {
var isChrome = !!window.chrome;
if (isChrome == true) {
//do this for chrome
} else if (isChrome != true) {
//do this for all other browsers including IE
//so copy and paste current matchMedia.js script form here https://github.com/paulirish/matchMedia.js/blob/master/matchMedia.js like below
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */
window.matchMedia || (window.matchMedia = function() {
"use strict";
// For browsers that support matchMedium api such as IE 9 and webkit
var styleMedia = (window.styleMedia || window.media);
// For those that don't support matchMedium
if (!styleMedia) {
var style = document.createElement('style'),
script = document.getElementsByTagName('script')[0],
info = null;
style.type = 'text/css';
style.id = 'matchmediajs-test';
script.parentNode.insertBefore(style, script);
// 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers
info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle;
styleMedia = {
matchMedium: function(media) {
var text = '#media ' + media + '{ #matchmediajs-test { width: 1px; } }';
// 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers
if (style.styleSheet) {
style.styleSheet.cssText = text;
} else {
style.textContent = text;
}
// Test if media query is true or false
return info.width === '1px';
}
};
}
return function(media) {
return {
matches: styleMedia.matchMedium(media || 'all'),
media: media || 'all'
};
};
}());
//below you can add your own matchMedia code
}
});
Related
I have a page with form for user registration. I wrapped it with <!--[if IE]> ... <![endif]--> to show it only in IE. And corresponding error is shown for other browsers: <![if !IE]>...<![endif]>.
But this doesn't fully work with IE 10. One can use java-script to determine IE 10, like:
<script type="text/javascript">
var pattern = /MSIE\s([\d]+)/;
var ua = navigator.userAgent;
var matched = ua.match(pattern);
if (matched) {
alert("IE 10");
}
</script>
But how can I bind it with html block I use for IE7+?
Updated
It needs for using the IX509 Windows interface which demands IE usage because it is COM object (I'm not sure, but it seems it uses ActiveX for it), otherwise strange errors will appear on a page when IX509 is used.
For ActiveX support, just check that the ActiveXObject exists in JS:
if(typeof window.ActiveXObject != "undefined")
Or more specifically:
if(typeof window.ActiveXObject == "function")
If you're confident that scoping is not an issue in your script and don't want the window., variables are of course automatically fetched from the window object, so you can shorten the code to:
if(typeof ActiveXObject != "undefined")
Though it should only be used with understanding of potential consequences
Use feature detection, not browser detection.
You can detect whether the browser supports ActiveX with the following simple line of code:
if(typeof window.ActiveXObject != "undefined") { ..... }
Why?
Browser detection is fragile -- newer versions of IE may not be picked up by your detection code, resulting in your site breaking. In fact this is exactly what's happened here. And you'd probably have the same issue all over again with IE11. The above feature detection script will work correctly in all browsers and all versions.
Not all IE installations have ActiveX available. If you detect IE and then assume it supports ActiveX, your site will break badly for those that don't have it. Again, using feature detection instead will avoid this issue.
I improved the approach I tried at first.
First of all error page is wrapped with the following <div>:
<div id="not_ie" style="display:none">
IE form is also wrapped with <div>:
<div id="ie" style="display:none">
And the following js makes form or error visible depending on browser type:
<script type="text/javascript">
var pattern = /MSIE\s([\d]+)/;
var ua = navigator.userAgent;
var matched = ua.match(pattern);
if (matched) {
var elem = document.getElementById("ie");
elem.style.display = "inline";
} else {
var elem = document.getElementById("not_ie");
elem.style.display = "inline";
}
</script>
There's no need in use of conditional comments, determining of ActiveX or version-specific feature of IE.
I am working on modernizing an older SAAS software. I am their first front end person. They currently only support older IE browsers - and tell their users to turn on quirks mode in newer IE browsers to their software still works.
During the slow process of modernizing I still need those users software to work and not fall apart.
Is there a conditional comment, javascript or other functionality that could let me on the front end know that the browser has been set to quirks mode manually?
I don't want to turn it off, as it is making other parts of the system work, I just need to be able to add a quirks mode to the html tag so that I can work out the kinks in css.
Thanks in advance.
Edit
OK, I have a js solution, well almost... This will give me an alert every time, but will only add the class to the html when I manually change the mode in ie. Any ideas?
$(document).ready(function() {
var quirksMode = (document.compatMode == 'BackCompat');
var isIE = ($('html').hasClass('ie'));
if ( quirksMode && isIE ) {
$('html').addClass('quirks');
alert('IE Quirks');
}
});
OK, I also need to find if they are in Document Mode IE 7 Standard manually, I know this is a mess, but they need it and I think it's important enough to make this happen. I am having the same issue with it not putting the class on unless I am changing the stuff manually, not just on load. Here is this code... it's in the same document ready from above.
if ( document.documentMode == 7) {
$('html').addClass('ie7_standard');
alert('IE 7 Mode');
};
var quirksMode = (document.compatMode == 'BackCompat');
var isIE = ($('html').hasClass('ie'));
if ( quirksMode && isIE ) {
$('html').addClass('quirks');
};
if ( document.documentMode == 7) {
$('html').addClass('ie7_standard');
};
This solves this issue. It adds a class to html if you have Quirks mode in IE or IE7 Standards Document Mode set manually.
F12 in IE won't always show the new class name, but if you have css tied to that class, it will function.
Thanks for your help everyone!
I used this question (How to detect Render Mode of browser for current page?) as a starting point, but it seemed to be slightly outdated.
I have this string which i'm trying to store and get to localStorage, and retrieve from it so it could show.
Here's my code:
var datas = new Array;
if (navigator.appName !== 'Microsoft Internet Explorer'){
var qsVal = document.getElementsByClassName("val");
}
else{
var qsVal = document.querySelectorAll('.val');
}
if (navigator.appName !== 'Microsoft Internet Explorer'){
var qsKey = document.getElementsByClassName("key");
}
else{
var qsKey = document.querySelectorAll('.key');
}
var storedPlays;
var stuff = document.getElementById("stuff");
function pushArray(){
for (var i=0, len = qsVal.length; i < len; i++){
thisValue = qsVal[i].value;
thisKey = qsKey[i].value;
datas.push([thisValue,thisKey]);
}
localStorage.setItem('datas', JSON.stringify(datas));
}
function showStuff(){
storedPlays = JSON.parse(localStorage.getItem('datas'));
document.getElementById("stuff").innerHTML = storedPlays;
}
It works great with FF and Chrome, but IE8 returns "'localStorage' is null or not an object" when I call 'showStuff'.
What's interesting is that it doesn't give me an error when I call 'pushArray', which uses 'localStorage' as well.
Iv'e also tried using "window.localStorage" instead of just "localStorage", it returned the same error...
IE8 is supposed to support localStorage, according to Microsoft and W3, so does anyone has any clue as to where the problem is?
Thanks a million!
EDIT - This is a jsfiddle for the code. for some reason, it doesn't work that good but just to give you a feel of the code...
As per my understanding IE8 give storage to only valid domains. Try placing your example in some Web-server it should resolve the issue.
I faced the same issue when I tested it as an individual file but when i placed it in a server(Tomcat in my case) it just worked fine.
Check if you are actually in IE 8 mode - as opposed to quirks or IE 7 mode. Fastest way to do this is hit F12 to bring up the dev tools, and the browser mode is listed on the upper right of that tab.
I would give using window.localStorage as shot. See Introduction to Web Storage for IE
Can you open the developer tools in IE and check that typeof json. stringify and json.parse are functions and also localstorage. I am not sure whether native JSON exist on IE.
Also why are you setting the object inside the loop, shouldnt it be outside it?
[Edit]
Added this fiddle for your code jsfiddle.net/yrhdN/2 and everything seems to work fine. I have tested in IE9 under IE8 compatibility mode)
[Edit]
One more thing about this code, it seems innerHtml in showStuff() doesn't work with a paragraph. Changing the html from p to div and using innerText makes things a little better:
<div id="stuff">
</div>
function showStuff(){
var storedPlays = JSON.parse(localStorage.getItem('datas'));
document.getElementById("stuff").innerText = storedPlays;
}
This seems to happen only in IE. Here is an updated fiddle: http://jsfiddle.net/yrhdN/7/
Try this also if you do not wish any local server application to shoot the webpage.
Look for the code in your script : window['localStorage'] !== null
change it to : window['localStorage'] != null
It worked in my case.
So I know $.browser has been deprecated and "frowned upon", since jQuery 1.3, but it continues to exist & work in the code.
It's still using the plain javascript: navigator.userAgent to determine the browser being used, as well as the version.
Now is there something about these I don't know about navigator itself, that I shouldn't be using either $.browser or plain vanilla JS to get the browser/version? I just want to make sure when they have IE8 (for example), they really do have it, and I'm not processing the wrong code.
What other alternatives do we have for browser sniffing? I know about $.support, I use modernizr, but sometimes I need just need the down and dirty browser version, instead of seeing what the browser is capable of handling (I think that is a completely different problem solver).
You kind of answer the question yourself. The ideal is to check for feature support. As more browsers and devices come onto the market this approach should scale.
However if you want to do something 'down and dirty' then browser detection of course works, but only so far as you will know your code works in the existing set of browsers (or even just those you've tested your code with).
Generally it's recommended not to try to guess what the browser is but to check if a function is available. There are too many browsers and variants.
To check if a function is available, you simply do this :
if (!Array.prototype.map) {
// not available, shut down computer !
If a "must" to know which browser on the page for me, I use this personally;
(function() {
var re_browsers = {
firefox: /firefox\/([\d\.]+)/,
chrome: /chrome\/([\d\.]+)/,
safari: /webkit.*?version\/([\d\.]+)/,
opera: /opera.*?version\/([\d\.]+)/,
ie: /msie\s+([\d\.]+)/
// ...
};
var ua = window.navigator.userAgent.toLowerCase(), k, re, browser = {};
for (k in re_browsers) {
if (re = re_browsers[k].exec(ua)) {
break;
}
}
browser[k] = true;
browser["version"] = parseFloat(re && re[1]);
browser["versionOrig"] = re[1];
jQuery.extend({browser: browser});
})();
I'm using ZeptoJS for my web app, but I'd like to fall back to jQuery if the browser doesn't support Zepto. Since IE is the only major browser not supported at the moment, I'm tempted to detect IE:
if(navigator.appName == 'Microsoft Internet Explorer'){
// load jquery
} else {
// load zepto
}
but I'd prefer to specificly detect Zepto support and use jQuery in other cases. Is there a feature detection way to do this?
You can also use JS trick described here to detect whether browser is IE, and use a modern asynchronous script loading library to load the required lib. Yepnope example:
yepnope({
test: !+"\v1", // IE?
yep: 'jquery.js',
nope: 'zepto.js'
});
Rather than doing that with Javascript, I'd take it one step ahead and use conditional statements. This could look like:
<!--[if lt IE 8 ]>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js"></script>
<![endif]-->
<!--[if !IE]>
<script src="/js/zepto.js"></script>
<![endif]-->
This goes right into your HTML files. The above snippet will load jQuery, if the browser is Internet Explorer 7 and below. Otherwise it'll include zepto.js.
As Zepto Documentation said, if you need to detect Internet Explorer you can use this code:
if ('__proto__' in {}) {
// IS NOT IE
} else {
// IS IE
}
Zepto use it to fall back on jQuery, but I have use it as browser detection too.
This might be a crazy idea (I'm not sure if Zepto will even load on an unsupported browser), but what about using Zepto's own browser detection to see if it's on an unsupported browser?
$.os.ios // => true if running on Apple iOS
$.os.android // => true if running on Android
$.os.webos // => true if running on HP/Palm WebOS
$.os.touchpad // => true if running on a HP TouchPad
$.os.version // => string with version number, "4.0", "3.1.1", "2.1", etc.
$.os.iphone // => true if running on iPhone
$.os.ipad // => true if running on iPad
$.os.blackberry // => true if running on BlackBerry
Maybe you could do something like this:
var isSupported = false;
for (os in $.os) {
if ($.os[os] == true) { isSupported = true; }
}
This won't catch chrome/firefox, which work fine with Zepto, but it does match the Zepto team's intentions for the thing, which may or may not be better.
Don't use the conditional comments, it's not going to be supported by IE10. This is the recommended approach from the zepto documentation:
Load Zepto on modern browser and jQuery on IE
<script>
document.write('<script src=' +
('__proto__' in {} ? 'zepto' : 'jquery') +
'.js><\/script>')
</script>
Zepto doesn't work in IE because IE doesn't support prototype, so this is exactly the right way to check.
The script above do a dynamical load but the logic is
<script>
if ('__proto__' in {}) {
// This is NOT IE
} else {
// This is IE
}
</script>
<script>
document.write('<script src=' + ('__proto__' in {} ? 'zepto' : 'jquery') + '.js><\/script>')
</script>
This is the recommended method on zepto.js official site. See http://zeptojs.com/#download
While many of the existing answers work fine when loading Zepto.js via an additional request, I have a situation where I know Zepto will suffice most of the time and I just want to merge it in with my scripts and lazily load jQuery if needed. I put together a small wrapper for Zepto will do just that.
Zepto conditional loading wrapper
It runs the "offical" '__proto__' in ... test and lazy loads jQuery if it fails. If it succeeds, then it continues loading Zepto.
I found that IE8 would blow up if Zepto was even loaded. This fixes that by skipping the rest of the module.
For the optimistic case, there isn't any additional script requests. For the jQuery path, well, those users weren't exactly getting the fast experience anyway.
This is an old topic, but it's what came up for me, and I was not happy with the solution overall. Someone in a comment above mentioned that the official zepto test will result in zepto going to FireFix 3.6 instead of JQuery, which I would prefer to avoid if at all possible.
So, my thought was...test to see if it supports some HTML5 feature AND if it's not IE. This may mean that the larger jQuery will go to more browsers than it should, but I would prefer "working" bloated code to a quick download of nothing. So, anyway, taking the isCanvasSupported() method from Modernizer and the __proto__ test recommended by zepto, I'm thinking this might be a good solution (haven't had a chance to actually test yet):
var isHtml5AndNotIE = function() {
var elem = document.createElement('canvas');
return '__proto__' in {} && !!(elem.getContext && elem.getContext('2d'));
};
Then, just use that method in the document.write() as in the examples above or wherever you are defining the path to jquery/zepto.
The only two browser versions that I could see in a quick cross-reference that support canvas but aren't supported by zepto are:
* IOS Safari 3.2 (4+ is supported by Zepto)
* Android 2.1 (2.2+ is supported by Zepto)
http://zeptojs.com/#platforms
http://caniuse.com/#feat=canvas
This is the way I do it:
<script type="text/javascript">
if(top.execScript){ // true only in IE
document.write("<script src='/js/jquery.js'>\x3C/script>");
}
else{
document.write("<script src='/js/zepto.min.js'>\x3C/script>");
}
</script>
You should raise the bar a bit so not only IE8 will get jQuery, but also other older browsers. Zepto for example requires features such as Array.prototype.some.
Zepto requires much the same features as picoQuery (which is an alternative to Zepto). In picoQuery, they do like this:
if (Array.isArray) {
// Modern browser
// (FF4+, IE9+, Safari 5+, Opera 10.5+, Konq 4.9+, Chrome 5+, etc)
document.write("<script src='/js/zepto.min.js'></script>");
}
else {
document.write("<script src='/js/jquery.js'></script>");
}
From compatibility tables we have that any browser that supports Array.isArray also supports querySelectorAll(), addEventListener(), dispatchevent, Array.prototype.indexOf and Array.prototype.some - all which are used in Zepto
picoQuery describes this choice here:
http://picoquery.com/the_fallback