Вы пишете код, тестируете в Chrome — всё летает. Открываете в Safari — половина не работает. Знакомо? Кроссбраузерность — это боль каждого фронтендера. Но есть хорошая новость: с правильным подходом можно писать код, который будет работать везде, от старого IE до нового Firefox.
Почему браузеры такие разные?
Каждый браузер использует свой движок для отображения страниц и выполнения JavaScript. Chrome и Edge работают на V8, Firefox — на SpiderMonkey, Safari — на JavaScriptCore. Это как разные переводчики: один понимает шутки, другой — нет. Добавьте сюда разные версии браузеров, и получите зоопарк, где каждый зверь хочет особого подхода.
Проблемы обычно возникают в трёх местах:
- Синтаксис — новые фичи вроде optional chaining или nullish coalescing поддерживаются не везде.
- API — методы вроде
Array.prototype.flat()илиfetchмогут отсутствовать. - Поведение — даже одинаковый код может давать разный результат из-за багов или различий в реализации.
Правило первое: не доверяй, проверяй
Самый простой способ — использовать feature detection. Это когда вы спрашиваете у браузера: «Эй, ты умеешь это делать?» И если нет — используете запасной вариант.
// Плохо: сразу используем fetch
fetch('/api/data')
.then(response => response.json())
.then(data => console.log(data));
// Хорошо: проверяем поддержку
if (window.fetch) {
fetch('/api/data')
.then(response => response.json())
.then(data => console.log(data));
} else {
// Фолбэк для старых браузеров
var xhr = new XMLHttpRequest();
xhr.open('GET', '/api/data');
xhr.onload = function() {
if (xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send();
}
Для проверки методов массивов или строк можно использовать такой трюк:
if (!Array.prototype.flat) {
Array.prototype.flat = function(depth) {
// Полифилл для flat
var flattened = [];
function flatten(arr, d) {
for (var i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i]) && d > 0) {
flatten(arr[i], d - 1);
} else {
flattened.push(arr[i]);
}
}
}
flatten(this, depth === undefined ? 1 : depth);
return flattened;
};
}
Полифиллы и транспиляция: два подхода к одной цели
Есть два основных способа сделать код совместимым:
- Полифиллы — это код, который добавляет недостающую функциональность. Вы просто включаете библиотеку, и старый браузер начинает понимать новые методы.
- Транспиляция — это когда вы пишете современный код, а специальный инструмент (например, Babel) превращает его в старый синтаксис, который понимают все браузеры.
Вот сравнение популярных инструментов:
| Инструмент | Тип | Что делает | Когда использовать |
|---|---|---|---|
| Babel | Транспилятор | Преобразует новый синтаксис в старый | Когда пишете на ES6+ и нужна поддержка IE11 |
| core-js | Полифилл | Добавляет недостающие методы и объекты | Когда нужны новые API в старых браузерах |
| Polyfill.io | Сервис | Автоматически подгружает нужные полифиллы | Для быстрого прототипирования |
На практике чаще всего используют комбинацию: Babel для синтаксиса и core-js для API.
Практические советы и лайфхаки
Вот несколько приёмов, которые сэкономят вам часы отладки:
- Используйте
addEventListenerвместоattachEvent. Старый IE требовал attachEvent, но сейчас это неактуально. Если всё же нужно — проверяйте наличие метода. - Осторожно с
event. В старых браузерах объект события передавался как глобальная переменнаяwindow.event. Всегда принимайте его как аргумент функции. - Не используйте
innerText. Этот метод нестандартный. ЛучшеtextContent, который работает везде. - Проверяйте
localStorage. В приватном режиме Safari он может быть недоступен. Оборачивайте в try/catch.
try...catch для работы с API, которые могут быть недоступны. Это лучше, чем проверять существование каждого метода.
// Вместо проверки каждого метода
if (window.localStorage) {
try {
localStorage.setItem('key', 'value');
} catch (e) {
// Обработка ошибки, если хранилище переполнено или недоступно
console.warn('LocalStorage недоступен:', e);
}
}
Ещё один важный момент — работа с CSS. Иногда браузеры по-разному применяют стили. Например, flexbox в старых версиях требовал префиксов. Но это уже больше про CSS, чем про JavaScript. Однако если вы динамически меняете стили через JS, учитывайте это.
Автоматизация проверки кроссбраузерности
Вручную тестировать в каждом браузере — это ад. К счастью, есть инструменты, которые помогают:
- Can I use — сайт, где можно проверить поддержку любой фичи.
- BrowserStack или Sauce Labs — облачные сервисы для тестирования в разных браузерах.
- ESLint с плагином compat — статически анализирует код и предупреждает о несовместимых конструкциях.
Вот пример настройки ESLint для проверки совместимости:
// .eslintrc.js
module.exports = {
plugins: ['compat'],
rules: {
'compat/compat': 'error'
},
env: {
browser: true,
es6: true
},
parserOptions: {
ecmaVersion: 2020
}
};
Этот плагин будет ругаться, если вы используете метод, который не поддерживается в указанных браузерах. Указываете в настройках browserslist, и он проверяет.
Заключение
Кроссбраузерность — это не магия, а набор простых правил и инструментов. Главное — не писать код вслепую, а проверять поддержку и использовать полифиллы. Помните: ваш код должен работать не только у вас на компьютере, но и у бабушки с планшетом на Android 5.
Начните с малого: добавьте feature detection, подключите Babel и core-js, настройте ESLint. Через неделю вы заметите, что багов стало меньше, а уверенности — больше. И да, не забывайте тестировать в Safari. Он всегда подкидывает сюрпризы.
Студия WNDER



