124

Though both are Webkit based browsers, Safari urlencodes quotation marks in the URL while Chrome does not.

Therefore I need to distinguish between these two in JS.

jQuery's browser detection docs mark "safari" as deprecated.

Is there a better method or do I just stick with the deprecated value for now?

AndreKR
  • 32,613
  • 18
  • 106
  • 168
  • I don't know if sticking with it is such a good idea, I haven't checked this out in depth, although I just browsed to the $.browser docs on chrome and it flags `$.browser.safari === true`. eeek. – davin May 05 '11 at 15:03
  • 1
    possible duplicate of [How to detect Safari, Chrome, IE, Firefox and Opera browser](http://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser) **without user agent sniffing**?. – Rob W May 25 '12 at 10:44

14 Answers14

355

Using a mix of feature detection and Useragent string:

    var is_opera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
    var is_Edge = navigator.userAgent.indexOf("Edge") > -1;
    var is_chrome = !!window.chrome && !is_opera && !is_Edge;
    var is_explorer= typeof document !== 'undefined' && !!document.documentMode && !is_Edge;
    var is_firefox = typeof window.InstallTrigger !== 'undefined';
    var is_safari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);

Usage:
if (is_safari) alert('Safari');

Or for Safari only, use this :

if ( /^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {alert('Its Safari');}
Panos Kalatzantonakis
  • 12,525
  • 8
  • 64
  • 85
  • 3
    With a ratio of 48 votes vs. 5 votes for a feature detection with side effects, apparently this is the recommended solution. :) Making it accepted answer. – AndreKR Sep 05 '13 at 16:08
  • 1
    As an example of just how fragile this sort of thing is, this code does not detect Internet Explorer 11 because the UA string has changed. See http://msdn.microsoft.com/en-us/library/ie/hh869301%28v=vs.85%29.aspx – Olly Hodgson Mar 19 '14 at 10:16
  • 1
    Android webview will also say Safari and that's not correct – Curtis Jun 16 '14 at 23:39
  • 15
    Chrome/Windows will report as Safari: `(Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36)` – Blaise Jul 20 '14 at 20:00
  • 6
    is_explorer = (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0) to also support IE11 >>> http://stackoverflow.com/a/22242528/2049986 – Jacob van Lingen Aug 20 '14 at 12:01
  • Thanks..but I am not able to detect opera, `var is_Opera = navigator.userAgent.indexOf("Presto") > -1;` is giving false. But is_chrome is giving true. (opera 28) – ibsenv Mar 14 '15 at 16:11
  • @ibsenv please check it now, I've updated the code to detect the newest version of Opera (v28). Thank you. – Panos Kalatzantonakis Mar 14 '15 at 20:24
  • except safari ? if (!is_safari) - is this right? i think its including chrome too – ShibinRagh May 25 '16 at 07:43
  • It works incorrect. function isSafari() { var isSafari = false; if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { isSafari = true; } } isSafari(); if(isSafari){ alert("foo & bar"); } – Vy Do Aug 30 '16 at 08:37
  • -1 from me; Chrome on my Mac right now has a user agent of "Mozilla/5.0 (iPad; CPU OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1" i.e. "Chrome" is **not** present. – Keith C Feb 14 '17 at 14:03
  • @PanosKal.Will it detects safari in Ipad as well? – Abhi Jan 12 '18 at 07:34
  • also Edge shows isChrome true now ... so need to add below : !!window.chrome && !IsOpera() && !IsEdge(); – Nigel Fds Apr 17 '19 at 01:44
  • this doesn't work -- `navigator.userAgent` has been available in Safari since Safari 11 – ortonomy Jun 14 '19 at 07:58
79

The following identifies Safari 3.0+ and distinguishes it from Chrome:

isSafari = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/)
brissmyr
  • 826
  • 6
  • 5
10

unfortunately the above examples will also detect android's default browser as Safari, which it is not. I used navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1 && navigator.userAgent.indexOf('Android') == -1

user3107045
  • 111
  • 1
  • 4
7

For checking Safari I used this:

$.browser.safari = ($.browser.webkit && !(/chrome/.test(navigator.userAgent.toLowerCase())));
if ($.browser.safari) {
    alert('this is safari');
}

It works correctly.

FlamyTwista
  • 447
  • 5
  • 17
3

Apparently the only reliable and accepted solution would be to do feature detection like this:

browser_treats_urls_like_safari_does = false;
var last_location_hash = location.hash;
location.hash = '"blah"';
if (location.hash == '#%22blah%22')
    browser_treats_urls_like_safari_does = true;
location.hash = last_location_hash;
AndreKR
  • 32,613
  • 18
  • 106
  • 168
  • 2
    Nice trick, but unfortunately it doesn't work. The equality (location.hash == '#%22blah%22') will not work because of the way location.hash treats the string. :/ – Panos Kalatzantonakis Oct 14 '11 at 12:45
  • 1
    Feature detection is the way to go, but there's a better method which does not have any side effects. Your snippet may interfere with other scripts which rely on hash change events. I've marked the question as a duplicate of [this](http://stackoverflow.com/a/9851769/938089?how-to-detect-safari-chrome-ie-firefox-and-opera-browser). I've created and tested the method in Safari 3.0 - 5.1.3 (Mac and Windows). It's a one-liner :) – Rob W May 25 '12 at 10:42
2

The only way I found is check if navigator.userAgent contains iPhone or iPad word

if (navigator.userAgent.toLowerCase().match(/(ipad|iphone)/)) {
    //is safari
}
ohrlando
  • 106
  • 11
1
//Check if Safari
  function isSafari() {
      return /^((?!chrome).)*safari/i.test(navigator.userAgent);
  }
//Check if MAC
     if(navigator.userAgent.indexOf('Mac')>1){
        alert(isSafari());
     }

http://jsfiddle.net/s1o943gb/10/

Code Spy
  • 9,626
  • 4
  • 66
  • 46
1

This will determine whether the browser is Safari or not.

if(navigator.userAgent.indexOf('Safari') !=-1 && navigator.userAgent.indexOf('Chrome') == -1)
{
    alert(its safari);
}else {
    alert('its not safari');
}
Dushyant Dagar
  • 1,019
  • 10
  • 17
1

I use to detect Apple browser engine, this simple JavaScript condition:

 navigator.vendor.startsWith('Apple')
Daniel De León
  • 13,196
  • 5
  • 87
  • 72
1

If you are checking the browser use $.browser. But if you are checking feature support (recommended) then use $.support.

You should NOT use $.browser to enable/disable features on the page. Reason being its not dependable and generally just not recommended.

If you need feature support then I recommend modernizr.

John Strickler
  • 25,151
  • 4
  • 52
  • 68
  • Teach a man to fish... "Is there a better method" - Yes, feature detection. – John Strickler May 05 '11 at 22:03
  • You mean something like `location.hash = '"blah"'; if (location.hash == '#%22blah%22') alert('is Safari');`? – AndreKR May 06 '11 at 12:26
  • @AndreKR Exactly, I'd make a function to specifically test for the feature you are checking for. – John Strickler May 06 '11 at 14:19
  • feature detection isn't reliable either since some browsers default to "yes I support X" when really they don't – Greg Flynn Jun 16 '11 at 12:52
  • 2
    @Greg You aren't asking the browser.. you are testing the browser. – John Strickler Jun 16 '11 at 13:10
  • $.browser is already depreciated and may be moved out of the jQuery core soon. http://api.jquery.com/jQuery.browser/ read the description, the jQuery team prefers you use feature detection too. – John Strickler Jun 16 '11 at 13:12
  • @John yea, you're right, I was thinking of something else, sorry! – Greg Flynn Jun 16 '11 at 13:49
  • 12
    Feature detection is great, but what about when you want to stop a particular browser from using CSS Animations (for example), because it has a buggy implementation? It technically supports the feature, but we want to take a decision to disable it for that browser, because the experience is better without in that instance. – Phil Ricketts Jun 30 '11 at 15:09
  • @Replete +1 Another example is File Drag and Drop support detection and wanting to *include* Safari 5 on Windows. Commonly suggested method of using `Modernizr.draganddrop && !!window.FileReader` will return false, but Safari 5 on Windows DOES support drag and drop. – Chris Apr 09 '13 at 15:21
0

Generic FUNCTION

 var getBrowseActive = function (browserName) {
   return navigator.userAgent.indexOf(browserName) > -1;
 };
0

A very useful way to fix this is to detect the browsers webkit version and check if it is at least the one we need, else do something else.

Using jQuery it goes like this:

"use strict";

$(document).ready(function() {
    var appVersion                  = navigator.appVersion;
    var webkitVersion_positionStart = appVersion.indexOf("AppleWebKit/") + 12;
    var webkitVersion_positionEnd   = webkitVersion_positionStart + 3;
    var webkitVersion               = appVersion.slice(webkitVersion_positionStart, webkitVersion_positionEnd);
 
    console.log(webkitVersion);

    if (webkitVersion < 537) {
        console.log("webkit outdated.");
    } else {
        console.log("webkit ok.");
    };
});

This provides a safe and permanent fix for dealing with problems with browser's different webkit implementations.

Happy coding!

Petroff
  • 808
  • 1
  • 12
  • 30
reicek
  • 86
  • 4
0
    // Safari uses pre-calculated pixels, so use this feature to detect Safari
    var canva = document.createElement('canvas');
    var ctx = canva.getContext("2d");
    var img = ctx.getImageData(0, 0, 1, 1);
    var pix = img.data;     // byte array, rgba
    var isSafari = (pix[3] != 0);   // alpha in Safari is not zero
Vitaly
  • 1
0

My best solution

function getBrowserInfo() {
  const ua = navigator.userAgent; let tem;
  let M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
  if (/trident/i.test(M[1])) {
    tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
    return { name: 'IE ', version: (tem[1] || '') };
  }
  if (M[1] === 'Chrome') {
    tem = ua.match(/\bOPR\/(\d+)/);
    if (tem != null) {
      return { name: 'Opera', version: tem[1] };
    }
  }
  M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
  tem = ua.match(/version\/(\d+)/i);
  if (tem != null) {
    M.splice(1, 1, tem[1]);
  }
  return {
    name: M[0],
    version: M[1],
  };
}

getBrowserInfo();
  • Welcome. Thanks for contributing. Code only responses are discouraged as low quality on SO. Please consider editing to add an explanation how/why this solves the OP's issue, and even additional supporting links to documentation. Note that most upvotes come from quality answers over time, as various users learn something from your post to apply to their own coding issues. More info is available in the SO [help](StackOverflow.com/help) – SherylHohman Dec 22 '20 at 22:00