[关闭]
@yangfch3 2015-11-28T19:19:21.000000Z 字数 5264 阅读 3872

Modernizr 初体验

JavaScript



新技术(标准)的尴尬

每一门新技术的出现都会为开发界注入新的活力,尤其是前端界这样日新月异的领域。

在迎接新技术与新标准的路上涌现了无数的尝鲜者,这些人有的成了高山,有的成了铺路石。拥抱新技术永远是开发者的第一选择,跟上时代的脚步是许多人的追求。

但是在前端界出现了许许多多的尴尬:不同内核的浏览器,不同的解析方式,不同的标准支持程度……以及每每提及便会难受一阵子的IE8-

但是这些尴尬的出现是历史的必然,因为时间永远不是倒着走的。我们无法像控制机器一样来控制所有的人一夜间升级到表现优良的现代浏览器。为了迎接新技术与新标准,前端开发者在与这些尴尬斗争的路上创造了许许多多杰作,这篇文章的主题 Modernizr 就是这样一个作品,他的出现为我们步入 CSS3HTML5 的世界提供了披荆斩棘的战甲。


HTML5 和 CSS3

HTML5CSS3WEB 开创了一篇新天地,但是旧版的非现代浏览器仍旧占据着一定的市场份额,而它们对 HTML5CSS3 的支持程度实在不敢恭维,但是这不能完全怪这些旧浏览器的生产厂商,因为他们诞生之时,HTML5CSS3 尚未正式推出。

我们要看到各个浏览器生产厂商也正在做着不懈的努力。chromeff 的升级大战,微软调转历史车头全新推出的 Edge ,各个厂商开始坐下来和和气气地商谈新 WEB 标准……

在我们能完全使用新标准(技术)之前,我们必须找到临时的方案——既是能很好地跟上新技术的步伐,同时也能让自己编码更加舒适——不能委屈自己。

jQuery 1.9 发布之前,jQuery内置了一个 jQuery.browser 函数来检测浏览器的版本,它根据 user agent 来返回浏览器的相关信息。我们可以根据结果得到用户浏览器版本,这样就像打一些补丁一样针对这些老的浏览器做一些 fallback 的工作。

可是 jQuery 1.9 发布的时候取消了这一 API (当然你可以使用 jQuery.migrate 插件),官方文档中解释为我们应该用检测 feature 的方案( jQuery.support )来判断我们需不需要 fallback,毕竟 user agent 伪造太容易了。比如 Chrome Mobile 版本则会加入 Safariuser agent,这也是为什么移动浏览器市场 Safari 雄踞第一的真正原因之一。

现在基本所有兼容性方案JS (类)库都是检测浏览器是否实现了某个 feature,如果实现了那么开发人员就可以充分利用这个 feature 做一些工作,反之没有实现开发人员也好提供一个 fallback

下面介绍本文的主角:Modernizr


关于 Modernizr

Modernizr 是兼容(类)库里的翘楚。从它获得的殊荣便可见一斑。

Modernizr 在 2010 和 2011 年均赢得了 .net Award for Open Source App of the Year ,要知道它的竞争对手都是像 WordpressDrupal 这些重量级选手。同时在2011年,它的首席开发者 Paul Irish 赢得了 Developer of the Year 大奖。


引入

Modernizr 内置了 html5shiv 类库,所以请在 <head> 中引入。

页面元素加载完再引入的缺点: FOUC——flash of unstyled content
(因为Modernizr会在检测 feature 后为文档动态添加 class ,所以许多 CSS 会在文档加载完后才加载,这就造成了部分元素短时间的两次不同渲染)

然后我们为我们的 html 标签添加 no-jsclass(类)。

现在我们在各个不同版本的不同浏览器下查看 htmlclass 的变化与差异。

以下为 chromeIE8htmlclass

  1. <html lang="en" class=" js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths">
  1. <html lang="en" class=" js no-flexbox no-flexboxlegacy no-canvas no-canvastext no-webgl no-touch no-geolocation postmessage no-websqldatabase no-indexeddb hashchange no-history draganddrop no-websockets no-rgba no-hsla no-multiplebgs no-backgroundsize no-borderimage no-borderradius no-boxshadow no-textshadow no-opacity no-cssanimations no-csscolumns no-cssgradients no-cssreflections no-csstransforms no-csstransforms3d no-csstransitions fontface generatedcontent no-video no-audio no-localstorage no-sessionstorage no-webworkers no-applicationcache no-svg no-inlinesvg no-smil no-svgclippaths">

原理:
1. Modernizr 运行检测浏览器的 feature 支持情况;
2. 检测完毕,将结果存储在各个 feature 检测对应的对象上;
3. 更新文档内 html 标签的 class,不支持的特性加前缀 no-
 (浏览器禁用了 JS,则 html 仍旧保持 no-js 的类名不变)
4. 开发者按需编写 CSS,按需 fallback

示例代码:

  1. <!DOCTYPE html>
  2. <html lang="en" class="no-js">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Index</title>
  6. <script src="./Modernizr-2.8.3/modernizr.js"></script>
  7. <style type="text/css">
  8. .test-para{
  9. line-height:24px;
  10. // 支持 touch 特性时加载这个样式
  11. }
  12. .no-touch .test-para{
  13. background-color:red;
  14. color:green;
  15. line-height:24px;
  16. // 不支持 touch 时加载这个样式
  17. }
  18. header{
  19. background-color:#ccc;
  20. line-height:24px;
  21. }
  22. nav{
  23. color:yellow;
  24. line-height:24px;
  25. }
  26. </style>
  27. </head>
  28. <body>
  29. <header>
  30. <div>
  31. Hey! 我是 header 里的灰色div。有了 Moderzinr,我在不支持 html5 新标签的旧版IE下也能正常显示了,因为 Modernizr 内置了 html5shiv。
  32. </div>
  33. <nav>
  34. Hey! 我是 header 里的黄色nav。有了 Moderzinr,我在不支持 html5 新标签的旧版IE下也能正常显示了,因为 Modernizr 内置了 html5shiv。
  35. </nav>
  36. </header>
  37. <p class="test-para">
  38. 当浏览器不支持 touch 新特性时,我会变为红底绿字!当浏览器支持 touch 新特性时,则是白底黑字。
  39. </p>
  40. </body>
  41. </html>

Browser Feature Test

引入了 Modernizr,我们便可以在我们的脚本里任意位置使用 Modernizr 提供的方法来浏览器是否支持某项特性,然后根据不同情况执行不同的代码

  1. // Modernizr.featuretodetect
  2. if(Modernizr.webgl){
  3. /* support WebGL */
  4. }
  5. else{
  6. /* not support WebGL */
  7. }
  8. // 一般格式
  9. if (Modernizr.awesomeNewFeature) {
  10. showOffAwesomeNewFeature();
  11. }
  12. else {
  13. getTheOldLameExperience();
  14. }

Modernizr.load()

基于 YepNope.jsModernizr.load() 方法根据一些条件判断来动态选择加载 CSSJavaScript,这无疑对避免不必要的资源加载有极大的帮助。

例如,我们常用的一个场景:

我们需要检测浏览器是否支持 WebGL,当浏览器支持 WebGL 的时候,就引入 three.js 这个类库做一些 3D 效果。浏览器不支持 WebGL 的时候可以使用 jebgl.js 做一些 fallback 操作。

  1. yepnope({
  2. test : Modernizr.geolocation,
  3. yep : 'normal.js',
  4. nope : ['polyfill.js', 'wrapper.js']
  5. });
  6. Modernizr.load(
  7. test: Modernizr.webgl,
  8. yep : 'three.js',
  9. nope: 'jebgl.js'
  10. );

相关资源: HTML5 Cross Browser Polyfills ——跨浏览器 HTML5 新特性解决方案

引入 jQuery 的常用写法:

  1. <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
  2. <script>window.jQuery || document.write('<script src="js/libs/jquery-1.7.1.min.js">\x3C/script>')</script>
  3. // 当 cdn 上的 jQuery 未能成功加载时便加载本地服务器上的 jQuery

使用 Modernizr.load() 的写法(见 yepnope.js 的写法):

  1. Modernizr.load([
  2. {
  3. load: '//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js',
  4. complete: function () {
  5. if ( !window.jQuery ) {
  6. Modernizr.load('js/libs/jquery-1.7.1.min.js');
  7. }
  8. }
  9. },
  10. {
  11. load: 'needs-jQuery.js'
  12. }
  13. ]);

测试了一下,需带 yepnope.jsModernizr 才能正常 load, 定制 Modernizr 时候有此选项, github 上直接拿的 Modernizr.js 不行。

yepnope 按需加载的写法:

  1. yepnope([{//yepnope 参数可以是 object,也可以是由多个 object 组成的 array
  2. // 本例参数为单个 object
  3. test : window.JSON,
  4. yep : 'yep.js',
  5. nope : ['./Modernizr-2.8.3/test/js/lib/polyfills.js', 'nope.js'],
  6. both : 'both.js',
  7. load : 'load.js',
  8. callback: function(){
  9. console.log("yepnope done!")
  10. // callback 会执行两次,yep nope 里的js文件也会请求两次,但对性能无多少影响
  11. // https://github.com/SlexAxton/yepnope.js/issues/10
  12. },
  13. complete: function(){
  14. console.log("yepnope completed!")
  15. },
  16. }]);
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注