Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Web components: custom elements

Web components: собственные элементы и теневой DOM

Web components: регистрация элемента, теневой DOM, свойства и события, доступность собственных элементов.

Прямой ответ

Собственный элемент регистрируется в браузере по имени с дефисом, поэтому разметка получает поведение без подключения библиотеки компонентов.

Часть API Что определяет
customElements.define Регистрацию имени элемента
shadowRoot Изоляцию разметки и стилей
observedAttributes Атрибуты, на изменение которых элемент реагирует
Событие Сообщение элемента внешнему коду
class InfoCard extends HTMLElement {
  static get observedAttributes() { return ["title"]; }
  connectedCallback() {
    const root = this.attachShadow({ mode: "open" });
    root.innerHTML = `<h2>${this.getAttribute("title")}</h2><slot></slot>`;
  }
}
customElements.define("info-card", InfoCard);

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

Регистрация элемента и имя

Регистрация связывает имя элемента с классом, поэтому имя выбирается по правилам, отличающим собственный элемент от стандартного.

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

Регистрация имени. Связь имени с классом устанавливается один раз, поэтому повторная регистрация того же имени отклоняется.

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

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

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

Теневой DOM и изоляция стилей

Теневой корень изолирует разметку и стили элемента, поэтому оформление компонента не затрагивает остальную страницу.

Изоляция разметки. Содержимое теневого корня не участвует в селекторах страницы, поэтому стили страницы не применяются к содержимому элемента.

Изоляция стилей. Стили элемента не выходят за пределы теневого корня, поэтому оформление компонента не затрагивает страницу.

Слот для содержимого. Место вставки внешнего содержимого, поэтому элемент принимает разметку из страницы.

Практическое следствие: стили страницы, заданные глобально, не применяются к содержимому теневого корня, поэтому оформление элемента задаётся внутри компонента.

Свойства, события и доступность

Собственный элемент объявляет свойства и события, поэтому взаимодействие с элементом выполняется через открытый интерфейс, а не через внутреннюю разметку.

Атрибуты и свойства. Значение атрибута отражается в свойстве, поэтому изменение значения объявляется явно.

Событие элемента. Элемент сообщает об изменении событием, поэтому внешний код реагирует без обращения к внутренней разметке.

Объявление назначения. Элемент объявляет роль и состояние, поэтому вспомогательная технология читает назначение компонента.

Практическое следствие: собственный элемент без объявления роли читается как неопределённый блок, поэтому назначение компонента недоступно.

О частичной гидратации — в статье про islands architecture; о семантике — в статье про семантическую разметку HTML.

Шаблон компонента и повторное использование

Шаблон определяет исходную разметку элемента, поэтому экземпляр компонента создаётся из единого описания без дублирования разметки.

Шаблон разметки. Описание содержимого элемента хранится отдельно, поэтому экземпляр создаётся копированием шаблона при подключении.

Единое описание. Изменение шаблона применяется ко всем экземплярам, поэтому правка выполняется в одном месте вместо правки каждой копии.

Стоимость создания. Копирование шаблона выполняется при подключении экземпляра, поэтому число экземпляров определяет время создания разметки.

Практическое следствие: разметка, заданная строкой внутри каждого экземпляра, дублируется, поэтому изменение содержимого требует правки всех мест задания.

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

Практика: создание собственных элементов

1. Используйте имя с дефисом. Имя без дефиса отклоняется при регистрации, поскольку зарезервировано.

2. Регистрируйте элемент до отображения разметки. Период неактивного состояния элемента сокращается.

3. Изолируйте стили теневым корнем. Оформление компонента не затрагивает остальную страницу.

4. Предусматривайте слот для внешнего содержимого. Элемент принимает разметку из страницы.

5. Объявляйте наблюдаемые атрибуты. Элемент реагирует на изменение значения атрибута.

6. Сообщайте об изменении событием. Внешний код реагирует без обращения к внутренней разметке.

7. Объявляйте роль и состояние элемента. Назначение компонента доступно вспомогательной технологии.

Рекомендации:

  1. Не обращайтесь к внутренней разметке теневого корня извне. Взаимодействие выполняется через свойства и события элемента.
  2. Учитывайте период до регистрации элемента. Разметка отображается без поведения до подключения кода.
  3. Сопоставляйте состав атрибутов с открытым интерфейсом. Значение, не объявленное атрибутом, не отражается в свойстве.
  4. Фиксируйте проверку доступности компонента в процессе разработки. Отсутствие объявления роли обнаруживается до выпуска.
  5. Пересматриваем интерфейс элемента при изменении поведения. Новое состояние требует объявления атрибутом и событием.

Практический сценарий: компонент читался как пустой блок

Контекст: собственный элемент отображался корректно, но вспомогательная технология объявляла его как неопределённый блок без названия.

  1. Диагностика. Проверка показала, что элемент не объявлял роль и состояние, а содержимое находилось в теневом корне. Вспомогательная технология читала внешний элемент без сведений о назначении, поскольку внутренняя разметка изолирована.
  2. Причина. Открытый интерфейс элемента не содержал объявления роли и состояния, поэтому назначение компонента не передавалось.
  3. Действия. (а) Добавили объявление роли элемента, соответствующей назначению компонента; (б) объявили состояние атрибутом, чтобы изменение читалось без обращения к теневому корню; (в) связали видимое название с элементом, чтобы объявление содержало название; (г) вынесли интерактивные части в элементы с семантикой, чтобы назначение определялось разметкой; (д) проверили чтение компонента вспомогательной технологией и убедились в объявлении роли и названия.
  4. Результат. Компонент объявляет роль, название и состояние, поэтому назначение доступно без обращения к внутренней разметке.

Вывод: изоляция теневого корня скрывает внутреннюю разметку от страницы, поэтому компонент без объявления роли читается как неопределённый блок. Объявление роли, названия и состояния в открытом интерфейсе элемента делает назначение доступным.

FAQ

Почему имя собственного элемента должно содержать дефис? Имя без дефиса зарезервировано для стандартных элементов, поэтому регистрация отклоняется.

Что даёт теневой корень? Изоляцию разметки и стилей компонента. Стили страницы не применяются к содержимому элемента, и наоборот.

Как внешний код взаимодействует с компонентом? Через свойства и события элемента. Обращение к внутренней разметке теневого корня извне не выполняется.

Нужно ли объявлять роль собственного элемента? Да, компонент без объявления роли читается вспомогательной технологией как неопределённый блок.

Источники: HTML Custom Elements, W3C Shadow DOM, MDN Web Components — ссылки в шапке.