Когда я только начинал программировать, меня всегда удивляло, почему один и тот же код работает в Chrome, но ломается в Firefox или Internet Explorer. Это как готовить одно блюдо, но в каждой кухне — свои плиты, свои сковородки и свои хитрости. Сегодня мы разберем, как создавать JavaScript-решения, которые будут работать одинаково хорошо в любом браузере. Это не магия, а набор проверенных практик и инструментов.

Digital-студия WNDER

Ссылка на оригинальную статью

Почему браузеры такие разные?

Каждый браузер — это отдельный движок, который интерпретирует JavaScript по-своему. Chrome использует V8, Firefox — SpiderMonkey, Safari — JavaScriptCore. Они стараются придерживаться стандартов ECMAScript, но всегда есть нюансы. Например, какие-то методы могут быть реализованы с задержкой или иметь различия в поведении. Это как два переводчика, которые переводят одну и ту же книгу, но с разными стилями.

К тому же, старые браузеры, которые до сих пор используют некоторые пользователи, не поддерживают новейшие возможности. Поэтому задача разработчика — написать код так, чтобы он работал и на новом Chrome, и на древнем IE11 (если это еще актуально для вашего проекта).

Основные принципы кроссбраузерности

Чтобы не сойти с ума, следуйте простым правилам. Они сэкономят вам часы отладки.

  • Используйте полифиллы — это маленькие скрипты, которые добавляют недостающие функции в старые браузеры. Например, если IE не поддерживает метод Array.prototype.includes, вы можете подключить полифилл, который реализует его самостоятельно.
  • Проверяйте поддержку функций — перед использованием новой возможности, проверьте, есть ли она в браузере. Это делается с помощью простых условий, например, if ('includes' in Array.prototype).
  • Пишите семантичный код — избегайте хакерских приемов, которые зависят от конкретного браузера. Лучше использовать стандартные методы и свойства.
  • Тестируйте на реальных устройствах — не полагайтесь только на эмуляторы. Откройте ваш сайт на реальном iPhone, Android, старом ноутбуке с Windows.
Правило: Всегда начинайте с базового JavaScript, который поддерживается везде, а затем добавляйте улучшения для современных браузеров. Это называется прогрессивным улучшением.

Инструменты для автоматизации проверки

Вручную проверять каждый браузер — это долго и скучно. Но есть инструменты, которые делают это за вас. Они помогают обнаружить проблемы до того, как их увидят пользователи.

Инструмент Что делает Когда использовать
Can I Use Показывает поддержку функций во всех браузерах Перед использованием новой фичи
Babel Транспилирует современный JS в старый синтаксис При сборке проекта
Autoprefixer Добавляет вендорные префиксы для CSS При работе со стилями
BrowserStack Позволяет тестировать на реальных браузерах и устройствах Перед релизом

Например, вы решили использовать fetch для запросов к серверу. Прежде чем писать код, загляните на Can I Use и посмотрите, поддерживается ли он в нужных вам браузерах. Если нет — добавьте полифилл или используйте старый добрый XMLHttpRequest.

Практические примеры кода

Давайте посмотрим, как применять эти принципы на практике. Предположим, нам нужно сделать AJAX-запрос на сервер и вывести результат на страницу.


// Современный подход с fetch
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => {
    console.log(data);
  })
  .catch(error => console.error('Ошибка:', error));

Но в старых браузерах fetch может не работать. Тогда мы пишем универсальную функцию:


function loadData(url, callback) {
  if (window.fetch) {
    // Используем fetch, если он есть
    fetch(url)
      .then(response => response.json())
      .then(data => callback(null, data))
      .catch(error => callback(error));
  } else {
    // Иначе используем XMLHttpRequest
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          callback(null, JSON.parse(xhr.responseText));
        } else {
          callback(new Error('Ошибка: ' + xhr.status));
        }
      }
    };
    xhr.send();
  }
}

Этот код работает везде: и в современных браузерах, и в древних. Мы просто проверяем наличие fetch и выбираем подходящий способ.

Работа с DOM и событиями

Еще одна частая проблема — различия в работе с DOM. В старых браузерах могут быть свои особенности. Например, метод addEventListener появился не сразу, раньше использовали attachEvent. Но сейчас это уже не актуально, так как все современные браузеры поддерживают addEventListener. Однако есть другие нюансы.

Например, свойство innerText не работает в Firefox (до недавнего времени), поэтому лучше использовать textContent. Или при получении стилей элемента: getComputedStyle есть везде, но в старых IE он требует немного другой подход.


// Получаем стиль элемента кроссбраузерно
function getStyle(el, prop) {
  if (window.getComputedStyle) {
    return window.getComputedStyle(el)[prop];
  } else {
    return el.currentStyle[prop]; // для старых IE
  }
}

Вот такой простой лайфхак спасает от множества проблем.

Лайфхак: Если вы пишете функцию, которая работает с DOM, проверьте ее в Node.js с помощью jsdom. Это эмуляция браузерного окружения, которая помогает отловить ошибки до тестирования на реальных браузерах.

Тестирование и отладка

Никогда не выпускайте код без тестирования. Даже если вы уверены, что все работает, проверьте. Особенно если речь идет о кроссбраузерности.

  • Используйте консоль разработчика в каждом браузере. Там вы увидите ошибки и предупреждения.
  • Проверяйте не только функциональность, но и внешний вид. Иногда из-за особенностей CSS элементы могут съезжать.
  • Не забывайте про мобильные браузеры. Они часто имеют свои особенности.

Также стоит настроить автоматическое тестирование с помощью Selenium или Puppeteer. Это позволит запускать проверки на разных браузерах автоматически.

Сборка проекта с Babel и Webpack

Чтобы не писать код вручную под каждый браузер, используют сборщики. Они преобразуют современный JavaScript в старый синтаксис и объединяют файлы.

Пример настройки Babel:


// .babelrc
{
  "presets": ["@babel/preset-env"]
}

А в webpack.config.js мы указываем, что нужно применить Babel ко всем JS-файлам:


// webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
};

Теперь вы пишете современный код, а Babel превращает его в понятный для старых браузеров.

Заключение

Кроссбраузерная разработка — это не страшно, если подходить к ней с умом. Главное — помнить о различиях, использовать полифиллы и проверять код. Не пытайтесь поддерживать все браузеры подряд, определите, какие важны для вашей аудитории, и сосредоточьтесь на них.

Итак, что мы узнали:

  • Браузеры отличаются из-за разных движков и версий.
  • Используйте полифиллы и проверяйте поддержку функций.
  • Автоматизируйте проверки с помощью инструментов.
  • Пишите универсальный код, а не под конкретный браузер.

Теперь вы готовы создавать решения, которые будут работать везде. Удачи!

Студия WNDER