兼容性

前端兼容性与跨浏览器适配

浏览器版本监控

Modernizr 是一个开源的 JS 库,它使得那些基于访客浏览器的不同(指对新标准支持性的差异)而开发不同级别体验的设计师的工作变得更为简单。它使得设计师可以在支持HTML5和 CSS3 的浏览器中充分利用HTML5和 CSS3 的特性进行开发,同时又不会牺牲其他不支持这些新技术的浏览器的控制。

当你在网页中嵌入 Modernizr 的脚本时,它会检测当前浏览器是否支持 CSS3 的特性,比如@font-face、border-radius、 border-image、box-shadow、rgba()  等,同时也会检测是否支持HTML5的 特性——比如 audio、video、本地储存、和新的标签的类型和属性等。在获取到这些信息的基础上,你可以在那些支持这些功能的浏览器上使用它们,来决定是否创建一个基于 JS 的 fallback,或者对那些不支持的浏览器进行简单的优雅降级。另外,Modernizr 还可以令 IE 支持对HTML5的元素应用 CSS 样式,这样开发者就可以立即使用这些更富有语义化的标签了。

if (browser === "the-one-they-make-you-use-at-work") {
  getTheOldLameExperience();
} else {
  showOffAwesomeNewFeature();
}

改为了:

if (Modernizr.awesomeNewFeature) {
  showOffAwesomeNewFeature();
} else {
  getTheOldLameExperience();
}

IE 版本限定

IE,特别是 IE8,简直是阻止前端框架推广与发展的一大限制。x-ua-compatible 用来指定 IE 浏览器解析编译页面的 model。x-ua-compatible 头标签大小写不敏感,必须用在 head 中,必须在除 title 外的其他 meta 之前使用。

  • 使用一行代码来指定浏览器使用特定的文档模式。
<meta http-equiv="x-ua-compatible" content="IE=9" />
<meta http-equiv="x-ua-compatible" content="IE=8" />
<meta http-equiv="x-ua-compatible" content="IE=7" />
  • 在一些情况下,我们需要限定浏览器对文档的解析到某一特定版本,或者将浏览器限定到一些旧版本的表现中。可以用如下的方式:
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" />
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE8" />
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE7" />

使用这种写法,浏览器或者使用标准模式进行解析,或者使用 IE5 Quirks 模式进行解析。

  • 为了测试,我们也可以使用下面的语句指定浏览器按照最高的标准模式解析页面。
<meta http-equiv="x-ua-compatible" content="IE=edge" />
  • 多个模式的指定。我们可以用逗号分割多个版本,这种情况下,浏览器会从这个列表中选择一个他所支持的最高版本来使用标准模式进行渲染。如下面的例子,在 IE8 进行浏览时,将会使用 IE7 的标准模式进行渲染,因为他本身不支持 IE9 和 IE10。
<meta http-equiv="x-ua-compatible" content="IE=7,9,10" />

Polyfill

shim 的意思是在一个老(旧)环境中模拟出一个新 API,有时也叫做 shiv,例如著名的 html5shiv 库。polyfill 的意思和 shim 差不多,2010 年 10 月份 Remy Sharp 引进了这个概念,一个 polyfill 是一段代码或插件,用来提供浏览器不能提供的功能。程序库先检查浏览器是否支持某个 API,如果不支持则加载对应的 polyfill。

polyfill 这个词最早来自居室装修领域,是一个英国产品,在美国称为 Spackling Paste(刮墙用的,Spackle 是美国抹墙粉的一个品牌。在中国称为腻子或填泥,腻子英文是 putty,而填泥英文是 filler)。可以这样理解:把旧的浏览器想象成一面有了裂痕的墙,这些 polyfill 会帮助我们把这面墙的裂痕抹平,桓我们一个光滑的墙壁。shim 的概念要比 polyfill 更大一些,可以将 polyfill 理解为专门兼容浏览器 API 的 shim。

Remy 这样帮我们理解 polyfill:如果浏览器 X 支持标准规定的功能,那么 polyfill 可以让浏览器 Y 的行为与浏览器 X 一样。

Polyfill.io

Polyfill 可以为旧浏览器提供和标准 API 一样的功能。比如你想要 IE 浏览器实现 Promise 和 fetch 功能,你需要手动引入 es6-promise、whatwg-fetch。而通过 Polyfill.io,你只需要引入一个 JS 文件。

<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>

Polyfill.io 通过分析请求头信息中的 UserAgent 实现自动加载浏览器所需的 polyfills。Polyfill.io 有一份默认功能列表,包括了最常见的 polyfills:document.querySelector、Element.classList、ES5 新增的 Array 方法、Date.now、ES6 中的 Object.assign、Promise 等。

Polyfill.io 同样允许我们进行异步加载:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <script
      src="https://cdn.polyfill.io/v2/polyfill.min.js?callback=main"
      async
      defer
    ></script>
    <script>
      function main() {
        var node = document.createElement("script");
        node.src = "index.js";
        document.body.appendChild(node);
      }
    </script>
  </head>
  <body></body>
</html>

DOM

if (!document.querySelectorAll) {
  document.querySelectorAll = function (selectors) {
    var style = document.createElement("style"),
      elements = [],
      element;
    document.documentElement.firstChild.appendChild(style);
    document._qsa = [];

    style.styleSheet.cssText =
      selectors +
      "{x-qsa:expression(document._qsa && document._qsa.push(this))}";
    window.scrollBy(0, 0);
    style.parentNode.removeChild(style);

    while (document._qsa.length) {
      element = document._qsa.shift();
      element.style.removeAttribute("x-qsa");
      elements.push(element);
    }
    document._qsa = null;
    return elements;
  };
}

if (!document.querySelector) {
  document.querySelector = function (selectors) {
    var elements = document.querySelectorAll(selectors);
    return elements.length ? elements[0] : null;
  };
}

优雅降级与渐进增强

渐进增强是指针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。优雅降级则是反其道行之,一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

优雅降级和渐进增强印象中是随着 css3 流出来的一个概念。由于低级浏览器不支持 css3,但 css3 的效果又太优秀不忍放弃,所以在高级浏览中使用 css3 而低级浏览器只保证最基本的功能。咋一看两个概念差不多,都是在关注不同浏览器下的不同体验,关键的区别是他们所侧重的内容,以及这种不同造成的工作流程的差异。

渐进增强 progressive enhancement:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。  优雅降级 graceful degradation:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

区别:优雅降级是从复杂的现状开始,并试图减少用户体验的供给,而渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要。降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带。 “优雅降级”观点认为应该针对那些最高级、最完善的浏览器来设计网站。而将那些被认为“过时”或有功能缺失的浏览器下的测试工作安排在开发周期的最后阶段,并把测试对象限定为主流浏览器(如 IE、Mozilla 等)的前一个版本。

在这种设计范例下,旧版的浏览器被认为仅能提供“简陋却无妨 (poor, but passable)” 的浏览体验。你可以做一些小的调整来适应某个特定的浏览器。但由于它们并非我们所关注的焦点,因此除了修复较大的错误之外,其它的差异将被直接忽略。 “渐进增强”观点则认为应关注于内容本身。

内容是我们建立网站的诱因。有的网站展示它,有的则收集它,有的寻求,有的操作,还有的网站甚至会包含以上的种种,但相同点是它们全都涉及到内容。这使得“渐进增强”成为一种更为合理的设计范例。这也是它立即被 Yahoo! 所采纳并用以构建其“分级式浏览器支持 (Graded Browser Support)”策略的原因所在。

下一页