检测Safari浏览器

252

如何使用JavaScript检测Safari浏览器?我尝试了下面的代码,但它不仅检测到了Safari浏览器,还检测到了Chrome浏览器。

function IsSafari() {

  var is_safari = navigator.userAgent.toLowerCase().indexOf('safari/') > -1;
  return is_safari;

}

1
一些与文件提交相关的JS代码在Safari上运行不同,在Chrome上正常运行。 - Tomas
1
你几乎肯定应该测试API之间的任何差异。除了Safari和Chrome之外,还有其他基于WebKit的浏览器。 - Quentin
20
有很多原因可能希望检测浏览器。例如,截至本文撰写时,在Safari中某些SVG引擎的方面(如过滤器)已经损坏,但在Chrome中工作正常。 - Paul Legato
有时候你就是无法修复 bug,因为你无法重现它(我没有 Mac 访问权限)。我已经在 Midori 上解决了问题(一些 BlobBuilder/Blob 的 sendAsBinary shim 问题),但客户说文件上传仍然存在问题,所以我能想到的最好的办法就是删除 Safari 支持并使用 iframes(就像旧版 IE 一样)。 - llamerr
1
可能是重复的问题:如何检测Chrome和Safari浏览器(Webkit) - anik4e
23个回答

248

注意:在定位和修复问题时,请尽可能检测特定的行为,而不是使用isSafari?进行目标定位。

作为最后的手段,可以使用此正则表达式来检测 Safari:

var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);

它使用负面环视,并排除Chrome、Edge和所有在其用户代理中包含Safari名称的Android浏览器。


3
这个不起作用。如果我在iPhone上使用Chrome浏览器,仍然会得到true。 - ayjay
54
这是因为iOS上的所有浏览器都只是Safari的外壳(Opera Mini在“Mini”模式下除外),包括Chrome。这并不一定意味着它们都会匹配此测试,因为userAgent字符串是由外壳决定的。你可能需要单独检测iOS上的Chrome,可以参考这个链接:https://dev59.com/CmYr5IYBdhLWcg3wRoSW#13808053 - fregante
2
现在已经修复了。你是对的,很多浏览器的问题在于它们包含其他名称,以避免被忽视。例如Edge在其UA中包括Chrome和Safari。基于用户代理的检查因此而糟糕:浏览器会改变,检查需要更新。不幸的是,没有完美的方法来检测浏览器,这总是一个猜测。 - fregante
2
使用特性检测绝对是个好主意,但有些行为很难或几乎不可能测试,例如移动设备上的视频是否自动全屏播放,这只会在iPhone和iPod上发生。要测试它,您需要加载一个视频并让用户播放它。 - fregante
2
说实话,我发现Safari的background-color属性在使用部分透明颜色值时会悄无声息地失败。也就是说,它“确实”会渲染出颜色,但它只会将其渲染为“透明”。任何覆盖该属性的东西都会在其他浏览器中覆盖预期的颜色。重点是,有时候特性检测并不是解决问题的方法。 - Mattias Martens
显示剩余6条评论

130

正如其他人已经指出的那样,特性检测比检查特定浏览器更可靠。一个原因是用户代理字符串可以被修改,另一个原因是该字符串可能会在新版本中发生更改并且破坏您的代码。

如果您仍然希望这样做并测试任何Safari版本,我建议使用以下方法:

var isSafari = navigator.vendor && navigator.vendor.indexOf('Apple') > -1 &&
               navigator.userAgent &&
               navigator.userAgent.indexOf('CriOS') == -1 &&
               navigator.userAgent.indexOf('FxiOS') == -1;

这将适用于所有设备上的所有版本的Safari:Mac、iPhone、iPod、iPad。

编辑

要在当前浏览器中进行测试:https://jsfiddle.net/j5hgcbm2/

编辑 2

根据Chrome文档更新,以正确检测iOS上的Chrome

编辑 3

根据Firefox文档更新,以正确检测iOS上的Firefox


8
遗憾的是,需要了解浏览器的原因不仅仅是特性检测。某个浏览器可能支持某个特性,但存在缺陷(例如:IE10中的画布缺陷,但相同的特性在IE9上能正常工作)。此外,Firefox与基于Webkit的浏览器(如Chrome)的行为也有所不同,例如对鼠标移动的响应。苹果公司的Safari存在回流错误,而在Chrome中则不存在。一些浏览器在执行某些计算密集型任务时的性能也可能会优于其他浏览器。 - DemiImp
Chrome在iOS上使用Safari Webkit引擎,所以它有点像Safari,而不是真正的Chrome。 - AMilassin
1
在Safari / Chrome上正常工作,但在我的iPhone上,Firefox被认为是移动版的Safari。 - M3RS
3
对于 Firefox,您可以添加 && !navigator.userAgent.match('FxiOS'),类似于 Chrome 检查 - 参考文献(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox)。 - Petri Pellinen
1
感谢@Andras报告iOS上Firefox的问题,以及Petri Pellinen提供的解决方案。 - qingu
显示剩余3条评论

126

您可以轻松使用Chrome的索引来过滤Chrome:

var ua = navigator.userAgent.toLowerCase(); 
if (ua.indexOf('safari') != -1) { 
  if (ua.indexOf('chrome') > -1) {
    alert("1") // Chrome
  } else {
    alert("2") // Safari
  }
}

8
无法运行。目前在iPhone上输出的是Chrome UA字符串,但其中甚至不包含单词“chrome”。 - Paul Carlton
8
Windows 10 中的 IE 11 UA 字符串也包含了 Safari 和 Chrome。 - cuixiping
26
@Flimm,浏览器检测有许多合法的用途。请不要假设您知道提问者或回答者的意图。虽然包含一些您可能认为相关的有用提示很好,但这绝不是必须的。 - Ruben Martinez Jr.
3
被投下负评,不可靠的解决方案 - 下面有更好的答案。 - Oli C
2
正如所提到的,这种方法已经过时了,它会将 Microsoft Edge 识别为 Chrome。 - damianmr
显示剩余3条评论

125

只需使用:

var isSafari = window.safari !== undefined;
if (isSafari) console.log("Safari, yeah!");

请注意,在Safari移动版中,这可能不可靠。


19
不确定为什么这个不太受重视 - 这个很完美,简短易懂。我需要排除桌面版Safari因缺乏getUserMedia功能而导致的问题。 - Stephen Tetreault
8
这是确定桌面版Safari的完美方法,因为它在移动设备上不起作用。 - godblessstrawberry
10
在 iPhone 11 Pro Max 模拟器 13.5 中,这个方案无法运作。 - Christian Valentin
8
我应该指出,这仅适用于macOS上的Safari,在我的情况下非常完美。谢谢! - Twyx
4
我想警告大家,这不是一种可靠的检测方式。我们曾经因为意识到这在iPad OS和iOS的Safari上无法工作而受到了伤害。 - Phil Rukin
显示剩余5条评论

27

这段代码用于检测仅限Safari浏览器

if (navigator.userAgent.search("Safari") >= 0 && navigator.userAgent.search("Chrome") < 0) 
{
   alert("Browser is Safari");          
}

7
此代码仅检测是否为不是Chrome浏览器的WebKit浏览器。许多其他浏览器将“Safari”包含在其用户代理字符串中,这是一个糟糕的想法。例如,Opera浏览器:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36 OPR/24.0.1558.51 (Edition Next)或者原生的Android浏览器:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.34 Safari/534.24 - rupps
抛掷平台侦测或许可以过滤特定的兼容性情况。 - ljgww
我刚刚检查了半打第三方iOS浏览器,它们都伪装成非常精确的Safari用户代理。 - Mitch Match
所以这只能检测Chrome。但是,我刚刚发现Chrome 44不再在UA中使用Chrome,而改用'CriOS' :( - Mitch Match

23

阅读了许多答案和帖子,并确定了最准确的解决方案。在Safari、Chrome、Firefox和Opera(桌面版和iOS版本)中进行了测试。首先,我们需要检测Apple供应商,然后排除Chrome、Firefox和Opera(适用于iOS)。

let isSafari = navigator.vendor.match(/apple/i) &&
             !navigator.userAgent.match(/crios/i) &&
             !navigator.userAgent.match(/fxios/i) &&
             !navigator.userAgent.match(/Opera|OPT\//);

if (isSafari) {
  // Safari browser is used
} else {
  // Other browser is used
}

22

由于Chrome和Safari的userAgent几乎相同,因此查看浏览器的供应商可能更容易。

Safari

navigator.vendor ==  "Apple Computer, Inc."

Chrome

navigator.vendor ==  "Google Inc."

火狐浏览器(为什么是空的?)

navigator.vendor ==  ""

IE(为什么它未定义?)

navigator.vendor ==  undefined

1
我正在寻找一种方法来在工作中禁用不同计算机(Mac桌面,iPad等)上Safari的警告信息,而这个方法完美地解决了我的问题。 - dylnmc
1
但是在iOS上为Chrome提供服务的供应商也将是“Apple Computer,Inc.”。很抱歉... - Piotr Kowalski
1
这在基于Chrome的边缘版本上失败了! - Qiulang
1
最聪明和最简单的解决方案。通常你想要捕捉Safari,因为它是新版IE - 修复它不支持的javascript问题 - 就像它应该做的那样。即使在iOS中,Chrome也基于Safari引擎,并且具有与Safari相同的糟糕支持。而这个简单的方法可以检测Mac OS中的Safari,以及iOS中的Safari和Chrome。太棒了。 - JoakimB
1
但是Chrome在iOS上的供应商也将是“Apple Computer,Inc。”很抱歉。这是因为Chrome在iOS上就是Safari,所以这正是您想要的。重点不是弄清浏览器的品牌,而是弄清楚您正在处理哪个引擎,以便您可以解决特定于引擎的错误。 - Mud
显示剩余3条评论

17
检测手势变化支持,就像这样:

const isSafari = !!window.GestureEvent
document.write(isSafari ? "You are using Safari." : "You are not using Safari.")

简单易用,适用于iOS和Android!如果需要ES5支持,请将const替换为var

1
你如何实际地检测事件是否存在? - Hicka
3
СйатЈ»С╗ЦТБђТЪЦtypeof window.GestureEvent === 'function'сђѓТёЈТђЮТў»ТБђТЪЦwindow.GestureEventуџёу▒╗тъІТў»тљдТў»тЄйТЋ░сђѓ - Jankapunkt
2
如果 ('GestureEvent' in window) {window.alert('This is WebKit');}。请注意,此检查检测到的是 WebKit 而不是 Safari - 但是,如果您正在寻找与桌面版 Safari 和 iOS 上的 所有 浏览器匹配(在 iOS 上,Chrome Mobile、Safari Mobile 等都只是具有不同皮肤的 Safari Mobile),则检测 WebKit(而不是 "Safari")可能是您想要的。 - Rounin
那正是我正在寻找的,谢谢。 - mtness

13

我不知道OP为什么想要检测Safari,但是在现今很少需要进行浏览器嗅探,更重要的是检测渲染引擎而不是浏览器名称。例如,在iOS上,所有浏览器都使用Safari/Webkit引擎,因此如果底层渲染引擎实际上是Safari/Webkit,获取“chrome”或“firefox”作为浏览器名称就没有意义了。我还没有在旧浏览器上测试过这段代码,但它可以用于Android、iOS、OS X、Windows和Linux上的所有较新浏览器。

<script>
    let browserName = "";

    if(navigator.vendor.match(/google/i)) {
        browserName = 'chrome/blink';
    }
    else if(navigator.vendor.match(/apple/i)) {
        browserName = 'safari/webkit';
    }
    else if(navigator.userAgent.match(/firefox\//i)) {
        browserName = 'firefox/gecko';
    }
    else if(navigator.userAgent.match(/edge\//i)) {
        browserName = 'edge/edgehtml';
    }
    else if(navigator.userAgent.match(/trident\//i)) {
        browserName = 'ie/trident';
    }
    else
    {
        browserName = navigator.userAgent + "\n" + navigator.vendor;
    }
    alert(browserName);
</script>

澄清一下:

  • iOS下的所有浏览器都将报告为“safari/webkit”
  • Android下除了Firefox的所有浏览器都将报告为“chrome/blink”
  • 在Windows、OS X或Linux下,Chrome、Opera、Blisk、Vivaldi等所有浏览器都将报告为“chrome/blink”

旧版本的IE浏览器中使用字符串MSIE而不是Trident。有时候Edge浏览器单词edge的最后一个字母e会丢失,你需要搜索edg。 - PHP Guru
这应该是新的被接受的答案,谢谢Christopher。 - Myndex
2023年 - 答案对我有效。仅在桌面端进行了测试,尚未在移动设备上进行测试。 - Michael Martell

12

在我的情况下,我需要同时针对iOS和macOS上的Safari进行操作。这对我起作用:

if (/apple/i.test(navigator.vendor)) {
  // It's Safari
}

1
谢谢!这个还能检测到不包含Safari字符串的WKWebView:Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 - mikep
有什么理由使用正则表达式来实现这个功能,而不是直接使用 navigator.vendor === "Apple Computer, Inc." - Newbyte
老实说,我不知道navigator.vendor可能包含什么内容,但在我的特定情况下,我需要针对任何苹果浏览器进行操作,所以正则表达式对我很有用。 - Simone
2
不起作用!它只能检测是否为iOS或macOS。如果我使用Firefox、Chrome或Opera,它仍然会显示我在使用Safari... - MrMaavin
2
怎么做呢?在Chrome上,navigator.vendorGoogle Inc.,因此测试返回false(它不是Safari)。Firefox对我来说返回一个空字符串,这也被评估为false。因此,这似乎很好地用于检测Safari。 - Simone
已在以下设备上进行测试:
  • macOS(Ventura)Chrome 108:false
  • macOS Safari:true
  • iOS Safari:true
  • iOS Chrome:无法测试
- younes0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接