【问题标题】:Detect Safari browser检测 Safari 浏览器
【发布时间】:2011-12-18 04:05:54
【问题描述】:

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

function IsSafari() {

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

}

【问题讨论】:

  • 一些与文件提交相关的 JS 代码在 Safari 中可以正常工作,而在 Chrome 中可以正常工作。
  • 您几乎可以肯定地测试 API 中存在的任何差异。除了 Safari 和 Chrome,还有其他基于 WebKit 的浏览器。
  • 希望检测浏览器的原因有很多。例如,在撰写本文时,SVG 引擎的某些方面(例如过滤器)在 Safari 中已损坏,但在 Chrome 中可以正常工作。
  • 有时您无法修复错误,因为您无法重现它(我无法访问 Mac)。我修复了 Midori 的问题(sendAsBinary shim 的一些 BlobBuilder/Blob 问题),但客户说文件上传仍然存在问题,所以我能想到的最好的事情就是删除 Safari 支持并为其使用 iframe(至于旧的 IE)

标签: javascript browser-detection


【解决方案1】:

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

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

【讨论】:

  • 不起作用。目前在 iPhone 上输出 chrome UA 字符串,里面甚至没有“chrome”这个词。
  • Windows 10 中的 IE 11 UA 字符串还包含 Safari 和 Chrome
  • @Flimm 浏览器检测有很多合法的用例。不要假设知道提问者或回答者的意图。虽然包含您可能认为相关的有用提示很好,但这绝不是必需的。
  • 这不适用于Android浏览器,包括“safari”但不包括“chrome”:developers.whatismybrowser.com/useragents/explore/software_name/…
  • 投反对票,作为不可靠的解决方案 - 下面有更好的答案。
【解决方案2】:

此代码仅用于检测 safari 浏览器

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

【讨论】:

  • 此代码仅检测 webkit 浏览器是否不是 chrome。许多其他浏览器在其用户代理字符串中包含“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),或 Stock Android 浏览器:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.34 Safari/534.24
  • 折腾平台检测或许可以过滤掉特定的兼容性情况。
  • 我刚刚检查了六个第三方 iOS 浏览器,它们都欺骗了非常精确的 Safari 用户代理。
  • 所以这只会检测 Chrome。然而,我刚刚发现 Chrome 44 在 UA 中不再有 Chrome,而是“CriOS”:(
  • 我们应该始终尝试进行特征检测,并将浏览器检测作为最后的手段,因为后者更有可能破坏和阻止合法用户。任何根本没有提到特征检测的答案都会遭到我的反对。
【解决方案3】:

注意:始终尝试检测您要修复的特定行为,而不是使用isSafari?定位它

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

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

它使用negative look-arounds,不包括 Chrome、Edge 和所有在其用户代理中包含 Safari 名称的 Android 浏览器。

【讨论】:

  • 这不起作用。如果我在 iPhone 上使用 Chrome 浏览器,我仍然是正确的。
  • 这是因为 iOS 上的所有浏览器都只是 Safari 的封装(除了 Mini 模式下的 Opera Mini),包括 Chrome。这并不一定意味着它们将 all 匹配此测试,因为 userAgent 字符串取决于包装器。你可能想单独detect Chrome on iOS
  • 老兄这对我有用!!!非常感谢.. navigator.userAgent 正在为 Windows 中的 Chrome 和 Mac 中的 Safari 返回诸如“5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36”之类的值。
  • 现已修复。您绝对是对的,许多浏览器的问题在于它们包含其他名称以尽量不被遗漏。 Like Edge 在其 UA 中同时包含 Chrome 和 Safari。由于这个原因,用户代理检查很糟糕:浏览器发生变化并且需要更新检查。不幸的是,没有完美的方法来检测浏览器,这总是一种猜测。
  • 使用特征检测绝对是一个好主意,但有些行为很难或几乎不可能测试,例如移动设备上的视频是否会自动全屏显示,这只会发生在 iPhone 和 iPod 上。要对其进行测试,您需要加载一个视频并让用户播放它。
【解决方案4】:

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

如果您仍想这样做并测试任何 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 docs更新以正确检测iOS上的Chrome

值得注意的是,iOS 上的所有浏览器都只是 Safari 的包装器,并且使用相同的引擎。请参阅 bfred.it 在此线程中对他自己的答案的评论。

编辑 3

根据Firefox docs更新以正确检测iOS上的Firefox

【讨论】:

  • 感谢您的评论 - 已更新以正确检测 iOS 上的 Chrome
  • @qingu - 我不懂这个javascript,我该怎么做 - if(safaribrowser) { do this } else { do that } 使用相同的代码什么值是'var isSafari'谢谢
  • @GAV: isSafari 在 Safari 浏览器中为 true,否则为 false。您可以简单地使用上面的 sn-p,然后几乎按照您发布的方式使用您的。 if (isSafari) { do_this(); } else { do_that(); }.
  • 不幸的是,尝试找出浏览器的原因不仅仅是功能检测。浏览器可以支持某个功能,但有问题(例如:IE10 中的画布错误,但相同的功能在 IE9 中有效)。此外,Firefox 的行为与基于 webkit 的浏览器不同,例如它如何响应鼠标移动。 Apple 的 Safari 存在 Chrome 中不存在的回流错误。某些浏览器在执行某些计算密集型任务时也比其他浏览器表现出色。
  • @Andras 对于 Firefox,您可以添加 &amp;&amp; !navigator.userAgent.match('FxiOS') 类似于 Chrome 检查 - ref (developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/…)
【解决方案5】:

也许这行得通:

Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor')

编辑:不再工作

【讨论】:

  • 这到底是做什么的,因为在所有浏览器上都返回 -1?
  • @Petroff 它不再在较新的 Safari 中工作。感谢您指出。
  • 请随意删除答案。
【解决方案6】:

我用这个

function getBrowserName() {
    var name = "Unknown";
    if(navigator.userAgent.indexOf("MSIE")!=-1){
        name = "MSIE";
    }
    else if(navigator.userAgent.indexOf("Firefox")!=-1){
        name = "Firefox";
    }
    else if(navigator.userAgent.indexOf("Opera")!=-1){
        name = "Opera";
    }
    else if(navigator.userAgent.indexOf("Chrome") != -1){
        name = "Chrome";
    }
    else if(navigator.userAgent.indexOf("Safari")!=-1){
        name = "Safari";
    }
    return name;   
}

if( getBrowserName() == "Safari" ){
    alert("You are using Safari");
}else{
    alert("You are surfing on " + getBrowserName(name));
}

【讨论】:

    【解决方案7】:

    修改了答案above的正则表达式

    var isSafari = /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent);
    
    • crios - Chrome
    • fxios - 火狐

    【讨论】:

      【解决方案8】:

      由于 chrome 和 safari 的 userAgent 几乎相同,因此可以更轻松地查看浏览器的供应商

      Safari

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

      navigator.vendor ==  "Google Inc."
      

      FireFox(为什么是空的?)

      navigator.vendor ==  ""
      

      IE(为什么未定义?)

      navigator.vendor ==  undefined
      

      【讨论】:

      • 我一直在寻找可以在各种计算机(mac 台式机、ipad 等)上禁用 safari 中的警告消息的方法,并且效果很好。
      • 但 iOS 上 Chrome 的供应商也将是“Apple Computer, Inc.”。对不起...
      • @PiotrKowalski - 你选择了哪种解决方案?
      • @tylerlindell 在本页底部使用“版本”一词查看我的答案。
      • 这对于基于 chrome 的边缘版本失败了!
      【解决方案9】:

      只需使用:

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

      【讨论】:

      • 不知道为什么这不是更高的 - 这是完美的,简短的,简单的。由于缺少 getUserMedia,我需要排除桌面 safari。
      • 这是确定桌面 safari 的完美方法,因为它不适用于移动设备
      • 这在 iPhone 11 Pro Max Simulator 13.5 中不起作用
      • 我应该注意,这仅适用于 macOS 上的 Safari,就我而言,它是完美的。谢谢!
      • 它对我不起作用。我在 mac 上使用 Safari 版本 14.0 (15610.1.28.1.9, 15610)
      【解决方案10】:

      只有 Safari 没有 Chrome:

      在尝试其他代码后,我没有发现任何适用于新旧版本 Safari 的代码。

      最后,我编写了这段代码,对我来说效果很好:

      var ua = navigator.userAgent.toLowerCase(); 
      var isSafari = false;
      try {
        isSafari = /constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || safari.pushNotification);
      }
      catch(err) {}
      isSafari = (isSafari || ((ua.indexOf('safari') != -1)&& (!(ua.indexOf('chrome')!= -1) && (ua.indexOf('version/')!= -1))));
      
      //test
      if (isSafari)
      {
        //Code for Safari Browser (Desktop and Mobile)
        document.getElementById('idbody').innerHTML = "This is Safari!";
      }
      else
      {
        document.getElementById('idbody').innerHTML = "Not is Safari!";
      }
      <body id="idbody">
      </body>

      【讨论】:

        【解决方案11】:

        我知道这个问题很老,但我还是想发布答案,因为它可能对某人有所帮助。上述解决方案在某些边缘情况下会失败,因此我们必须以分别处理 iOS、桌面和其他平台的方式来实现它。

        function isSafari() {
            var ua = window.navigator.userAgent;
            var iOS = !!ua.match(/iP(ad|od|hone)/i);
            var hasSafariInUa = !!ua.match(/Safari/i);
            var noOtherBrowsersInUa = !ua.match(/Chrome|CriOS|OPiOS|mercury|FxiOS|Firefox/i)
            var result = false;
            if(iOS) { //detecting Safari in IOS mobile browsers
                var webkit = !!ua.match(/WebKit/i);
                result = webkit && hasSafariInUa && noOtherBrowsersInUa
            } else if(window.safari !== undefined){ //detecting Safari in Desktop Browsers
                result = true;
            } else { // detecting Safari in other platforms
                result = hasSafariInUa && noOtherBrowsersInUa
            }
            return result;
        }
        

        【讨论】:

          【解决方案12】:

          我观察到只有一个词可以区分 Safari——“版本”。所以这个正则表达式将完美运行:

          /.*Version.*Safari.*/.test(navigator.userAgent)
          

          【讨论】:

            【解决方案13】:

            这个独特的“问题”100% 表明浏览器是 Safari(信不信由你)。

            if (Object.getOwnPropertyDescriptor(Document.prototype, 'cookie').descriptor === false) {
               console.log('Hello Safari!');
            }
            

            这意味着 cookie 对象描述符在 Safari 上设置为 false,而其他所有设置为 true,这实际上让我对其他项目感到头疼。编码愉快!

            【讨论】:

            • 似乎不再正确。在 Firefox 上也会崩溃“Object.getOwnPropertyDescriptor(...) is undefined”
            【解决方案14】:

            我不知道 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”
            • 除 Firefox 之外的所有 Android 浏览器都将报告为“chrome/blink”
            • Chrome、Opera、Blisk、Vivaldi 等在 Windows、OS X 或 Linux 下都将报告为“chrome/blink”

            【讨论】:

            • 旧版本的 IE 有字符串 MSIE 而不是 Trident。有时 edge 在单词 edge 中缺少最后的 e。您必须搜索 edg
            • 这应该是新接受的答案,谢谢克里斯托弗。
            【解决方案15】:

            据记录,我发现的最安全的方法是从this answer 实现浏览器检测代码的 Safari 部分:

            const isSafari = window['safari'] && safari.pushNotification &&
                safari.pushNotification.toString() === '[object SafariRemoteNotification]';
            

            当然,处理特定于浏览器的问题的最佳方法始终是进行功能检测,如果可能的话。不过,使用上面的一段代码仍然比代理字符串检测要好。

            【讨论】:

            • 这不适用于 iPhone OS 13_4_1 上的 safari Version/13.1 Mobile/15E148 Safari/604.1。
            【解决方案16】:

            最简单的答案:

            function isSafari() {
             if (navigator.vendor.match(/[Aa]+pple/g).length > 0 ) 
               return true; 
             return false;
            }
            

            【讨论】:

            • 它可以工作,虽然没有正则表达式可以更简单:navigator.vendor.toLowerCase().indexOf('apple') &gt; -1
            • 更简单...if (navigator.vendor.match(/apple/i)) { ... }.
            • 这不适用于 ios 13.3.1 on firefox,因为它显示 Apple Computer, inc
            • @nuttynibbles:这可能是你想要的,因为 iOS 上的每个浏览器都是伪装的 Safari。
            【解决方案17】:

            我创建了一个返回布尔类型的函数:

            export const isSafari = () => navigator.userAgent.toLowerCase().indexOf('safari') !== -1
            

            【讨论】:

              【解决方案18】:

              用户代理嗅探非常棘手且不可靠。我们试图用上面@qingu's answer之类的东西来检测 iOS 上的 Safari,它在 Safari、Chrome 和 Firefox 上运行得很好。但它错误地将 Opera 和 Edge 检测为 Safari。

              所以我们进行了功能检测,就像今天一样,serviceWorker 仅在 Safari 中受支持,在 iOS 上的任何其他浏览器中均不受支持。如https://jakearchibald.github.io/isserviceworkerready/中所述

              支持不包括该平台上第三方浏览器的 iOS 版本(请参阅 Safari 支持)。

              所以我们做了类似的事情

              if ('serviceWorker' in navigator) {
                  return 'Safari';
              }
              else {
                  return 'Other Browser';
              }
              

              注意:未在 MacOS 上的 Safari 上测试。

              【讨论】:

                【解决方案19】:

                就我而言,我需要同时在 iOS 和 macOS 上定位 Safari。这对我有用:

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

                【讨论】:

                • 谢谢!这也可以检测到不包含 Safari 字符串的 WKWebView:Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148
                • 有什么理由为此使用正则表达式而不是仅仅使用navigator.vendor === "Apple Computer, Inc."
                • 老实说,我不知道 navigator.vendor 可能包含什么,但在我的具体情况下,我通常需要针对任何 Apple 浏览器,所以正则表达式对我有用
                • 不起作用!它只检测它是 iOS 还是 macOS。如果我使用 Firefox、Chrome 或 Opera,它仍然说我使用 Safari...
                【解决方案20】:

                阅读许多答案和帖子并确定最准确的解决方案。在 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
                }
                

                【讨论】:

                  【解决方案21】:

                  我测试了#Christopher Martin 发布的代码,它报告我的浏览器为 Chrome,因为它在测试 Edge 之前对其进行了测试,否则它将对旨在识别 Chrome 的测试做出正确的回答。我修改了他的答案以纠正该缺陷和其他两个缺陷,即:

                  1. Edge 的缩写用户代理子字符串
                  2. 非常古老的 MSIE 字符串

                  将代码转换为函数会产生以下函数和通过调试控制台报告的测试脚本。

                      <script type="text/javascript">
                      function BasicBrowserSniffer ( )
                      {
                          if ( navigator.userAgent.match ( /edge\//i ) ) {
                              return 'edge/edgehtml';
                          }
                          if ( navigator.userAgent.match ( /edg\//i ) ) {
                              return 'edge/edgehtml';
                          }
                          else if ( navigator.vendor.match ( /google/i ) ) {
                              return 'chrome/blink';
                          }
                          else if ( navigator.vendor.match ( /apple/i ) ) {
                              return 'safari/webkit';
                          }
                          else if ( navigator.userAgent.match ( /firefox\//i ) ) {
                              return 'firefox/gecko';
                          }
                          else if ( navigator.userAgent.match ( /trident\//i ) ) {
                              return 'ie/trident';
                          }
                          else if ( navigator.userAgent.match ( /msie\//i ) ) {
                              return 'ie/trident';
                          }
                          else
                          {
                              return navigator.userAgent + "\n" + navigator.vendor;
                          }
                      };  // BasicBrowserSniffer function
                  
                      console.info ( 'Entering function anonymous DocumentReady function' );
                      console.info ( 'User Agent String   = ' + navigator.userAgent.toLowerCase ( ));
                      console.info ( 'User Agent Vendor   = ' + var uav = navigator.vendor.toLowerCase ( );
                      console.info ( 'BasicBrowserSniffer = ' + BasicBrowserSniffer ( ) );
                      console.info ( 'Leaving function anonymous DocumentReady function' );
                  </script>
                  

                  【讨论】:

                    【解决方案22】:

                    基于@SudarP 的回答。

                    在 2021 年第三季度,此解决方案将在 Firefox (Uncaught TypeError: navigator.vendor.match(...) is null) 和 Chrome (Uncaught TypeError: Cannot read properties of null (reading 'length')) 中失败;

                    所以这里有一个固定且更短的解决方案:

                    function isSafari() {
                      return (navigator.vendor.match(/apple/i) || "").length > 0
                    }
                    

                    【讨论】:

                      【解决方案23】:

                      检测gesture change

                      手势更改仅在 Safari 上得到相当广泛的支持(并且适用于 iOS):

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2023-03-23
                        • 2012-09-19
                        • 2011-03-08
                        • 1970-01-01
                        • 2023-01-18
                        • 2019-02-11
                        • 2012-04-08
                        相关资源
                        最近更新 更多