使用Modernizr检测IE的正确方法是什么?

85

我想使用Modernizr JS库来检测一些浏览器属性,以确定要显示哪些内容。

我的应用程序名为Pano2VR,可以输出HTML5和SWF格式。但我需要提供HTML5版本给iOS设备用户。

然而,IE根本无法呈现这个“HTML5”输出。看起来他们的输出使用了CSS3 3D转换和WebGL,这其中一个或多个在IE9中显然不被支持。

因此,对于那些用户,我需要显示Flash版本。我打算使用IFRAME,并通过Modernizr脚本传递SRC,或根据浏览器文档编写正确的IFRAME代码。

这一切都导致如何使用Modernizr简单地检测IE或非IE?或者检测CSS 3D转换?

还是有其他方法吗?

9个回答

197

Modernizr并不直接检测浏览器,而是检测其特性和能力,这是它试图实现的全部精髓。

您可以尝试使用像这样的简单检测脚本,然后使用它来进行选择。我也包括了版本检测,以防需要。如果您只想检查任何版本的IE,可以查找navigator.userAgent的值是否为“MSIE”。

var BrowserDetect = {
        init: function () {
            this.browser = this.searchString(this.dataBrowser) || "Other";
            this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "Unknown";
        },
        searchString: function (data) {
            for (var i = 0; i < data.length; i++) {
                var dataString = data[i].string;
                this.versionSearchString = data[i].subString;

                if (dataString.indexOf(data[i].subString) !== -1) {
                    return data[i].identity;
                }
            }
        },
        searchVersion: function (dataString) {
            var index = dataString.indexOf(this.versionSearchString);
            if (index === -1) {
                return;
            }

            var rv = dataString.indexOf("rv:");
            if (this.versionSearchString === "Trident" && rv !== -1) {
                return parseFloat(dataString.substring(rv + 3));
            } else {
                return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
            }
        },

        dataBrowser: [
            {string: navigator.userAgent, subString: "Edge", identity: "MS Edge"},
            {string: navigator.userAgent, subString: "MSIE", identity: "Explorer"},
            {string: navigator.userAgent, subString: "Trident", identity: "Explorer"},
            {string: navigator.userAgent, subString: "Firefox", identity: "Firefox"},
            {string: navigator.userAgent, subString: "Opera", identity: "Opera"},  
            {string: navigator.userAgent, subString: "OPR", identity: "Opera"},  

            {string: navigator.userAgent, subString: "Chrome", identity: "Chrome"}, 
            {string: navigator.userAgent, subString: "Safari", identity: "Safari"}       
        ]
    };
    
    BrowserDetect.init();
    document.write("You are using <b>" + BrowserDetect.browser + "</b> with version <b>" + BrowserDetect.version + "</b>");

你可以简单地检查:

BrowserDetect.browser == 'Explorer';
BrowserDetect.version <= 9;

2
谢谢。我最终追踪到问题是他们的文件需要webgl支持。因此,我可以使用Modernizer来测试并写入一个代码块或另一个代码块。但这是浏览器检测的绝佳解决方案。再次感谢。 - Steve
2
需要记住的一件事是:UA字符串完全可以由用户自定义。因此,检查UA字符串并不是一种检查浏览器的一致方式。https://developer.mozilla.org/zh-CN/docs/DOM/window.navigator.userAgent在“注释”部分中: 基于检测用户代理字符串的浏览器识别是不可靠的,不建议使用,因为用户代理字符串是可由用户配置的。 - Andrew Senner
51
但是有多少用户使用修改、欺骗或不正确的UA字符串浏览网页?你希望花费多少工程时间来确保这个微小的少数群体在您的网站上拥有最佳体验?通过UA字符串进行浏览器嗅探是一种实用和明智的方法。 - Jed Richards
17
@Wintamute,完全同意。对“特性检测是邪恶的”这种讲座已经感到厌烦了。我们在从事工程,而不是追求艺术。 - Philip007
9
一般人会认为,如果某人修改了他们的UA字符串,那么他们知道自己在做什么,并且能够应对后果。实际上,这正是UA字符串的存在意义 - 声明浏览器版本给服务器。如果客户端想要欺骗服务器,那么好吧,这就是生活!当然,字符串被更改而无需用户同意的可能性很小,但实际上这并不是真正的问题 - 我们难道还要喂饱用户并给他们揉背吗? - Rolf
显示剩余11条评论

20
你可以使用Modernizr来检测IE或非IE,通过检查SVG SMIL动画支持。
如果在你的Modernizr设置中包含了SMIL特性检测,你可以使用简单的CSS方法,以及目标.no-smil类,这是Modernizr应用于html元素的。
html.no-smil {
  /* IE/Edge specific styles go here - hide HTML5 content and show Flash content */
}

或者,您可以使用Modernizr和简单的JavaScript方法,如下所示:

if ( Modernizr.smil ) {
  /* set HTML5 content */
} else {
  /* set IE/Edge/Flash content */
}

请记住,IE/Edge可能会在未来支持SMIL,但目前没有计划这样做。
供参考,这是caniuse.com上的SMIL兼容性表。

我认为这是最佳答案。如此简单。 - Batman
2
虽然这样做可以起作用,但只是暂时的。特性检测和Modernizr 的整个意义在于你不必担心明天会发生什么。如果 Edge 明天更新了 smil 支持,你的代码将不再起作用,甚至可能你都不知道。 - Jason
目前微软并没有计划在Edge浏览器中支持SMIL。 - jacefarm
1
这看起来很简单,但显然Edge现在支持SMIL - Jeremy Carlson

12

检测CSS 3D变换

Modernizr可以检测CSS 3D变换。如果浏览器支持它们,Modernizr.csstransforms3d的真值将告诉你。

上面的链接允许您选择在Modernizr中包含哪些测试,并且您正在寻找的选项在那里可用。


专门检测IE

或者,如user356990所回答的那样,如果您仅搜索IE,可以使用条件注释。与其创建一个全局变量,不妨使用HTML5 Boilerplate's 的 <html> 条件注释技巧来分配一个类:

<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
如果您已经初始化了 jQuery,您只需检查 $('html').hasClass('lt-ie9') 即可。如果您需要检查您所处的 IE 版本,以便有条件地加载 jQuery 1.x 或 2.x,您可以这样做:
myChecks.ltIE9 = (function(){
    var htmlElemClasses = document.querySelector('html').className.split(' ');
    if (!htmlElemClasses){return false;}
    for (var i = 0; i < htmlElemClasses.length; i += 1 ){
      var klass = htmlElemClasses[i];
      if (klass === 'lt-ie9'){
        return true;
      }
    }
    return false;
}());

注意:IE条件注释只支持包括IE9在内的浏览器版本。从IE10开始,微软鼓励使用特性检测而非浏览器检测。


无论您选择哪种方法,都应该进行测试。

if ( myChecks.ltIE9 || Modernizr.csstransforms3d ){
    // iframe or flash fallback
} 

当然,不要字面理解那个 || 符号。


个人而言,我总是尝试进行基于功能的检测,而不是浏览器检测。 - Chris
@Chris 祝你好运,我也是这样吗?我觉得你并没有真正读懂我的答案。 - iono
你的回答是第一个建议使用特性检测的,所以我想如果其他人阅读了这条评论,它可能会帮到他们。 - Chris
@Chris 哦,抱歉。我以为你在谴责我包含 IE 测试。 - iono

9
如果你正在寻找一个使用特征检测和UA嗅探的JS版本(类似于html5 boilerplate以前的功能):
var IE = (!! window.ActiveXObject && +(/msie\s(\d+)/i.exec(navigator.userAgent)[1])) || NaN;
if (IE < 9) {
    document.documentElement.className += ' lt-ie9' + ' ie' + IE;
}

3

在对这个问题进行更多研究后,我最终采用了以下解决方案来针对IE 10+。 由于IE10和11是唯一支持-ms-high-contrast媒体查询的浏览器,所以这是一个不需要任何JavaScript的好选择:

@media screen and (-ms-high-contrast: active), screen and (-ms-high-contrast: none) {  
   /* IE10+ specific styles go here */  
}

完美运行。


2
CSS技巧有一个很好的解决方案来针对IE 11:http://css-tricks.com/ie-10-specific-styles/。.NET和Trident/7.0是IE独有的,因此可以用来检测IE 11的版本。然后,该代码将用户代理字符串添加到带有属性“data-useragent”的html标签中,以便可以特别针对IE 11进行定位...

1

我需要检测IE与其他大多数浏览器的区别,但我不想依赖UA字符串。我发现使用es6number和Modernizr正好满足我的需求。我对此没有太多担忧,因为我不认为IE会支持ES6数字。所以现在我知道了任何版本的IE与Edge / Chrome / Firefox / Opera / Safari之间的区别。

更多细节请参见:http://caniuse.com/#feat=es6-number

请注意,我并不真正关心Opera Mini的假阴性。你可能会关心。


1

我同意我们应该测试功能,但是很难找到一个简单的答案来回答“现代浏览器”支持哪些功能,而“旧浏览器”不支持哪些功能。

所以我启动了一堆浏览器并直接检查了 Modernizer。我添加了一些我绝对需要的功能,然后我添加了“inputtypes.color”,因为它似乎涵盖了我关心的所有主要浏览器:Chrome、Firefox、Opera、Edge……但不包括IE11。现在我可以温和地建议用户最好使用Chrome/Opera/Firefox/Edge。

这就是我使用的内容-您可以编辑测试列表以适应您特定的情况。如果缺少任何功能,则返回false。

/**
 * Check browser capabilities.
 */
public CheckBrowser(): boolean
{
    let tests = ["csstransforms3d", "canvas", "flexbox", "webgl", "inputtypes.color"];

    // Lets see what each browser can do and compare...
    //console.log("Modernizr", Modernizr);

    for (let i = 0; i < tests.length; i++)
    {
        // if you don't test for nested properties then you can just use
        // "if (!Modernizr[tests[i]])" instead
        if (!ObjectUtils.GetProperty(Modernizr, tests[i]))
        {
            console.error("Browser Capability missing: " + tests[i]);
            return false;
        }
    }

    return true;
}

这是“inputtypes.color”所需的GetProperty方法。
/**
 * Get a property value from the target object specified by name.
 * 
 * The property name may be a nested property, e.g. "Contact.Address.Code".
 * 
 * Returns undefined if a property is undefined (an existing property could be null).
 * If the property exists and has the value undefined then good luck with that.
 */
public static GetProperty(target: any, propertyName: string): any
{
    if (!(target && propertyName))
    {
        return undefined;
    }

    var o = target;

    propertyName = propertyName.replace(/\[(\w+)\]/g, ".$1");
    propertyName = propertyName.replace(/^\./, "");

    var a = propertyName.split(".");

    while (a.length)
    {
        var n = a.shift();

        if (n in o)
        {
            o = o[n];

            if (o == null)
            {
                return undefined;
            }
        }
        else
        {
            return undefined;
        }
    }

    return o;
}

0
你可以使用< !-- [if IE] > hack来设置一个全局的js变量,然后在你的普通js代码中进行测试。这有点丑陋,但对我来说效果很好。

23
条件注释在Internet Explorer >=10中不再受支持。 - rudimenter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接