W3docs

Совместимость с браузерами

Узнайте, как браузеры по-разному отображают HTML, CSS и JavaScript, и как писать кросс-браузерный код с помощью определения возможностей, CSS.supports, полифилов и прогрессивного улучшения.

Обеспечение совместимости с браузерами — критически важный аспект веб-разработки. Разные браузеры могут по-разному интерпретировать и отображать HTML, CSS и JavaScript, что приводит к несоответствиям в отображении и работе веб-страниц. В этом руководстве объясняется, почему возникают такие различия, как браузеры строят DOM, и описываются конкретные техники для написания кода, работающего везде: определение возможностей (в JavaScript и CSS), полифилы, прогрессивное улучшение и постепенное ухудшение.

Золотое правило, проходящее через всё это: определяйте возможности, а не браузеры. Проверять, что умеет браузер, — надёжно; проверять, каким браузером он представляется (через строку navigator.userAgent), — нет: строки user-agent легко подделываются, постоянно меняются и перестают работать при выходе новой версии браузера.

Понимание проблем совместимости

Почему возникают проблемы совместимости

Проблемы совместимости возникают потому, что разные браузеры используют разные движки рендеринга и реализуют возможности в разное время. Например, Chrome использует движок Blink, Firefox — Gecko, а Safari — WebKit. Каждый движок реализует одни и те же веб-стандарты, но новый API может появиться в одном движке на несколько месяцев раньше другого, а в старых или ограниченных браузерах (корпоративный IE, встроенные веб-просмотрщики, киоски) он может не появиться вообще. Результатом становятся различия как в рендеринге, так и в поведении JavaScript.

Типичные проблемы совместимости

  1. Различия в CSS-разметке: Разное толкование CSS браузерами приводит к различиям в макете и стилях.
  2. Функциональность JavaScript: Некоторые возможности JavaScript могут поддерживаться одним браузером, но не поддерживаться другими.
  3. Поддержка HTML5 и CSS3: Новые возможности HTML5 и CSS3 могут не поддерживаться одинаково во всех браузерах.
  4. Пробелы в DOM API: Метод узла DOM (например, element.closest() или element.replaceChildren()) может отсутствовать в старых движках и вызывать TypeError во время выполнения.

Как разные браузеры работают с DOM

Движки рендеринга браузеров

Каждый браузер использует собственный движок рендеринга для интерпретации и отображения веб-контента:

  • Chrome и Edge: Blink
  • Firefox: Gecko
  • Safari: WebKit

Эти движки разбирают HTML, применяют CSS и выполняют JavaScript для построения и отображения DOM. Поскольку DOM — это живое представление в памяти, с которым работает JavaScript, любое различие в том, какие методы DOM предоставляет движок, напрямую влияет на то, какой код выполнится. Именно поэтому скрипты, работающие в одном браузере, могут выдавать ошибки в другом — проблема редко в «синтаксисе», чаще в том, что «этот метод здесь не существует».

Пример: работа с CSS Grid Layout

<!DOCTYPE html>
<html>
<head>
    <title>CSS Grid Example</title>
    <style>
        .container {
            display: grid;
            grid-template-columns: 1fr 1fr;
        }
        .item {
            padding: 20px;
            background-color: lightblue;
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="item">Item 1</div>
        <div class="item">Item 2</div>
    </div>
</body>
</html>

Этот пример демонстрирует базовый CSS Grid Layout. Хотя современные браузеры полностью поддерживают CSS Grid, Internet Explorer 11 поддерживает только более старую нестандартную версию спецификации, что может вызывать проблемы с макетом, если не использовать префиксы или полифилы.

Инструменты и техники для обеспечения кросс-браузерной совместимости

Инструменты тестирования

  1. Инструменты разработчика в браузере: Встроенные инструменты в браузерах, такие как Chrome DevTools, Firefox Developer Tools и Safari Web Inspector, помогают отлаживать и тестировать проблемы совместимости.
  2. Сервисы кросс-браузерного тестирования: Инструменты вроде BrowserStack и Sauce Labs позволяют тестировать сайт в разных браузерах и на разных устройствах.

Техники

  1. Используйте CSS-сбросы: Нормализуйте или сбрасывайте CSS для обеспечения единообразных стилей в разных браузерах.
  2. Полифилы и шимы: Используйте JavaScript-библиотеки, добавляющие недостающие возможности в старые браузеры.
  3. Прогрессивное улучшение: Сначала реализуйте основную функциональность, затем улучшайте её для более современных браузеров.
  4. Autoprefixer: Автоматически добавляйте вендорные префиксы к CSS-правилам для обеспечения совместимости с разными браузерами.

Использование определения возможностей

Введение в определение возможностей

Определение возможностей проверяет, поддерживает ли браузер ту или иную функцию перед её использованием, чтобы код мог перейти к запасному варианту вместо того, чтобы выдавать ошибку. Это современная альтернатива анализу user-agent.

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

// Detect a DOM/Web API: is the property or method actually there?
if ('clipboard' in navigator && navigator.clipboard.writeText) {
  navigator.clipboard.writeText('copied!');
} else {
  // Fallback for browsers without the async Clipboard API
  console.log('Clipboard API not available — use a manual fallback');
}

// Detect a method on an element before calling it
const el = document.querySelector('.item');
if (el && typeof el.closest === 'function') {
  el.closest('.container');
}

К числу распространённых вещей, которые стоит проверять таким же образом, относятся: 'fetch' in window, 'IntersectionObserver' in window, 'localStorage' in window (завёрнутый в try/catch, так как приватный режим может выдавать ошибку) и 'serviceWorker' in navigator.

Определение поддержки CSS из JavaScript

Для CSS-возможностей браузеры предоставляют метод CSS.supports(). Он возвращает boolean, что позволяет принимать решения по стилизации в JavaScript:

if (window.CSS && CSS.supports('display', 'grid')) {
  document.body.classList.add('has-grid');
} else {
  document.body.classList.add('no-grid'); // ship a flexbox/float fallback
}

// You can also pass a full condition string:
CSS.supports('(gap: 1rem) and (display: flex)'); // true / false

Использование Modernizr для определения возможностей

Modernizr — популярная JavaScript-библиотека, которая определяет поддержку функций HTML5 и CSS3 в браузере пользователя.

<!DOCTYPE html>
<html>
<head>
    <title>Modernizr Example</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/3.12.1/modernizr.min.js"></script>
</head>
<body>
    <div id="feature-check"></div>
    <script>
        if (Modernizr.canvas) {
            document.getElementById('feature-check').textContent = 'Canvas is supported!';
        } else {
            document.getElementById('feature-check').textContent = 'Canvas is not supported.';
        }
    </script>
</body>
</html>

В этом примере Modernizr используется для проверки поддержки браузером элемента HTML5 <canvas> и вывода соответствующего сообщения.

Для CSS можно использовать правило @supports, чтобы применять стили только при поддержке возможности:

.container {
  display: flex;
}
@supports (display: grid) {
  .container {
    display: grid;
  }
}

Правило @supports — это CSS-аналог CSS.supports(): базовое объявление (display: flex) является запасным вариантом, а улучшенный макет применяется только там, где браузер понимает grid.

Полифилы и прогрессивное улучшение

Когда возможность отсутствует, существуют две стратегии, решающие разные проблемы:

  • Полифил — загрузка небольшого скрипта, который добавляет недостающий API, чтобы обычный код работал без изменений. Используйте это, когда возможность необходима (например, старый браузер не поддерживает fetch, поэтому вы загружаете полифил для fetch). Недостаток — дополнительный вес, загружаемый каждым посетителем, если не загружать его условно.
  • Прогрессивное улучшение / постепенное ухудшение — создание работающей базовой версии, не требующей продвинутых возможностей, с последующим добавлением улучшений там, где они поддерживаются. Страница функционирует и без них.

Условная загрузка полифила снимает нагрузку с современных браузеров:

// Only fetch the polyfill if the browser actually needs it
if (!('IntersectionObserver' in window)) {
  const script = document.createElement('script');
  script.src = 'https://cdn.jsdelivr.net/npm/[email protected]/intersection-observer.js';
  document.head.appendChild(script);
}
// ... otherwise modern browsers pay nothing extra

Поскольку определение возможностей и fetch API часто используются вместе, защищайте сетевой код таким же образом перед тем, как полагаться на него.

Лучшие практики

  1. Тестируйте рано и часто: Регулярно тестируйте веб-страницы в разных браузерах и на разных устройствах в процессе разработки.
  2. Используйте определение возможностей: Применяйте определение возможностей, чтобы сайт корректно работал во всех браузерах.
  3. Применяйте адаптивный дизайн: Используйте техники адаптивного дизайна, чтобы сайт хорошо выглядел на всех размерах экрана и при любой ориентации.
  4. Следите за изменениями в браузерах: Отслеживайте последние разработки и изменения в технологиях браузеров и веб-стандартах.
  5. Сначала проверяйте таблицу поддержки: Прежде чем принять API, найдите его на caniuse.com или MDN, чтобы узнать, какие браузеры его поддерживают и существует ли полифил.
Внимание

Избегайте анализа user-agent (navigator.userAgent) для выбора пути выполнения кода. Строки UA поддаются подделке и постоянно меняются, поэтому определение незаметно ломается при выходе следующей версии браузера. Вместо этого определяйте саму возможность с помощью in, typeof, CSS.supports() или @supports.

Информация

Используйте определение возможностей (и библиотеки вроде Modernizr там, где они экономят время), чтобы сайт корректно обрабатывал неподдерживаемые возможности, предоставляя запасные варианты и единообразный опыт во всех браузерах.

Заключение

Обеспечение кросс-браузерной совместимости необходимо для предоставления единообразного пользовательского опыта. Понимая, почему браузеры различаются, тестируя рано в разных движках и определяя возможности вместо анализа браузеров — а затем подкрепляя определение полифилами или прогрессивным улучшением, — вы сможете создавать надёжные веб-приложения, работающие для всех.

Чтобы глубже изучить DOM, с которым вы обеспечиваете совместимость, ознакомьтесь со статьями Работа с DOM, Поиск: getElement, querySelector и Введение в события браузера.

Практика

Практика
Какие из следующих утверждений о совместимости DOM с браузерами верны?
Какие из следующих утверждений о совместимости DOM с браузерами верны?
Was this page helpful?