@yangfch3
2015-11-28T19:19:21.000000Z
字数 5264
阅读 3836
JavaScript
每一门新技术的出现都会为开发界注入新的活力,尤其是前端界这样日新月异的领域。
在迎接新技术与新标准的路上涌现了无数的尝鲜者,这些人有的成了高山,有的成了铺路石。拥抱新技术永远是开发者的第一选择,跟上时代的脚步是许多人的追求。
但是在前端界出现了许许多多的尴尬:不同内核的浏览器,不同的解析方式,不同的标准支持程度……以及每每提及便会难受一阵子的IE8-
。
但是这些尴尬的出现是历史的必然,因为时间永远不是倒着走的。我们无法像控制机器一样来控制所有的人一夜间升级到表现优良的现代浏览器。为了迎接新技术与新标准,前端开发者在与这些尴尬斗争的路上创造了许许多多杰作,这篇文章的主题 Modernizr
就是这样一个作品,他的出现为我们步入 CSS3
和 HTML5
的世界提供了披荆斩棘的战甲。
HTML5
和 CSS3
为 WEB
开创了一篇新天地,但是旧版的非现代浏览器仍旧占据着一定的市场份额,而它们对 HTML5
和 CSS3
的支持程度实在不敢恭维,但是这不能完全怪这些旧浏览器的生产厂商,因为他们诞生之时,HTML5
和 CSS3
尚未正式推出。
我们要看到各个浏览器生产厂商也正在做着不懈的努力。chrome
与 ff
的升级大战,微软调转历史车头全新推出的 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
版本则会加入Safari
的user agent
,这也是为什么移动浏览器市场Safari
雄踞第一的真正原因之一。
现在基本所有兼容性方案的 JS
(类)库都是检测浏览器是否实现了某个 feature
,如果实现了那么开发人员就可以充分利用这个 feature
做一些工作,反之没有实现开发人员也好提供一个 fallback
。
下面介绍本文的主角:Modernizr
。
Modernizr
是兼容(类)库里的翘楚。从它获得的殊荣便可见一斑。
Modernizr
在 2010 和 2011 年均赢得了.net Award for Open Source App of the Year
,要知道它的竞争对手都是像Wordpress
、Drupal
这些重量级选手。同时在2011年,它的首席开发者Paul Irish
赢得了Developer of the Year
大奖。
Modernizr
:https://modernizr.com/download?setclassesModernizr
内置了 html5shiv
类库,所以请在 <head>
中引入。
页面元素加载完再引入的缺点: FOUC
——flash of unstyled content
。
(因为Modernizr
会在检测 feature
后为文档动态添加 class
,所以许多 CSS
会在文档加载完后才加载,这就造成了部分元素短时间的两次不同渲染)
然后我们为我们的 html
标签添加 no-js
的 class
(类)。
现在我们在各个不同版本的不同浏览器下查看 html
的 class
的变化与差异。
以下为 chrome
与 IE8
下 html
的 class
:
<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">
<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
。
示例代码:
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="UTF-8">
<title>Index</title>
<script src="./Modernizr-2.8.3/modernizr.js"></script>
<style type="text/css">
.test-para{
line-height:24px;
// 支持 touch 特性时加载这个样式
}
.no-touch .test-para{
background-color:red;
color:green;
line-height:24px;
// 不支持 touch 时加载这个样式
}
header{
background-color:#ccc;
line-height:24px;
}
nav{
color:yellow;
line-height:24px;
}
</style>
</head>
<body>
<header>
<div>
Hey! 我是 header 里的灰色div。有了 Moderzinr,我在不支持 html5 新标签的旧版IE下也能正常显示了,因为 Modernizr 内置了 html5shiv。
</div>
<nav>
Hey! 我是 header 里的黄色nav。有了 Moderzinr,我在不支持 html5 新标签的旧版IE下也能正常显示了,因为 Modernizr 内置了 html5shiv。
</nav>
</header>
<p class="test-para">
当浏览器不支持 touch 新特性时,我会变为红底绿字!当浏览器支持 touch 新特性时,则是白底黑字。
</p>
</body>
</html>
引入了 Modernizr
,我们便可以在我们的脚本里任意位置使用 Modernizr
提供的方法来浏览器是否支持某项特性,然后根据不同情况执行不同的代码。
// Modernizr.featuretodetect
if(Modernizr.webgl){
/* support WebGL */
}
else{
/* not support WebGL */
}
// 一般格式
if (Modernizr.awesomeNewFeature) {
showOffAwesomeNewFeature();
}
else {
getTheOldLameExperience();
}
基于 YepNope.js ,Modernizr.load()
方法根据一些条件判断来动态选择加载 CSS
和 JavaScript
,这无疑对避免不必要的资源加载有极大的帮助。
例如,我们常用的一个场景:
我们需要检测浏览器是否支持
WebGL
,当浏览器支持WebGL
的时候,就引入three.js
这个类库做一些3D
效果。浏览器不支持WebGL
的时候可以使用jebgl.js
做一些fallback
操作。
yepnope({
test : Modernizr.geolocation,
yep : 'normal.js',
nope : ['polyfill.js', 'wrapper.js']
});
Modernizr.load(
test: Modernizr.webgl,
yep : 'three.js',
nope: 'jebgl.js'
);
相关资源: HTML5 Cross Browser Polyfills ——跨浏览器 HTML5 新特性解决方案
引入 jQuery
的常用写法:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.7.1.min.js">\x3C/script>')</script>
// 当 cdn 上的 jQuery 未能成功加载时便加载本地服务器上的 jQuery
使用 Modernizr.load()
的写法(见 yepnope.js
的写法):
Modernizr.load([
{
load: '//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js',
complete: function () {
if ( !window.jQuery ) {
Modernizr.load('js/libs/jquery-1.7.1.min.js');
}
}
},
{
load: 'needs-jQuery.js'
}
]);
测试了一下,需带
yepnope.js
的Modernizr
才能正常load
, 定制Modernizr
时候有此选项,github
上直接拿的Modernizr.js
不行。
yepnope
按需加载的写法:
yepnope([{//yepnope 参数可以是 object,也可以是由多个 object 组成的 array
// 本例参数为单个 object
test : window.JSON,
yep : 'yep.js',
nope : ['./Modernizr-2.8.3/test/js/lib/polyfills.js', 'nope.js'],
both : 'both.js',
load : 'load.js',
callback: function(){
console.log("yepnope done!")
// callback 会执行两次,yep nope 里的js文件也会请求两次,但对性能无多少影响
// https://github.com/SlexAxton/yepnope.js/issues/10
},
complete: function(){
console.log("yepnope completed!")
},
}]);