Главная/ Javascript решения/ Определение браузера и его версии

Определение браузера и его версии

Дата публикации: 02.06.2010

Последнее обновление: 03.06.2010

Определение браузера и его версии Internet Explorer, Firefox, Opera, Chrome, Safari, Netscape, Konqueror, Avant, Dillo… и это только некоторые из ныне доступных браузеров пользователю. Что же в этом плохого?

В «идеальном» мире есть утвержденные веб стандарты, которых придерживаются все разработчики браузеров. Это значит, что на один и тот же правильно написанный тобою HTML код (или CSS код, или JS), каждый из браузеров реагирует одинаково. Но в реальном мире у разработчиков браузеров преобладает мнение, что стандарты — это для далекого розового будущего и когда оно придет они начнут их придерживаться. А сейчас иногда браузеры позволяют совершенно непредсказуемо реагировать на код.

Тебе остается для таких «иногда» научиться точно определять браузер и применять к нему особые меры.

Задача

При помощи JavaScript определить браузер и его версию (без использования дополнительных библиотек).

Метод навигатора

Теория

Среди объектов javascript есть объект navigator, у которого доступен метод UserAgent. Этот метод вернет строку, в которой содержится информация о браузере, его версии, ядре, операционной системе, в которой он запущен, а так же некоторых агентах и службах, встроенных в него. Примеры UserAgent:

  • Opera/9.64 (Windows NT 5.1; U; ru) Presto/2.1.1
  • Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.9.0.2) Gecko/2008092313 Ubuntu/9.25 (jaunty) Firefox/3.8
  • Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; el-GR)

Решение

Т.к. UserAgent возращает имя браузера и его версию для разных браузеров однотипно, поэтому можно составить регулярное выражение для получения нужной информации. Допустим UserAgent вернул такую строку:

Opera/9.64 (Windows NT 5.1; U; ru) Presto/2.1.1

В этой строке нужная информация — это Opera/9.64. Парсим строку и «вытаскиваем» нужное:

function browserDetectNav(chrAfterPoint)
{
var
    UA=window.navigator.userAgent,       // содержит переданный браузером юзерагент
    //--------------------------------------------------------------------------------
	OperaB = /Opera[ /]+w+.w+/i,     //
	OperaV = /Version[ /]+w+.w+/i,   //	
	FirefoxB = /Firefox/w+.w+/i,     // шаблоны для распарсивания юзерагента
	ChromeB = /Chrome/w+.w+/i,       //
	SafariB = /Version/w+.w+/i,      //
	IEB = /MSIE *d+.w+/i,             //
	SafariV = /Safari/w+.w+/i,       //
        //--------------------------------------------------------------------------------
	browser = new Array(),               //массив с данными о браузере
	browserSplit = /[ /.]/i,           //шаблон для разбивки данных о браузере из строки
	OperaV = UA.match(OperaV),
	Firefox = UA.match(FirefoxB),
	Chrome = UA.match(ChromeB),
	Safari = UA.match(SafariB),
	SafariV = UA.match(SafariV),
	IE = UA.match(IEB),
	Opera = UA.match(OperaB);
		
		//----- Opera ----
		if ((!Opera=="")&(!OperaV=="")) browser[0]=OperaV[0].replace(/Version/, "Opera")
				else 
					if (!Opera=="")	browser[0]=Opera[0]
						else
							//----- IE -----
							if (!IE=="") browser[0] = IE[0]
								else 
									//----- Firefox ----
									if (!Firefox=="") browser[0]=Firefox[0]
										else
											//----- Chrom ----
											if (!Chrome=="") browser[0] = Chrome[0]
												else
													//----- Safari ----
													if ((!Safari=="")&&(!SafariV=="")) browser[0] = Safari[0].replace("Version", "Safari");
//------------ Разбивка версии -----------

	var
            outputData;                                      // возвращаемый функцией массив значений
                                                             // [0] - имя браузера, [1] - целая часть версии
                                                             // [2] - дробная часть версии
	if (browser[0] != null) outputData = browser[0].split(browserSplit);
	if ((chrAfterPoint==null)&&(outputData != null)) 
		{
			chrAfterPoint=outputData[2].length;
			outputData[2] = outputData[2].substring(0, chrAfterPoint); // берем нужное ко-во знаков
			return(outputData);
		}
			else return(false);
}

В функцию передаётся всего один параметр — chrAfterPoint, который определяет количество возвращаемых знаков версии. Т.е. функция вернет номер версии и chrAfterPoint знаков после запятой. Если параметр не будет передан — функция вернет все знаки после запятой.

Пример вызова функции:

<button onclick="showBrowVer()">Определить браузер</button>

<script type="text/javascript"> // скриптик будет вызывать нашу функцию определения
                                // и выводить результат
function showBrowVer()          
{
var
data = browserDetectNav();      //вызываем функцию, параметр НЕ передаем,
                                //поэтому в результате получим все знаки версии после запятой

alert("Браузер: "+data[0]+", Версия: "+data[1]+"."+data[2]); //выводим результат
}
	
</script>

Демо пример. Проверено в:

Недостаток

Это информация из UserAgent. Его очень легко подделать, подменить или, как говориться, «подсунуть»(такой возможностью наделены такие звери как Opera и Safari). К тому же зачастую менее известные браузеры представляются более именитыми «коллегами», но это совсем не значит, что они поддерживают нужные нам свойства или методы.

Вывод

Несмотря на недостаток, такой метод в большинстве случаев определит браузер совершенно точно, а если в него интегрировать еще и парочку способов по вычислению «партизанов» (маскирующихся браузеров), то доля удачных определений существенно возрастёт.

Заметки

  • в примере определяются самые популярные браузеры (IE, Firefox, Opera, Chrome и Safari), остальные можно добавить по желанию и потребностям;
  • нужно заметить, что Safari и Opera (начиная с 10-й версии) передают информацию о себе двумя блоками в строке Useragent, поэтому для них схема отличается от общей
  • т.к. Opera умеет »прикидываться« другими браузерами, казалось бы, что её по юзерагенту не вычислить, тем не менее в строке юзерагента помимо идентификатора другого браузера, она передаёт и свой. Проверку на Opera просто ставим в первую очередь.

Метод объектов и свойств

Усложним задачу так, чтобы скрипт научился обнаруживать и «партизан» :). Проще говоря, определить браузер однозначно, даже если он умеет маскироваться под своих коллег.

Теория

После некоторого анализа и не без помощи Google, было выяснено следующее:

  • Opera

    Умеет(умела) прикидываться другими браузерами. Но тем не менее, объект JavaScript window.opera поддерживают все версии оперы 5+. Вот она и спалилась. Кстати, этот же объект может выдать нам и версию: window.opera.version().

  • Chrome

    Так же имеет уникальный для себя объект window.chrome

  • Firefox

    C давних пор имеет, как минимум, объект window.sidebar и window.globalStorage, которые не поддерживают другие браузеры.

  • Safari

    Не легко его отделить от всех браузеров, тем не менее обнаружилось, что такой объект как window.external в Safari отсутствует (кстати, также его нет в Opera, но это не страшно).

  • IE

    Линейку IE выделить не составило большого труда. Такие объекты как window.all и window.ActiveXObject поддерживает только IE. Другой вопрос, как его разбить по версиям? Но и тут есть варианты:

    • IE 6

      Такое свойство как window.navigator.userProfile поддерживает только он

    • IE 8

      Появился объект window.Storage и window.Event, коих не было в предыдущих версиях.

    • IE 7

      Можно выделить методом исключения. А именно: по объекту window.Event или window.Storage, которые характерны для 8-й версии и все тому же свойству window.navigator.userProfile, которое характерно для 6-й.

Решение

Путём проверки на поддержку определенного объекта (свойтсва, метода), делаем вывод о браузере, а в некоторых случаях и о его версии (Opera, IE).

Пример функции:

function browserDetectJS() {
var
	browser = new Array();
	
//Opera
	if (window.opera) {
		browser[0] = "Opera";
		browser[1] = window.opera.version();
	}
		else 
//Chrome	
		if (window.chrome) {
			browser[0] = "Chrome";
		}
			else
//Firefox
			if (window.sidebar) {
				browser[0] = "Firefox";
			}
				else
//Safari 
					if ((!window.external)&&(browser[0]!=="Opera")) {
						browser[0] = "Safari";
					}
						else
//IE
						if (window.ActiveXObject) {
							browser[0] = "MSIE";
							if (window.navigator.userProfile) browser[1] = "6"
								else 
									if (window.Storage) browser[1] = "8"
										else 
											if ((!window.Storage)&&(!window.navigator.userProfile)) browser[1] = "7"
												else browser[1] = "Unknown";
						}
	
	if (!browser) return(false)
		else return(browser);
}

Демо пример. Проверено в:

Недостатки

Путём проверки поддержки объектов можно сделать вывод о марке практически любого браузера, но не всегда можно определить версию. Поэтому, если использовать такой способ, то там, где вывод о версии невозможно сделать на основании объектов, придётся брать версию из того же UserAgent.

Заметки

  • Конечно же, уникальных объектов для разных браузеров существует порядком больше, но на данный момент этого будет достаточно, дабы пробить браузер на поддерживаемые объекты.

Комплексный подход

Складываем оба метода в один файл, пишем «объединяющую» функцию с несколькими условиями и получаем на выход мини-библиотечку с тремя способами определения.

Пример объединяющей функции:

/*
	Набор функций для определения имени и версии браузера.
	
	Функция browserDetectNav - определение браузера при помощи объекта Navigator
	Функция browserDetectJS  - определение браузера при помощи JS объектов и св-в
	Функция getBrowser	 - делает вывод о браузере на основании обоих методов
	
	Формат входящих и исходящих данный у всех функций одинаков.
	Методы не зависимы друг от друга, можно использовать любой или вместе.
	
	Входящие параметры: 		chrAfterPoint - целое число,
						определяющее кол-во знаков после запятой в возвращаемой версии браузера.
						Если оставить пустым - вернет все знаки после запятой.
	Возвращаемые параметры: 	outputData - массив, где
					outputData[0] - имя браузера,
					outputData[1] - основная версия браузера (значение до запятой),
					outputData[2] - знаки версии после запятой (кол-во определяется входящим параметром)
						если возвращается "undefined" - браузер (или версия) не определен (неизвестный)
						если не возвращается версия (в некоторых случаях) - браузер "маскированый"
*/
function browserDetectNav(chrAfterPoint)
{
var
    UA=window.navigator.userAgent,       // содержит переданный браузером юзерагент
    //--------------------------------------------------------------------------------
	OperaB = /Opera[ /]+w+.w+/i,     //
	OperaV = /Version[ /]+w+.w+/i,   //	
	FirefoxB = /Firefox/w+.w+/i,     // шаблоны для распарсивания юзерагента
	ChromeB = /Chrome/w+.w+/i,       //
	SafariB = /Version/w+.w+/i,      //
	IEB = /MSIE *d+.w+/i,             //
	SafariV = /Safari/w+.w+/i,       //
        //--------------------------------------------------------------------------------
	browser = new Array(),               //массив с данными о браузере
	browserSplit = /[ /.]/i,           //шаблон для разбивки данных о браузере из строки
	OperaV = UA.match(OperaV),
	Firefox = UA.match(FirefoxB),
	Chrome = UA.match(ChromeB),
	Safari = UA.match(SafariB),
	SafariV = UA.match(SafariV),
	IE = UA.match(IEB),
	Opera = UA.match(OperaB);
		
		//----- Opera ----
		if ((!Opera=="")&(!OperaV=="")) browser[0]=OperaV[0].replace(/Version/, "Opera")
				else 
					if (!Opera=="")	browser[0]=Opera[0]
						else
							//----- IE -----
							if (!IE=="") browser[0] = IE[0]
								else 
									//----- Firefox ----
									if (!Firefox=="") browser[0]=Firefox[0]
										else
											//----- Chrom ----
											if (!Chrome=="") browser[0] = Chrome[0]
												else
													//----- Safari ----
													if ((!Safari=="")&&(!SafariV=="")) browser[0] = Safari[0].replace("Version", "Safari");
//------------ Разбивка версии -----------

	var
            outputData;                                      // возвращаемый функцией массив значений
                                                             // [0] - имя браузера, [1] - целая часть версии
                                                             // [2] - дробная часть версии
	if (browser[0] != null) outputData = browser[0].split(browserSplit);
	if ((chrAfterPoint==null)&&(outputData != null)) 
		{
			chrAfterPoint=outputData[2].length;
			outputData[2] = outputData[2].substring(0, chrAfterPoint); // берем нужное ко-во знаков
			return(outputData);
		}
			else return(false);
}

function browserDetectJS() {
var
	browser = new Array();
	
//Opera
	if (window.opera) {
		browser[0] = "Opera";
		browser[1] = window.opera.version();
	}
		else 
//Chrome	
		if (window.chrome) {
			browser[0] = "Chrome";
		}
			else
//Firefox
			if (window.sidebar) {
				browser[0] = "Firefox";
			}
				else
//Safari 
					if ((!window.external)&&(browser[0]!=="Opera")) {
						browser[0] = "Safari";
					}
						else
//IE
						if (window.ActiveXObject) {
							browser[0] = "MSIE";
							if (window.navigator.userProfile) browser[1] = "6"
								else 
									if (window.Storage) browser[1] = "8"
										else 
											if ((!window.Storage)&&(!window.navigator.userProfile)) browser[1] = "7"
												else browser[1] = "Unknown";
						}
	
	if (!browser) return(false)
		else return(browser);
}

function getBrowser(chrAfterPoint) {
var
    browserNav = browserDetectNav(chrAfterPoint),    // хранит результат работы функции browserDetectNav
    browserJS = browserDetectJS();                   // хранит результат работы функции browserDetectJS

// сравниваем результаты отработки двух методов
	if (browserNav[0] == browserJS[0]) return(browserNav)                //если одинаковый - возвращаем результат первого метода
		else
			if (browserNav[0] != browserJS[0]) return(browserJS) //если разный - возвращаем результат второго метода
				else
					return(false);                       //в случае, если браузер не определен
};

function isItBrowser(browserCom, browserVer, detectMethod) {
var browser;                                                      // контейнер для результатов обнаружения

switch (detectMethod) {                                           // определяемся какой из методов использовать (3-й параметр)
	case 1: browser = browserDetectNav(); break;	
	case 2: browser = browserDetectJS(); break;
	default: browser = getBrowser();
};

	if ((browserCom == browser[0])&(browserVer == browser[1])) return(true)                                 // если переданы два параметра и они совпали - возвращаем true
		else
			if ((browserCom == browser[0])&((browserVer == null)||(browserVer == 0))) return(true)  // если передан один параметр и он совпал - возвращаем true
				else return(false);	
};

Итого имеем:

  • browserDetectNav() — определяем браузер методом «Навигатора»
  • browserDetectJS() — определяем браузер методом JS объектов и свойств
  • getBrowser() — определяя браузер, прмиеняем сразу два метода для большей надежности
  • isItBrowser(browserName, [version]) — функция вернет true, если текущий браузер совпадает с указанным и false, если не совпадает

Скачать всё целиком можно тут:

Как использовать

  1. подключаем к странице вышеприведенный скрипт
  2. вызываем функцию getBrowser (например, при загрузке страницы — событие onload)
  3. условием отслеживаем нужный браузер, при необходимости и нужную версию, и выполняем какой-то ко для него

Варианты имен браузеров, которые возращает функция:

  • MSIE
  • Safari
  • Chrome
  • Opera
  • Firefox

Например, хотим «поймать» IE7:

<script type="text/javascript" src="path-to/bdetect.js"></script>
<script type="text/javascript">
function bdetect()
{
   getBrowser();
    /* ставим условие, в котором определяем нужный нам браузер и его версию */
   if(data[0]=="MSIE" && data[1]=="7")
   {
        какой-то код для IE7
   }
}
window.onload = bdetect;
</script>

или можно вот так:

<script type="text/javascript" src="path-to/bdetect.js"></script>
<script type="text/javascript">
function bdetect()
{
   if(isItBrowser("MSIE","7"))
   {
        какой-то код для IE7
   }
}
window.onload = bdetect;
</script>

Вывод

Если использовать оба метода в совокупности (вызывая функцию getBrowser), то через такой «фильтр» вероятность «просочиться» крайне мала, да и на практике не так часто приходится столь жестко придираться к бедным браузерам.

Заметки

  • за ИЕ6 было замечено неадекватное восприятие комментариев, поэтому, если вдруг он не захочет «определятся», рекомендую взять версию скрипта без комментариев