2025年 Safari 和 iOS版本检测新思路

大家好,我是 Immerse,一名独立开发者、内容创作者、AGI 实践者。

关注公众号:沉浸式趣谈,获取最新文章(更多内容只在公众号更新)

个人网站:yaolifeng.com 也同步更新。

转载请在文章开头注明出处和版权信息。

我会在这里分享关于编程独立开发AI干货开源个人思考等内容。

如果本文对您有所帮助,欢迎动动小手指一键三连(点赞评论转发),给我一些支持和鼓励,谢谢!


最近看到一篇文章,针对于 Safari 和 iOS 版本检测很不错,分享出来给大家。

之前都用 User-Agent 一把嗦,但文章提到检测结果不准确。

两个方式

  1. User-Agent
  2. 特性检测

User-Agent 检测

这个方法就是获取浏览器的 User-Agent,从里面提取版本信息。

但是有问题,这个结果不准确。

Safari 的 UA 字符串里有两个版本号,一个是技术版本,一个是市场版本。很多脚本会把这俩搞混。

还有一点,从 macOS 11 开始,Safari 的 UA 里系统版本就不更新了,永远显示 10.15.7。

所以想从 UA 里准确获取版本?基本不可能。

MDN 官方都说了,别依赖 UA 字符串做浏览器检测逻辑,这是个常见 bug 源头。

特性检测

苹果官方推荐: 特性检测。

就是直接检查浏览器支不支持某个 API 或 CSS 特性。

但它没法区分所有版本,因为很多特性在好几个版本里都有。

解决思路

把两种方法结合起来用, 主要靠特性检测,UA 检测作为补充。

第一步:检测 WebKit 引擎

在 iOS 上,所有浏览器都必须用 WebKit,包括 Chrome、Firefox 这些。

所以检测 WebKit 能帮我们缩小范围:

js 复制代码
// 桌面 Safari 和所有 iOS 浏览器
function isWebkit() {
    return 'GestureEvent' in window;
}

// 所有移动端 WebKit 浏览器
function isMobileWebKit() {
    return 'ongesturechange' in window;
}

// 只检测桌面 Safari
function isDesktopWebKit() {
    return typeof window !== 'undefined' && 'safari' in window && 'pushNotification' in window.safari;
}

第二步:检测特定 iOS 版本

去查 Safari 发布说明或 WebKit 的更新日志,找到某个版本新增的特性。

比如我想检测 iOS 17.0,发现这个版本加入了 contain-intrinsic-size 支持。

那就检测这个特性:

js 复制代码
// iOS 17.0+ 返回 true
const isAtLeastiOS17 = CSS.supports('contain-intrinsic-size', '100px');

如果要检测具体的小版本,可以配合下一个版本的特性来排除。

比如 ManagedMediaSource 是在 iOS 17.1 才有的:

js 复制代码
const supportsManagedMediaSource = 'ManagedMediaSource' in window;

// 只匹配 iOS 17.0
function isOnlyiOS170() {
    return isAtLeastiOS17 && !supportsManagedMediaSource;
}

if (isMobileWebKit()) {
    if (isOnlyiOS170()) {
        // 这是 iOS 17.0
    }
}

第三步:真机测试

理论归理论,实际测试才是王道。

踩坑:

iOS 17.6 的发布说明里说支持 CSS 的 safe 关键字,用 @supports 检测也返回 true。

结果真机上一跑,根本不生效。

这种情况下,只能换个思路,检测实际的渲染效果:

js 复制代码
const isSafeKeywordSupported = () => {
    const container = document.createElement('div');
    const child = document.createElement('span');

    child.textContent = 'Evil Martians';

    container.style.display = 'flex';
    container.style.justifyContent = 'safe center';
    container.style.width = '5%';
    container.style.position = 'absolute';
    container.style.top = '-9999px';
    container.style.left = '-9999px';

    container.appendChild(child);
    document.body.appendChild(container);

    const containerRect = container.getBoundingClientRect();
    const childRect = child.getBoundingClientRect();
    const isCroppedOnLeft = childRect.left < containerRect.left;

    document.body.removeChild(container);
    return !isCroppedOnLeft;
};

通过检查元素的实际渲染位置,判断特性是不是真的生效了。

第四步:配合 UA 检测

有时候特性检测也不够用。

比如要区分 iPad 和其他设备。

iPad 的 UA 字符串跟 macOS 上的 Safari 一模一样。

但如果 UA 显示是 macOS,特性检测又显示是移动端 WebKit,那就能判断出这是 iPad:

js 复制代码
// 检测 iPadOS
function isiPad() {
    return isDesktopWebKit() && isMobileWebKit();
}

几个关键点

WebKit 不等于 Safari,iOS 上所有浏览器都用 WebKit。

主要用特性检测,UA 检测只是补充。

多看 Safari 和 WebKit 的发布说明,但也别全信,因为有些变更根本没写进去。

真机测试不能省,有些 bug 只有在实际设备上才能发现。

有时候 @supports 会撒谎,浏览器说支持但实际不行,这时候得检查实际渲染效果。

写在最后

核心思路就是:特性检测为主,UA 检测为辅,真机测试验证。

参考资料

相关推荐
_AaronWong14 小时前
Electron 实现仿豆包划词取词功能:从 AI 生成到落地踩坑记
前端·javascript·vue.js
cxxcode14 小时前
I/O 多路复用:从浏览器到 Linux 内核
前端
用户54330814419414 小时前
AI 时代,前端逆向的门槛已经低到离谱 — 以 Upwork 为例
前端
JarvanMo14 小时前
Flutter 版本的 material_ui 已经上架 pub.dev 啦!快来抢先体验吧。
前端
雨中飘荡的记忆15 小时前
OpenClaw:开源AI助手平台的革命之路
后端
恋猫de小郭15 小时前
AI 可以让 WIFI 实现监控室内人体位置和姿态,无需摄像头?
前端·人工智能·ai编程
哀木15 小时前
给自己整一个 claude code,解锁编程新姿势
前端
程序员鱼皮15 小时前
GitHub 关注突破 2w,我总结了 10 个涨星涨粉技巧!
前端·后端·github
UrbanJazzerati15 小时前
Vue3 父子组件通信完全指南
前端·面试
用户2986985301415 小时前
程序员效率工具:Spire.Doc如何助你一键搞定Word表格排版
后端·c#·.net