工作遇到的浏览器兼容问题
1、JavaScript
1.1 兼容IE8
1、不要使用HTML5新标签如header、footer等
2、轮播使用的JQuery用低版本
1.2 360浏览器使用meta标签强制使用指定内核
目前国内主流浏览器多为双核浏览器,基于开发成本和效果考虑,兼容模式实在头疼。目前,360浏览器可以使用meta进行设置,强制使用指定内核打开页面,方法如下
<!-- content的取值为webkit,ie-comp,ie-stand之一,区分大小写,分别代表用webkit内核,IE兼容内核,IE标准内核。 -->
<meta name="renderer" content="webkit|ie-comp|ie-stand">
<!-- 用极速核 -->
<meta name="renderer" content="webkit">
<!-- ie兼容内核 -->
<meta name="renderer" content="ie-comp">
<!-- ie标准内核 -->
<meta name="renderer" content="ie-stand">
360浏览器文档:http://se.360.cn/v6/help/meta.html
- 渲染内核的技术细节
内核 | 内核版本 | HTML5支持 | ActiveX控件支持 |
---|---|---|---|
Webkit | Chrome 45 | YES | NO |
IE兼容 | IE6/7 | NO | YES |
IE标准 | IE9/IE10/IE11(取决于用户的IE) | YES | YES |
1.3 X-UA-Compatible定义IE浏览器的渲染方式
X-UA-Compatible是自从IE8新加的一个设置,对于IE8以下的浏览器是不识别的。通过在meta中设置X-UA-Compatible的值,可以指定网页的兼容性模式设置。
浏览器模式影响浏览器的行为表现以及声明的版本号。 文档模式影响DOM的转换、渲染操作,影响的是浏览器的外观表现,决定网页显示成什么样子的。
<!--告诉IE浏览器,无论是否用DTD声明文档标准,IE8/9都会以IE7引擎来渲染页面 -->
<meta http-equiv="X-UA-Compatible" content="IE=7" />
<!-- 告诉IE浏览器,IE8/9及以后的版本都会以最高版本IE来渲染页面 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- IE=edge 告诉IE使用最新引擎渲染页面 chrome=1可以激活Chrome Frame -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!--
如果存在客户端Chrome Frame并启用,那么浏览器访问页面会被Chrome内核渲染
使用IE内核浏览器来访问,会渲染至该浏览器的最高版本,比如你使用IE9浏览器,
那么就算在兼容模式切换至IE7,但仍会渲染成IE9的样子(当然IE7浏览器是不会渲染成IE9的,不然想想都好美丽)
-->
<!-- -->
Chrome Frame: Google的一个项目,在不改变IE的外观情况下使用Chrome内核,也就是说在电脑里安装了Chrome Frame chrome=1
才会生效, Google在2014年就已经不提供这个项目的支持服务了。
如果不想在html写X-UA-Compatible, 也可以在服务器里面配置。
1.3.1 Apache服务器设置X-UA-Compatible
可以在Apache主机做一些设置让服务器告诉IE采用何种引擎来渲染。在网站作用目录找到或新建.htaccess文件,添加下面的内容保存即可。
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
BrowserMatch MSIE ie
Header set X-UA-Compatible "IE=Edge" env=ie
BrowserMatch chromeframe gcf
Header append X-UA-Compatible "chrome=1" env=gcf
</IfModule>
</IfModule>
1.3.2 Nginx服务器设置X-UA-Compatible
找到\nginx\conf\nginx.conf
并编辑,在server { }区域里(最好是闭合符前面起一行)添加下列代码即可
add_header "X-UA-Compatible" "IE=Edge,chrome=1";
1.4 windows的navigator对象判断当前浏览器模式
Navigator 对象包含有关浏览器的信息。
http://www.w3school.com.cn/jsref/dom_obj_navigator.asp
function mode(){
if (window.navigator.userAgent.indexOf('compatible') != -1) {
alert('兼容模式');
}else if(window.navigator.userAgent.indexOf('AppleWebKit') != -1) { alert('极速模式浏览'); }
}
1.5 IE9兼容
1.5.1 XMLHttpRequest().open("GET", url, true);拒绝访问
针对 拒绝访问 是由于浏览器安全机制导致的,解决方法为点击IE浏览器的的“工具->Internet 选项->安全->自定义级别”将“其他”选项中的“通过域访问数据源”选中为“启用”
设置了浏览器的安全设置axios、angular的$http以及原生XMLHttpRequest请求都可以成功请求,jq的话还是需要设置jQuery.support.cors = true;才可以请求
https://www.zhihu.com/question/269574277
1.5.2 手动给dom添加classList
在IE9中 使用dom操作类样式document.querySelector(".header").classList
报错,经查找在IE9中没有classList,可手动实现一个:
// 给不支持classList的浏览器(ie9以及以下等)的元素添加classList属性
if (!("classList" in document.documentElement)) {
Object.defineProperty(HTMLElement.prototype, "classList", {
get: function() {
var self = this;
function update(fn) {
return function(value) {
var classes = self.className.split(/\s+/g),
index = classes.indexOf(value);
fn(classes, index, value);
self.className = classes.join(" ");
};
}
return {
add: update(function(classes, index, value) { if (!~index) classes.push(value); }),
remove: update(function(classes, index) { if (~index) classes.splice(index, 1); }),
toggle: update(function(classes, index, value) {
if (~index) classes.splice(index, 1);
else classes.push(value);
}),
contains: function(value) {
return !!~self.className.split(/\s+/g).indexOf(value);
},
item: function(i) { return self.className.split(/\s+/g)[i] || null; }
};
}
});
}
https://blog.csdn.net/qq_18271353/article/details/53893664
1.6 edge浏览器自动给电话号加可以点击的链接
当做好的网页在edge浏览器打开的时候发现手机号是可以点击的链接,经过在网上查找资料,发现是微软在 IE 11以上会自动给手机号加上可以点击的链接,以便于有可以处理手机号的程序访问如Skype.
如果不想浏览器这么做,可以在HTML文件中head标签中添加一个meta标签:
<meta name="format-detection" content="telephone=no"/>
1.7 在IE环境使用axios,提示“Promise”未定义
在项目中使用axios,在一些主流浏览器中使用都没问题,但是在IE浏览器中却出错了,提示:Promise未定义。
原因:axios 使用了promise , 而使用的IE11中不支持promise
解决方案:
可以利用插件’es6-promise’的polyfill()方法来实现兼容,具体步骤如下:
npm install -g es6-promise
在使用axios方法之前,导入es6-promise,并调用 polyfill()方法,即:
import promise from 'es6-promise' ; promise.ployfill();
直接引用的文件
https://github.com/stefanpenner/es6-promise
在HTML文件中添加:
<!-- Minified version of `es6-promise-auto` below. --> <script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js"></script>
如果考虑速度,可以把上面的内容复制到HTML文件中。
可以es6-promise.js , 也可以用es6-promise.auto.js :es6-promise是个库而已,不会自动polyfill。要想自动polyfill那么就用es6-promise.auto。
参考资料:
http://bugshouji.com/bbs-read-run?tid=494
https://www.jianshu.com/p/3c0359285d77
https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js
:!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.ES6Promise=e()}(this,function(){"use strict";function t(t){var e=typeof t;return null!==t&&("object"===e||"function"===e)}function e(t){return"function"==typeof t}function n(t){B=t}function r(t){G=t}function o(){return function(){return process.nextTick(a)}}function i(){return"undefined"!=typeof z?function(){z(a)}:c()}function s(){var t=0,e=new J(a),n=document.createTextNode("");return e.observe(n,{characterData:!0}),function(){n.data=t=++t%2}}function u(){var t=new MessageChannel;return t.port1.onmessage=a,function(){return t.port2.postMessage(0)}}function c(){var t=setTimeout;return function(){return t(a,1)}}function a(){for(var t=0;t<W;t+=2){var e=V[t],n=V[t+1];e(n),V[t]=void 0,V[t+1]=void 0}W=0}function f(){try{var t=Function("return this")().require("vertx");return z=t.runOnLoop||t.runOnContext,i()}catch(e){return c()}}function l(t,e){var n=this,r=new this.constructor(p);void 0===r[Z]&&O(r);var o=n._state;if(o){var i=arguments[o-1];G(function(){return P(o,r,i,n._result)})}else E(n,r,t,e);return r}function h(t){var e=this;if(t&&"object"==typeof t&&t.constructor===e)return t;var n=new e(p);return g(n,t),n}function p(){}function v(){return new TypeError("You cannot resolve a promise with itself")}function d(){return new TypeError("A promises callback cannot return that same promise.")}function _(t){try{return t.then}catch(e){return nt.error=e,nt}}function y(t,e,n,r){try{t.call(e,n,r)}catch(o){return o}}function m(t,e,n){G(function(t){var r=!1,o=y(n,e,function(n){r||(r=!0,e!==n?g(t,n):S(t,n))},function(e){r||(r=!0,j(t,e))},"Settle: "+(t._label||" unknown promise"));!r&&o&&(r=!0,j(t,o))},t)}function b(t,e){e._state===tt?S(t,e._result):e._state===et?j(t,e._result):E(e,void 0,function(e){return g(t,e)},function(e){return j(t,e)})}function w(t,n,r){n.constructor===t.constructor&&r===l&&n.constructor.resolve===h?b(t,n):r===nt?(j(t,nt.error),nt.error=null):void 0===r?S(t,n):e(r)?m(t,n,r):S(t,n)}function g(e,n){e===n?j(e,v()):t(n)?w(e,n,_(n)):S(e,n)}function A(t){t._onerror&&t._onerror(t._result),T(t)}function S(t,e){t._state===$&&(t._result=e,t._state=tt,0!==t._subscribers.length&&G(T,t))}function j(t,e){t._state===$&&(t._state=et,t._result=e,G(A,t))}function E(t,e,n,r){var o=t._subscribers,i=o.length;t._onerror=null,o[i]=e,o[i+tt]=n,o[i+et]=r,0===i&&t._state&&G(T,t)}function T(t){var e=t._subscribers,n=t._state;if(0!==e.length){for(var r=void 0,o=void 0,i=t._result,s=0;s<e.length;s+=3)r=e[s],o=e[s+n],r?P(n,r,o,i):o(i);t._subscribers.length=0}}function M(t,e){try{return t(e)}catch(n){return nt.error=n,nt}}function P(t,n,r,o){var i=e(r),s=void 0,u=void 0,c=void 0,a=void 0;if(i){if(s=M(r,o),s===nt?(a=!0,u=s.error,s.error=null):c=!0,n===s)return void j(n,d())}else s=o,c=!0;n._state!==$||(i&&c?g(n,s):a?j(n,u):t===tt?S(n,s):t===et&&j(n,s))}function x(t,e){try{e(function(e){g(t,e)},function(e){j(t,e)})}catch(n){j(t,n)}}function C(){return rt++}function O(t){t[Z]=rt++,t._state=void 0,t._result=void 0,t._subscribers=[]}function k(){return new Error("Array Methods must be provided an Array")}function F(t){return new ot(this,t).promise}function Y(t){var e=this;return new e(U(t)?function(n,r){for(var o=t.length,i=0;i<o;i++)e.resolve(t[i]).then(n,r)}:function(t,e){return e(new TypeError("You must pass an array to race."))})}function q(t){var e=this,n=new e(p);return j(n,t),n}function D(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function K(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function L(){var t=void 0;if("undefined"!=typeof global)t=global;else if("undefined"!=typeof self)t=self;else try{t=Function("return this")()}catch(e){throw new Error("polyfill failed because global object is unavailable in this environment")}var n=t.Promise;if(n){var r=null;try{r=Object.prototype.toString.call(n.resolve())}catch(e){}if("[object Promise]"===r&&!n.cast)return}t.Promise=it}var N=void 0;N=Array.isArray?Array.isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)};var U=N,W=0,z=void 0,B=void 0,G=function(t,e){V[W]=t,V[W+1]=e,W+=2,2===W&&(B?B(a):X())},H="undefined"!=typeof window?window:void 0,I=H||{},J=I.MutationObserver||I.WebKitMutationObserver,Q="undefined"==typeof self&&"undefined"!=typeof process&&"[object process]"==={}.toString.call(process),R="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,V=new Array(1e3),X=void 0;X=Q?o():J?s():R?u():void 0===H&&"function"==typeof require?f():c();var Z=Math.random().toString(36).substring(2),$=void 0,tt=1,et=2,nt={error:null},rt=0,ot=function(){function t(t,e){this._instanceConstructor=t,this.promise=new t(p),this.promise[Z]||O(this.promise),U(e)?(this.length=e.length,this._remaining=e.length,this._result=new Array(this.length),0===this.length?S(this.promise,this._result):(this.length=this.length||0,this._enumerate(e),0===this._remaining&&S(this.promise,this._result))):j(this.promise,k())}return t.prototype._enumerate=function(t){for(var e=0;this._state===$&&e<t.length;e++)this._eachEntry(t[e],e)},t.prototype._eachEntry=function(t,e){var n=this._instanceConstructor,r=n.resolve;if(r===h){var o=_(t);if(o===l&&t._state!==$)this._settledAt(t._state,e,t._result);else if("function"!=typeof o)this._remaining--,this._result[e]=t;else if(n===it){var i=new n(p);w(i,t,o),this._willSettleAt(i,e)}else this._willSettleAt(new n(function(e){return e(t)}),e)}else this._willSettleAt(r(t),e)},t.prototype._settledAt=function(t,e,n){var r=this.promise;r._state===$&&(this._remaining--,t===et?j(r,n):this._result[e]=n),0===this._remaining&&S(r,this._result)},t.prototype._willSettleAt=function(t,e){var n=this;E(t,void 0,function(t){return n._settledAt(tt,e,t)},function(t){return n._settledAt(et,e,t)})},t}(),it=function(){function t(e){this[Z]=C(),this._result=this._state=void 0,this._subscribers=[],p!==e&&("function"!=typeof e&&D(),this instanceof t?x(this,e):K())}return t.prototype["catch"]=function(t){return this.then(null,t)},t.prototype["finally"]=function(t){var n=this,r=n.constructor;return e(t)?n.then(function(e){return r.resolve(t()).then(function(){return e})},function(e){return r.resolve(t()).then(function(){throw e})}):n.then(t,t)},t}();return it.prototype.then=l,it.all=F,it.race=Y,it.resolve=h,it.reject=q,it._setScheduler=n,it._setAsap=r,it._asap=G,it.polyfill=L,it.Promise=it,it.polyfill(),it});
1.8. 解决IE浏览器不识别location.origin 的问题
if (!window.location.origin) {
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
}
2、CSS
2.1 css3 新属性transform
transform 的四个rotate、scale、skew和translate属性,
目前支持的浏览器 Safari 3.1+、 Chrome 8+、Firefox 4+、Opera 10+、IE9+;
transform: rotate(45deg) scale(1.5) translate(150px, 200px);
/* for Chrome || Safari */
-webkit-transform: rotate(45deg) scale(1.5) translate(150px, 200px);
/* for Firefox */
-moz-transform: rotate(45deg) scale(1.5) translate(150px, 200px);
/* for IE */
-ms-transform: rotate(45deg) scale(1.5) translate(150px, 200px);
/* for Opera */
-o-transform: rotate(45deg) scale(1.5) translate(150px, 200px);
https://blog.csdn.net/teresa502/article/details/8207198
2.2 IE9下 a标签里面有图片,去掉蓝色边框
// 在IE下去掉蓝色边框
a {
text-decoration: none;
}
img {
vertical-align: middle;
width: 273px;
height: 32px;
border: none; // 在IE下去掉蓝色边框
}
参考资料
<!DOCTYPE HTML>
<!--[if !IE]><!--><html lang="zh-cn"><!--<![endif]-->
<!--[if gt IE 9]><html class="ie10" lang="zh-cn"><![endif]-->
<!--[if IE 9]><html class="ie9 lte9" lang="zh-cn"><![endif]-->