浏览器原理 · 10/51
1. addEventListener 第三个参数 2. addEventListener 与 attachEvent 区别 3. 浏览器兼容性测试与内核 4. 浏览器兼容性问题 5. 浏览器内核与引擎 6. 浏览器图层创建条件 7. 浏览器多进程架构 8. 浏览器渲染机制 9. 浏览器存储方案 10. 浏览器版本检测方法 11. children 与 childNodes 区别 12. 常见浏览器兼容性问题 13. Chrome 页面进程数量 14. 坐标系统对比 15. 多标签页通讯方案 16. 删除 Cookie 17. 自定义事件 18. DOM 事件处理方式演进 19. 元素尺寸属性对比 20. DOM 节点操作 21. DOM 事件机制 22. addEventListener 与 attachEvent 的区别 23. 获取页面所有复选框 24. HTMLCollection 与 NodeList 区别 25. Hybrid 应用开发 26. 强缓存命中机制 27. 浏览器缓存机制 28. 页面编码与资源编码不一致处理 29. jQuery 事件绑定方法对比 30. Input 点击触发的事件顺序 31. JavaScript 浏览器兼容性问题 32. jQuery 多事件绑定实现 33. JSBridge 原理 34. 链接点击后 Hover 失效解决方案 35. 减少重绘和回流的性能优化 36. 移动端 300ms 点击延迟问题 37. 移动端视口配置 38. 移动端点击穿透问题解决 39. 移动端兼容性问题 40. JSBridge 原理与实现 41. 移动端 1px 像素问题解决方案 42. 浏览器渲染流程 43. 页面加载完成事件对比 44. Offset、Scroll、Client 属性对比 45. 同源策略与跨域解决方案 46. Script 标签位置对页面加载的影响 47. Service Worker 与 PWA 48. 存储方案对比:Cookie、Storage、IndexedDB 49. 强缓存默认时间 50. URL 到页面显示的完整过程 51. V8 引擎 JavaScript 执行过程

浏览器版本检测方法

使用 User-Agent 解析和特性检测识别浏览器版本

问题

检测浏览器版本有哪些方式?

解答

1. User-Agent 字符串解析

// 获取 User-Agent 字符串
const ua = navigator.userAgent;

// 检测常见浏览器
function getBrowserInfo() {
  const ua = navigator.userAgent;
  
  // Chrome (需要排除 Edge 和 Opera)
  if (/Chrome/.test(ua) && !/Edg|OPR/.test(ua)) {
    const match = ua.match(/Chrome\/(\d+)/);
    return { name: 'Chrome', version: match ? match[1] : 'unknown' };
  }
  
  // Firefox
  if (/Firefox/.test(ua)) {
    const match = ua.match(/Firefox\/(\d+)/);
    return { name: 'Firefox', version: match ? match[1] : 'unknown' };
  }
  
  // Safari (需要排除 Chrome)
  if (/Safari/.test(ua) && !/Chrome/.test(ua)) {
    const match = ua.match(/Version\/(\d+)/);
    return { name: 'Safari', version: match ? match[1] : 'unknown' };
  }
  
  // Edge (Chromium 内核)
  if (/Edg/.test(ua)) {
    const match = ua.match(/Edg\/(\d+)/);
    return { name: 'Edge', version: match ? match[1] : 'unknown' };
  }
  
  return { name: 'unknown', version: 'unknown' };
}

console.log(getBrowserInfo());
// { name: 'Chrome', version: '120' }

2. 特性检测

// 通过浏览器特有 API 判断
function detectByFeature() {
  // Chrome 特有
  if (window.chrome && window.chrome.runtime) {
    return 'Chrome 或 Chromium 内核';
  }
  
  // Firefox 特有
  if (typeof InstallTrigger !== 'undefined') {
    return 'Firefox';
  }
  
  // Safari 特有
  if (/constructor/i.test(window.HTMLElement)) {
    return 'Safari';
  }
  
  // IE 特有
  if (/*@cc_on!@*/false || document.documentMode) {
    return 'IE';
  }
  
  return 'unknown';
}

3. 使用第三方库

// 使用 UAParser.js
import UAParser from 'ua-parser-js';

const parser = new UAParser();
const result = parser.getResult();

console.log(result.browser);
// { name: 'Chrome', version: '120.0.0.0', major: '120' }

console.log(result.os);
// { name: 'Windows', version: '10' }

console.log(result.device);
// { model: undefined, type: undefined, vendor: undefined }
// 使用 Bowser
import Bowser from 'bowser';

const browser = Bowser.getParser(navigator.userAgent);

console.log(browser.getBrowserName());    // 'Chrome'
console.log(browser.getBrowserVersion()); // '120.0.0.0'

// 条件判断
const isValidBrowser = browser.satisfies({
  chrome: '>=90',
  firefox: '>=80',
  safari: '>=14'
});

4. navigator 其他属性

// 厂商信息
console.log(navigator.vendor);
// Chrome: 'Google Inc.'
// Firefox: ''
// Safari: 'Apple Computer, Inc.'

// 平台信息
console.log(navigator.platform);
// 'Win32', 'MacIntel', 'Linux x86_64'

// 新版 API (部分浏览器支持)
if (navigator.userAgentData) {
  console.log(navigator.userAgentData.brands);
  // [{ brand: 'Google Chrome', version: '120' }, ...]
  
  // 获取详细信息
  navigator.userAgentData.getHighEntropyValues([
    'platform',
    'platformVersion',
    'architecture'
  ]).then(data => console.log(data));
}

关键点

  • User-Agent 不可靠:可被修改,且各浏览器格式混乱,需要注意判断顺序
  • 特性检测优先:判断功能是否可用比判断浏览器类型更实用
  • 推荐第三方库:UAParser.js、Bowser 等库处理了各种边界情况
  • userAgentData 是趋势:新的 API 更结构化,但兼容性有限
  • 避免过度依赖:浏览器检测应作为降级方案,而非主要逻辑