IE9: Як не треба перевіряти версію браузера або "чому не працюють фотки ВКонтакте" - Блог Костянтина Кичинського

Одна з усім відомих проблем веб-розробки, або точніше веб-верстки, - це питання сумісності створюваної або генерується верстки, включаючи розмітку на HTML і стилі на CSS, і використовуваних функцій (API) на JavaScript в різних версіях різних браузерів. У загальному випадку, це стосується далеко не тільки Internet Explorer і зокрема IE6 та IE7, а й усіх інших браузерів, тому що у всіх є баги і це просто даність з якої можна миритися або НЕ миритися і, наприклад, активно постити звіти про помилки на Microsoft Connect .

Сьогодні ми почнемо наше занурення в питання сумісності з одного неправильного сценарію і характерний приклад проблем, до яких це може призводити.

Хоча в якості прикладу я беру конкретний сайт і його код, це анітрохи не означає мого ставлення до ресурсу - це просто дуже характерний приклад, який зачіпає безліч користувачів.

Отже, ми маємо сайт і деяку кількість браузерів, які потрібно "детектувати", так як в залежності від браузера або його версії, поведінка браузера на одному і тому ж коді може відрізнятися. Визначати, хто саме до нас прийшов, можна як на стороні сервера, так і на стороні клієнта, як з якихось очевидним ознаками начебто User Agent String, так і за непрямими, начебто особливостей поведінки або підтримки тієї чи іншої функціональності.

// Conditional Comments <! - [if IE]> <! [Endif] -> // Unique Objects if (document.all) ... if (window.attachEvent) ... if (window.ActiveXObject) ... // Unique Behaviors (CSS Hacks, etc.) * html {}

На стороні клієнта досить часто можна бачити код приблизно такого змісту (приклад з vk.com):

var _ua = navigator.userAgent.toLowerCase (); var browser = {version: (_ua.match (/.+(?:me|ox|on|rv|it|ra|ie)[\/:] ([\ d.] +) /) || [0 , '0']) [1], opera: /opera/i.test(_ua), msie: (! this .opera && /msie/i.test(_ua)), msie6: (! this .opera && / msie 6 / i.test (_ua)), msie7: (! this .opera && / msie 7 / i.test (_ua)), msie8: (! this .opera && / msie 8 / i.test (_ua)) , mozilla: /firefox/i.test(_ua), chrome: /chrome/i.test(_ua), safari: (! (/ chrome / i.test (_ua)) && / webkit | safari | khtml / i. test (_ua)), iphone: /iphone/i.test(_ua), ipod: /ipod/i.test(_ua), iphone4: /iphone.*OS 4 / i.test (_ua), ipod4: / ipod . * OS 4 / i.test (_ua), ipad: /ipad/i.test(_ua), safari_mobile: /iphone|ipod|ipad/i.test(_ua), mobile: / iphone | ipod | ipad | opera mini | opera mobi / i.test (_ua)}

З цього прикладу добре видно міна відкладеної дії з Internet Explorer, яка обов'язково спрацює з виходом нової версії IE (і спрацювала з виходом IE9 Beta), не кажучи вже про "хитрощі" з Opera і поділом Сhrome і Safari, які обидва базуються на Webkit, але не зовсім однаково.

(Якщо код вище вам здається занадто складним, значить ви ще не бачили версію від Apple .)

Чому спрацює міна, описана вище? Вона не враховує майбутнього. Тому далі в коді (особливо великому) цілком можуть з'являтися (і з'являються) ділянки, що виглядають приблизно так:

if (browser.msie &&! browser.msie8) {...} else {...}

Це, очевидно, призводить до того, що для IE9 виконується точно така ж гілка коду, як для IE6 та IE7, і це не є запланованим розробниками сценарієм. Бум-с! Ми отримуємо фотографії ВКонтакте, що не перегортаються в IE9.

Ви можете детально подивитися, як це працює за допомогою відладчика в Dev Tools (F12). Також ви можете через Dev Tools поміняти User Agent String, наприклад, на Firefox, і переконатися, що в цьому випадку все працює коректно.

Висновок: якщо вам дійсно потрібно виконувати в код залежності від версії браузера, подумайте про майбутнє і поведінці ваших логічних виразів при зміні навколишніх умов.

Умова, наведене вище, може здатися природним (і навіть економним - замість двох перевірок зробили одну), якщо відштовхуватися тільки від справжнього:

Умова, наведене вище, може здатися природним (і навіть економним - замість двох перевірок зробили одну), якщо відштовхуватися тільки від справжнього:

Але як тільки на горизонті з'являються нові ввідні, умова перестає працювати "очікуваним" способом і починає робити саме те, що в ньому прописано:

Але як тільки на горизонті з'являються нові ввідні, умова перестає працювати очікуваним способом і починає робити саме те, що в ньому прописано:

Якщо дійсно потрібно відштовхуватися від версії браузера, наведене вище логічне вираз потрібно явно розкривати, щоб уникнути закладені в ньому пастки:

Якщо дійсно потрібно відштовхуватися від версії браузера, наведене вище логічне вираз потрібно явно розкривати, щоб уникнути закладені в ньому пастки:

Якщо хочеться відштовхуватися від номера версії, встановлюючи одну "роздільну лінію", то краще явно розділяти перевіркою на "більше-менше" номери версії, але ніяк не запереченням одного конкретного варіанту:

Якщо хочеться відштовхуватися від номера версії, встановлюючи одну роздільну лінію, то краще явно розділяти перевіркою на більше-менше номери версії, але ніяк не запереченням одного конкретного варіанту:

І просто для розуміння: є випадки, коли OS або браузер дійсно потрібно враховувати, причому не через багів або прогалин в підтримці того чи іншого стандарту. Наприклад, в тому ж ВКонтакте користувачам Mac-браузерів в деяких сценаріях пропонується використовувати Meta замість Ctrl, якого у них немає.

Чому спрацює міна, описана вище?