大家好,我是 Immerse,一名獨立開發者、內容創作者、AGI 實踐者。
關注公眾號:沉浸式趣談,獲取最新文章(更多內容只在公眾號更新)
個人網站:https://yaolifeng.com 也同步更新。
轉載請在文章開頭註明出處和版權信息。
我會在這裏分享關於編程、獨立開發、AI乾貨、開源、個人思考等內容。
如果本文對您有所幫助,歡迎動動小手指一鍵三連(點贊、評論、轉發),給我一些支持和鼓勵,謝謝!
最近看到一篇文章,針對於 Safari 和 iOS 版本檢測很不錯,分享出來給大家。
之前都用 User-Agent 一把嗦,但文章提到檢測結果不準確。
兩個方式
- User-Agent
- 特性檢測
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 能幫我們縮小範圍:
// 桌面 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 支持。
那就檢測這個特性:
// iOS 17.0+ 返回 true
const isAtLeastiOS17 = CSS.supports('contain-intrinsic-size', '100px');
如果要檢測具體的小版本,可以配合下一個版本的特性來排除。
比如 ManagedMediaSource 是在 iOS 17.1 才有的:
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。
結果真機上一跑,根本不生效。
這種情況下,只能換個思路,檢測實際的渲染效果:
<video src="https://qncdn.mopic.mozigu.net/work/143/25/8fe6997ae26b491d/safecenter.mp4" controls></video>
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:
// 檢測 iPadOS
function isiPad() {
return isDesktopWebKit() && isMobileWebKit();
}
幾個關鍵點
WebKit 不等於 Safari,iOS 上所有瀏覽器都用 WebKit。
主要用特性檢測,UA 檢測只是補充。
多看 Safari 和 WebKit 的發佈説明,但也別全信,因為有些變更根本沒寫進去。
真機測試不能省,有些 bug 只有在實際設備上才能發現。
有時候 @supports 會撒謊,瀏覽器説支持但實際不行,這時候得檢查實際渲染效果。
寫在最後
核心思路就是:特性檢測為主,UA 檢測為輔,真機測試驗證。
參考資料
- https://developer.apple.com/documentation/safari-release-notes
- https://webkit.org/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent