Определение браузера и его версии
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.chromeFirefox
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, если не совпадает
Скачать всё целиком можно тут:
Как использовать
- подключаем к странице вышеприведенный скрипт
- вызываем функцию getBrowser (например, при загрузке страницы — событие onload)
- условием отслеживаем нужный браузер, при необходимости и нужную версию, и выполняем какой-то ко для него
Варианты имен браузеров, которые возращает функция:
- 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 было замечено неадекватное восприятие комментариев, поэтому, если вдруг он не захочет "определятся", рекомендую взять версию скрипта без комментариев
Обновление ver 1.1
Недавний проект натолкнул на мысль, которая "обсасывается" в сети уже долгое время и имеет как уйму сторонников, так и противников. А именно: просить(требовать) юзера обновить браузер для адекватного отображения сайта. Решений и идей по этому вопросу сегодня существует масса, каждый волен выбрать себе более подходящую сам. Я же предлагаю небольшое дополнение к плагинчику bdetect.
Просим обновиться
Не всегда трудности нам приносит наш "горячо любимый ИЕ6", есть масса(а современем она только увеличивается) приёмов и css-правил(CSS3), кои уже можно успешно применять глядя на актуальные версии браузеров, но есть люди которым лень или некогда обновить свой браузер(я говорю сейчас об Opera, Mozzila и т.п), более того, даже у заказчиков порой обнаруживаются старые версии(недавно вычислилась Opera древнее 10.10)... Но ближе к "телу", как говорится, итак функция checkBrowser():
/* checkBrowser(params = { warning: [string], // окончание шаблонной фразы "Версия Вашего браузера BBBBB (ver ХХ.ХХ) {warning}" message: [string], // основное сообщение question: [string], // сам вопрос "Не желаете ли?" (у каждого свой подход к людям) :) chrome: [float], // минимально-допустимые версии браузеров safari: [float], msie: [float], opera: [float], firefox: [float], chromeLink: [string], // ссылки на обновление safariLink: [string], msieLink: [string], operaLink: [string], firefoxLink: [string] }) */ function checkBrowser(){ if (!params.chromeLink) params.chromeLink = ''; if (!params.safariLink) params.safariLink = ''; if (!params.msieLink) params.msieLink = ''; if (!params.operaLink) params.operaLink = ''; if (!params.firefoxLink) params.firefoxLink = ''; if (!params.warning) params.warning = 'устарела!rnrn' else params.warning += 'rnrn'; if (!params.question) params.question = 'Хотите ли обновить версию своего браузера?'; if (!params.message) params.message = '' else params.message += 'rnrn'; if (!params.chrome) params.chrome = 6; if (!params.safari) params.safari = 5; if (!params.msie) params.msie = 6; if (!params.opera) params.opera = 10.5; if (!params.firefox) params.firefox = 3.5; var browser = getBrowser(1), browserName = browser[0], browserVer = browser[1], browserVerPoints = browser[2], browserVer = parseFloat(browserVer+"."+browserVerPoints), systemMessage = 'Версия Вашего браузера '+browserName+'(ver '+browserVer+') '+params.warning+params.message+params.question, bLink = ''; switch (browserName) { case 'Chrome': if (browserVer >= params.chrome) return false else bLink = params.chromeLink; break; case 'Safari': if (browserVer >= params.safari) return false else bLink = params.safariLink; break; case 'MSIE': if (browserVer >= params.msie) return false else bLink = params.msieLink; break; case 'Opera': if (browserVer >= params.opera) return false else bLink = params.operaLink; break; case 'Firefox': if (browserVer >= params.firefox) return false else bLink = params.firefoxLink; break; }; var conf = confirm(systemMessage); if (conf == true) document.location.href = bLink else return false; };
Ничего супер особенного, функция, предлагает обновить браузер, если его версия ниже минимально-допустимой. По умолчанию, минимальные версии установлены такие:
- Chrome 6
- Safari 5
- IE 5.5
- Opera 10.5
- Firefox 3.5
Линки на обновление:
А также фраза по умолчанию: "Версия Вашего браузера {имя браузера}(ver {версия}) устарела! Хотите ли обновить версию своего браузера?"
Все вышеперечисленное будет справедливо при вызове "голой" функции: checkBrowser().
Результат(я специально завысил минимальные версии, дабы увидеть диалог)
Своя рубаха...
Поскольку каждая верстка уникальна и у каждого web-разработчика своё представление о вежливости и корректности, то любой из параметров можно задать при вызове функции, я задам все:
checkBrowser (params = { warning: 'уже немного несвежая!', message: 'Так как Ваш браузер самый лучший и быстрый, то Вы можете сделать его еще лучше и быстрее.', question:'Не хотите ли Вы, многоуважаемый юзер, обновить свой, безспорно, лучший браузер в мире?', chrome: 10, safari: 10, msie: 9, opera: 11, firefox: 4 });
Скачать:
- - 5кб
- - 2кб