跨平台的浏览器尽管版本相同,但总会存在不同的问题,作为一名合格的前端开发,我们需要面向最大公约数来设计,就得使用各种方法来检测客户端,以克服或避免这些缺陷。
我们的宗旨是:第一,绝对不意气用事;第二,绝对不漏过任何一个浏览器;第三,绝对保证浏览器公正漂亮。
任何时候,只要有更普适的方案可选,都应该毫不犹豫地选择。首先要设计最常用的方案,然后再考虑为特定的浏览器进行补救。
能力检测
能力检测(又称特性检测)即在 JavaScript 运行时中使用一套简单的检测逻辑,测试浏览器是否支持某种特性。
if (object.propertyInQuestion) {
// 使用 object.propertyInQuestion
}
1、安全能力检测
能力检测最有效的场景是检测能力是否存在的同时,验证其是否能够展现出预期的行为。
举个🌰:下面这个函数尝试检测某个对象是否可以排序
// 不要这样做!错误的能力检测,只能检测到能力是否存在
function isSortable(object) {
return !!object.sort;
}
简单地测试到一个属性存在并不代表这个对象就可以排序。更好的方式是检测 sort 是不是函数:
// 好一些,检测 sort 是不是函数
function isSortable(object) {
return typeof object.sort == "function";
}
上面的代码中使用的 typeof
操作符可以确定 sort 是不是函数,从而确认是否可以调用它对数据进行排序。
2、基于能力检测进行浏览器分析
检测特性
场景:可以按照能力将浏览器归类。
// 检测浏览器是否支持 Netscape 式的插件
let hasNSPlugins = !!(navigator.plugins && navigator.plugins.length);
// 检测浏览器是否具有 DOM Level 1 能力
let hasDOM1 = !!(document.getElementById && document.createElement &&
document.getElementsByTagName);
检测浏览器
场景:可以根据对浏览器特性的检测并与已知特性对比,确认用户使用的是什么浏览器。
优点:比用户代码嗅探(稍后讨论)更准确的结果。
缺点:未来的浏览器版本可能不适用于这套方案。
未来的浏览器版本可能不适用于这套方案
通过检测一种或一组能力,并不总能确定使用的是哪种浏览器。能力检测最适合用于决定下一步该怎么做,而不一定能够作为辨识浏览器的标志。
用户代理检测
用户代理检测通过浏览器的用户代理字符串确定使用的是什么浏览器。用户代理字符串包含在每个
HTTP 请求的头部,在 JavaScript 中可以通过 navigator.userAgent 访问。
浏览器分析
想要知道自己代码运行在什么浏览器上,大部分开发者会分析 window.navigator.userAgent
返回的字符串值。
伪造用户代理
通过检测用户代理来识别浏览器并不是完美的方式,毕竟这个字符串是可以造假的。只不过实现window.navigator
对象的浏览器(即所有现代浏览器)都会提供 userAgent
这个只读属性。
对付这种造假是一件吃力不讨好的事。检测用户代理是否以这种方式被篡改过是可能的,但总体来看还是一场猫捉老鼠的游戏。
分析浏览器
- 浏览器
- 浏览器版本
- 浏览器渲染引擎
- 设备类型(桌面/移动)
- 设备生产商
- 设备型号
- 操作系统
- 操作系统版本
软件与硬件检测
现代浏览器提供了一组与页面执行环境相关的信息,包括浏览器、操作系统、硬件和周边设备信息。这些属性可以通过暴露在
window.navigator
上的一组 API 获得。不过,这些 API 的跨浏览器支持还不够好,远未达到标准化的程度。
1、识别浏览器与操作系统
navigator
和 screen
对象也提供了关于页面所在软件环境的信息。
navigator.oscpu
navigator.oscpu属性是一个字符串,通常对应用户代理字符串中操作系统/系统架构相关信息。
navigator.vendor
navigator.vendor属性是一个字符串,通常包含浏览器开发商信息。返回这个字符串是浏览器navigator兼容模式的一个功能。
navigator.platform
navigator.platform 属性是一个字符串,通常表示浏览器所在的操作系统。
screen.colorDepth 和 screen.pixelDepth
screen.colorDepth 和 screen.pixelDepth 返回一样的值,即显示器每像素颜色的位深
screen.orientation
screen.orientation 属性返回一个 ScreenOrientation 对象,其中包含 Screen Orientation API
定义的屏幕信息。
2、浏览器元数据
navigator
对象暴露出一些 API,可以提供浏览器和操作系统的状态信息。
Geolocation API
navigator.geolocation 属性暴露了 Geolocation API,可以让浏览器脚本感知当前设备的地理位
置。
注意⚠️:这个 API 只在安全执行环境(通过 HTTPS 获取的脚本)中可用。
Connection State 和 NetworkInformation API
浏览器会跟踪网络连接状态并以两种方式暴露这些信息:连接事件和 navigator.onLine 属性。
相应地,当设备断开网络连接后,浏览器会在 window 对象上触发 offline 事件。
Battery Status API
浏览器可以访问设备电池及充电状态的信息。 navigator.getBattery()方法会返回一个期约实例,解决为一个 BatteryManager 对象
3、硬件
浏览器检测硬件的能力相当有限。不过, navigator
对象还是通过一些属性提供了基本信息。
处理器核心数
navigator.hardwareConcurrency 属性返回浏览器支持的逻辑处理器核心数量,包含表示核心
数的一个整数值(如果核心数无法确定,这个值就是 1)。
设备内存大小
navigator.deviceMemory 属性返回设备大致的系统内存大小,包含单位为 GB 的浮点数(舍入
为最接近的 2 的幂: 512MB 返回 0.5, 4GB 返回 4)。
最大触点数
navigator.maxTouchPoints 属性返回触摸屏支持的最大关联触点数量,包含一个整数值。
最后
在选择客户端检测方法时,首选是使用能力检测。特殊能力检测要放在次要位置,作为决定代码逻辑的参考。用户代理检测是最后一个选择,因为它过于依赖用户代理字符串。