网页开发者工具箱:Modernizr

这是关于有用库的一系列文章的第三篇,所有网页开发者都应该将这些库纳入他们的工具箱。本文的目的是向您展示这些库的功能,并帮助您充分利用它们。本文的第三篇专门介绍 Modernizr 库。

简介

Modernizr 是一个最初由 Faruk Ateş 编写的库。

它是以现代方式构建跨浏览器网站或应用程序的关键库之一。该库的核心是称为 渐进增强和优雅降级 的网页设计模式。这种设计模式不需要 Modernizr,但 Modernizr 可以让事情变得更容易。它检测下一代网页技术(如 HTML5 或 CSS3)的原生实现的可用性,并允许您相应地调整您的应用程序,这比尝试一些难看的用户代理嗅探要好得多。

基本用法

使用此库非常简单:下载它,将其链接到您的页面 - 就完成了!

Modernizr 会自动将一些 CSS 类添加到根 html 元素。例如,如果您想测试 Web Sockets 支持,如果浏览器支持该功能,它会将 websockets 类添加到 html 元素,否则它会添加 no-websockets 类。它会对 JavaScript 做同样的事情,通过添加一个全局变量 Modernizr.websocket,该变量的值为布尔值。

让我们看一个简单的例子:用 RGBa 颜色做一些事情。

首先:下载 Modernizr 的自定义版本

Modernizr, download page.

其次:将其链接到您的文档

<!DOCTYPE html>
<!--
The "no-js" class is here as a fallback.
If Modernizr is not running, you'll know
something is wrong and you will be able to act
accordingly. In contrast, if everything goes well,
Modernizr will remove that special class.
-->
<html class="no-js">
<head>
    <meta charset="utf-8">
    <title>I want to do stuff with RGBa</title>
    <script src="modernizr.js"></script>
</head>
<body>
...
</body>
</html>

第三:使用它

使用 CSS

.rgba div {
    /* Do things with CSS for browsers that support RGBa colors */
}

.no-rgba div {
    /* Do things with CSS for browsers that DO NOT support RGBa colors */
}

使用 JavaScript

if(Modernizr.rgba) {
    // Do things with JS for browsers that support RGBa colors
} else {
    // Do things with JS for browsers that DO NOT support RGBa colors
}

让我们看看这个简单的例子

%CODEtoolbox-3-1%

高级用法

当您必须处理异构环境(例如移动浏览器)时,基本用法已经很好了,但还有更多。

条件加载

Modernizr 提供了一种方便的方法来进行条件加载。实际上,YepNope 库 是 Modernizr 项目的独立分支。因此,如果您愿意,您可以将 YepNope 直接捆绑在 Modernizr 中。如果您想要根据特定浏览器的能力加载基于 polyfill 的文件,它非常完美。

Modernizr.load({
    test: Modernizr.indexeddb,
    nope: "indexeddb-polyfill.js"
});

这是一个非常强大的工具:不要犹豫 阅读文档。请注意,Modernizr 团队维护着一个 非常准确的 polyfill 列表。您可以随意使用您需要的任何东西(当然要谨慎)。

自定义测试

Modernizr 带有一组 44 个针对主流技术的测试。如果您需要测试其他一些技术,Modernizr 提供 一个 API 来构建和插入您自己的测试

// Let's test the native JSON support ourselves
Modernizr.addTest('json', function(){
    return window.JSON
        && window.JSON.parse
        && typeof window.JSON.parse === 'function'
        && window.JSON.stringify
        && typeof window.JSON.stringify === 'function';
});

假设上述测试通过,现在 HTML 元素上将有一个 json 类,并且 Modernizr.json 将为 true。否则,HTML 元素上将有一个 no-json 类,并且 Modernizr.json 将为 false。

处理 CSS 前缀

CSS 前缀是一个非常敏感的话题。Modernizr 提供跨浏览器的代码来处理这个问题。Modernizr 提供了一个非常有用的工具来处理这个问题:Modernizr.prefixed()。此方法适用于 CSS 属性(在 CSS OM 中使用驼峰式命名法)以及 DOM 属性。

例如,Modernizr.prefixed("transition") 在 Firefox 中将返回“MozTransition”,但在 Safari 和 Chrome 中将返回“WebkitTransition”。

测试媒体查询

目前,在任何浏览器中都没有简单的方法从 JS 中测试媒体查询。为了帮助解决这个问题,Modernizr 有一个特殊的工具:Modernizr.mq()。此方法将测试您选择的媒体查询,并相应地返回 true 或 false。

if(Modernizr.mq("screen and (max-width: 400px)")) {
    // Do some stuff for small screens
}

限制和注意事项

这个库是一个很棒的工具,但它不是魔法。您应该谨慎使用它,不要忘记其他技术来处理不可预测的行为。例如,不要忘记在足够的情况下依赖 CSS 级联。

以下示例是 Modernizr 的极端误用

div {
    color : white;
}

.rgba div {
    background : rgba(0,0,0,.8);
}

.no-rgba div {
    background : #333;
}

如果由于某种原因 Modernizr 没有执行,您的文本将无法阅读(白色文本在白色背景上)。在这种特定情况下,您最好执行以下操作(顺便说一下,它也更容易阅读和维护)

div {
    color : white;
    background : #333;
    background : rgba(0,0,0,.8);
}

因此,在使用此库时,不要盲目,花点时间思考如果 Modernizr 不可用会发生什么。在很多情况下,您已经有了现有的回退,不要忘记使用它们。

结论

当您必须构建大型跨浏览器内容时,Modernizr 是最实用的工具,从最古老的 Internet Explorer 6 到最新的 Firefox Nightly。一旦您掌握了它,您就可以为您的网站和应用程序添加一些魔法。然而,与所有强大的工具一样,需要花费一些时间才能熟悉它,并明智地利用它的全部潜力。但是,Modernizr 绝对值得付出努力。

关于 Jeremie Patonnier

Jeremie 是 Mozilla 开发者网络的长期贡献者/员工,从 2000 年开始担任专业网页开发者。他倡导网页标准,编写文档,并创建各种关于网页技术的内容,以期让所有人都能访问这些内容。

Jeremie Patonnier 撰写的更多文章…


16 条评论

  1. Skoua

    这篇文章比 Modernizr 文档清晰得多!
    谢谢!

    2012 年 7 月 17 日 下午 08:22

    1. Jeremie Patonnier

      不用谢 :) 但是,Modernizr 文档更完整;)

      2012 年 7 月 17 日 下午 14:34

  2. Vlad

    Modernizr 非常棒,您的文章确实非常清晰。现在我鼓励每个人使用它。

    2012 年 7 月 18 日 上午 06:10

  3. Federico Brigante

    我认为您的用法不正确…也许,这取决于我们如何处理问题。

    理想情况下,网站应该可以在不需要 JavaScript 的情况下运行,为什么我们要依赖一个脚本(它可能无法加载或执行)来应用基本样式?

    除了您在“限制和注意事项”下建议的直接覆盖属性的快速修复方法之外,还可以使用以下方法进行渐进增强

    div { /* no rgba, default, no js required */
        background : #333;
    }
    
    .rgba div { /* with rgba, requires js */
        background : rgba(0,0,0,.8);
    }
    

    但是!如何做相反的事情?

    div { /* let's presume rgba is supported */
        background : rgba(0,0,0,.8);
    }
    
    .no-rgba div { /* if it isn't, fix it with javascript (Modernizr) */
        background : #333;
    }
    

    这基本上与 polyfill 的工作方式相同,它们依赖于 JavaScript 来“修复”旧浏览器。我们已经在 oldIE 中依赖于 html5shim 来启用 HTML5 元素的样式,因此我认为我们应该对 CSS 功能使用相同的方法。

    2012 年 7 月 18 日 下午 16:55

    1. Jeremie Patonnier

      网站应该可以在不需要 JavaScript 的情况下运行

      我非常同意 :)

      为什么我们要依赖一个脚本(它可能无法加载或执行)来应用基本样式?

      我们不应该这样做,这就是我在“限制和注意事项”下展示了 CSS 级联的简单用法作为最佳实践的原因

      如何做相反的事情?

      div { /* 假设 rgba 受支持 */
      background : rgba(0,0,0,.8);
      }

      .no-rgba div { /* 如果不支持,则使用 JavaScript(Modernizr)修复它 */
      background : #333;
      }

      这里的问题是,如果由于某种原因浏览器不支持 RGBa 并且脚本无法运行(并且脚本无法运行有很多原因),您的网站将无法正常运行(根本没有背景)。当您以另一种方式执行此操作时,您将永远不会遇到此问题。但是,当我们谈论 CSS 时,始终更安全地尽可能多地依赖级联来处理浏览器中缺少 CSS 支持的问题。

      这基本上与 polyfill 的工作方式相同,它们依赖于 JavaScript 来“修复”旧浏览器。

      是的,但我们应该始终注意 polyfill。使用 polyfill 从来不是一个安全的选择,而且重要的是要始终检查我们用 polyfill 模拟的东西,如果 polyfill 不起作用,它永远不会严重破坏用户体验。网络是一个非常狂野的地方,因此处理未知情况非常重要,这需要在编码时保持高度自律。Polyfill 不是魔法,它只是一个对流血伤口的补丁。

      2012 年 7 月 19 日 下午 2:04

      1. Federico Brigante

        让我们坦诚地说,如果你使用高级功能,你的网站在没有 javascript 的情况下某些浏览器(例如使用 html5shim 的 IE8-)中崩溃。

        我的意思是,既然我们已经在老 IE 中依赖 JS,那么让我们只在这些浏览器中依赖 JS,而不是在新浏览器中。因此,使用支持 javascript 的“.no-feature”来填充功能,而不是在现代浏览器中使用“.feature”。

        公平地说,要偏爱那些最新的人(因此,偏爱未来的用户),而不是那些不最新的人(希望他们很快就会消失)。

        2012 年 7 月 22 日 下午 2:19

        1. Jeremie Patonnier

          是的,我同意你的看法。

          我们将依靠 JS 来使我们的网站正常运行。但即使在现代浏览器中,假设 JS 始终按预期工作也是一种流程设计。它不会。有很多原因导致这种情况。

          网络问题阻止脚本正确加载
          脚本本身的错误
          与第三方脚本冲突
          与浏览器扩展冲突
          以及更多我无法想象的;)

          因此,即使在现代浏览器中,也有一些情况会导致你的网站或应用程序崩溃。但这并不意味着我们应该尽一切努力让我们的应用程序在没有 JavaScript 的情况下正常工作。不,这仅仅意味着我们必须处理错误,在某些情况下(并非所有情况下),这种错误处理就是找到一种方法来执行与 JavaScript 相同的操作,但无需使用它。

          这里的问题是,没有一个单一的答案。每个人都必须根据自己的项目背景找到自己的答案。

          2012 年 7 月 22 日 下午 2:44

  4. Paul Miller

    Frederico、Jeremie,我认为你们俩都部分正确。当我构建一个网站时,我希望使用尽可能少的 js 脚本。正确使用 CSS 可以解决我们 90% 的支持问题,只要我们级联得当。但是,对于那 10% 可能甚至不是 CSS 相关问题,而且通常,涉及 HTML5 功能的时候,polyfill 可能完全有必要。

    我认为背景颜色示例不是一个好的选择来论证这一点。如果你想在不支持 RGBa 的旧浏览器中使用纯色,而在支持 RGBa 的新浏览器中使用透明颜色,你只需这样做

    div {
    background-color: #333;
    background-color: rgba(0,0,0,.8);
    }

    或者,如果你要对这些进行疯狂的处理,创建一个重复规则(为了 ie7 或 ie6 的缘故

    div {
    background-color: #333;
    color: #FFA500;
    }

    div {
    background-color: rgba(0,0,0,.8);
    color: rgba(255,255,0,.5);
    }

    所有 css;无需使用 js。

    2012 年 7 月 19 日 下午 10:14

    1. Federico Brigante

      显然,rgba 问题可以用(也应该)在没有 Modernizr 的情况下解决,但很多其他问题不行(因此 Modernizr 存在并流行),所以只需用“<大多数 Modernizr 支持的功能>”替换“rgba”(例如 transforms?),我的解决方案应该仍然有效。

      2012 年 7 月 22 日 下午 2:22

  5. Jhon St

    每个人都应该像你一样写文章,直截了当,用简单而不做作的语言,没有多余的额外内容,并用简单的例子来理解这个想法。谢谢。

    2012 年 7 月 20 日 下午 4:10

  6. ionut popa

    大家好,
    我认为 rgba 问题也可以通过这种方式处理,而无需使用 javascript。

    div {
    background : #333;
    background : rgba(0,0,0,.8); // 不理解此属性的浏览器会跳过它
    }

    另外,在 JS 中处理 css 前缀属性的用例是什么?通常从 javascript 中,我们为 html 元素应用/切换一个类,而不是添加属性。(Modernizr.prefixed(“transition”))

    2012 年 8 月 28 日 上午 8:24

    1. Jeremie Patonnier

      “通常从 javascript 中,我们为 html 元素应用/切换一个类,而不是添加属性。”

      你说得对,这绝对是最佳实践。

      2012 年 8 月 28 日 下午 3:01

  7. 紫色叶子

    这听起来难以置信。

    这是一项非常特殊的工作,需要检查每一个可能性。
    但这绝对值得。例如,html5/css3 中的 rgba 功能非常棒。因此,我会测试 rgba 是否存在,如果不存在,我就会使用 jquery animate?这应该没问题,对吧?

    问候

    2012 年 11 月 2 日 上午 9:56

  8. 托马斯

    渐进增强和优雅降级 -

    渐进增强和优雅降级不是同一个硬币的两面吗?

    我认为,如果我没说错的话,渐进增强是一种模式,优雅降级是另一种模式。例如,参见维基百科上的内容

    http://en.wikipedia.org/wiki/Progressive_enhancement

    我认为你需要在某个地方重新编写一下,抱歉说出这句话。
    : )

    我的意思是建设性的,我们有时都会犯错误。也许是我错了。

    问候;)

    2012 年 11 月 11 日 下午 2:55

    1. Jeremie Patonnier

      嗨!

      嗯,恕我直言,在我看来,在网页设计中,渐进增强和优雅降级是同一件事,只是视角不同。使用渐进增强,你可以为普通浏览器工作,并确保最先进的浏览器可以从最新的现代功能中获益;使用优雅降级,你可以为普通浏览器工作,并确保旧版浏览器可以渲染一些功能。因此,它始终是关于面向未来和向后兼容的……这是自网络诞生以来一直存在的故事;)

      对我来说,不可能在不进行优雅降级的情况下进行渐进增强,因为总会有一个旧版浏览器、一个普通浏览器和一个最先进的浏览器。更糟糕的是,在某些情况下,你所定义的普通浏览器在其他情况下可能是旧版浏览器或最先进的浏览器。因此,我不同意说这两种模式是不同的,它们是同一全局模式的两个部分。

      干杯 :)

      2012 年 11 月 11 日 下午 10:47

      1. 托马斯

        是的,但使用优雅降级,你并没有照顾到旧版浏览器。你针对新浏览器构建,并希望页面可以优雅地降级。

        使用渐进增强,你可以针对大多数浏览器构建,以确保页面可以很好地渲染。然后,你确保浏览器支持哪些功能以及不支持哪些功能。如果浏览器支持这些功能,就使用它们。

        所以,我相信它们在某种程度上是不同的。它们解决的是同一个问题。

        但我知道你的意思。如果我之前说得不清楚,我认为你的文章很好;)

        干杯 :)

        2012 年 12 月 5 日 上午 5:46

本文的评论已关闭。