Устаревший тег <shadow> был точкой подстановки в Shadow DOM первой версии. Он нужен был, когда у одного компонента создавали несколько shadow root: тег показывал внутри нового дерева содержимое старого. Браузеры его убрали, и теперь для них это неизвестный тег. Тег парный: закрывающий </shadow> нужен.
Под фразой «тег shadow» часто имеют в виду тень в CSS: box-shadow, text-shadow или drop-shadow(). Все они собраны в таблице ниже. А вместо устаревшего тега используют slot и вложенные компоненты.
<shadow></shadow>
В этой статье
Тег shadow в HTML: что это за устаревший тег
Shadow DOM прячет часть разметки компонента от остальной страницы. Эту скрытую часть называют shadow root. В первой версии у одного компонента могло быть несколько таких скрытых деревьев, одно над другим. Тег shadow, записанный в новом дереве, показывал на своём месте содержимое старого: так компонент мог дополнить предыдущий, а не заменить его.
У тега нет собственных атрибутов, кроме глобальных. Во второй версии Shadow DOM у компонента остался один shadow root, а передачей содержимого занимается slot. Для вложенных компонентов используют обычную вложенность: внутренний компонент находится в shadow root внешнего.
<shadow></shadow>
Какие ещё бывают shadow: тень в CSS и Shadow DOM
Слово shadow встречается в нескольких местах HTML и CSS, и ни одно из них не является тегом shadow. Эти значения собраны в таблице ниже. Отдельно есть атрибут shadowrootmode у template: он создаёт shadow root прямо в разметке.
| Где встречается | Что это | Пример |
|---|---|---|
box-shadow | свойство CSS: тень вокруг блока | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); |
text-shadow | свойство CSS: тень от текста | text-shadow: 1px 1px 2px gray; |
filter: drop-shadow() | функция CSS: тень по контуру картинки, учитывает прозрачность | filter: drop-shadow(2px 2px 4px black); |
| shadow root | скрытая часть компонента в Shadow DOM, а не тег | el.attachShadow({ mode: "open" }) |
template shadowrootmode | атрибут, который по стандарту создаёт shadow root прямо из разметки | <template shadowrootmode="open">...</template> |
Как браузер читает shadow в разметке
Для браузера shadow неизвестный тег. Его класс HTMLUnknownElement, а display по умолчанию inline. Текст внутри остаётся обычным текстом страницы. Класса HTMLShadowElement и метода createShadowRoot в браузере больше нет, остался только attachShadow.
const s = document.querySelector("shadow");
console.log(s.constructor.name, typeof HTMLShadowElement);
Пример: как браузер читает shadow
Кнопки меняют запись. Под ней показаны класс тега, размер и наличие старых классов браузера.
Работает ли shadow внутри shadow root
Нет. Если записать shadow в современный shadow root, содержимое компонента не покажется: сам компонент имеет высоту 0. Содержимое выводит только slot. Чтобы собрать компонент из нескольких слоёв, внешний slot передают внутрь вложенного компонента.
Пример: shadow и slot внутри shadow root
Кнопки меняют запись в shadow root. Высоты и назначенные слоты измерены в рамке.
Какие браузеры понимали shadow
Версии такие же, как у тега content. В Safari тега не было.
Пример: таблица версий
| Браузер | С какой версии | Убран в версии |
|---|---|---|
| Chrome | 35 | 89 |
| Edge | 79 | 89 |
| Firefox | 33, только с включённым флагом | 59 |
| Opera | 26 | 75 |
| Safari | не было | нет |
Чем заменить shadow: slot и вложенные компоненты
Вместо подстановки старого дерева используют slot, о котором подробнее рассказано на странице про content. Если нужно собрать компонент из нескольких слоёв, внешний компонент помещает внутрь себя внутренний, а slot внешнего компонента записан внутри внутреннего, и у внутреннего в shadow root есть свой slot, который его принимает.
const outer = host.attachShadow({ mode: "open" });
outer.innerHTML = '<div id="inner"><slot></slot></div>';
const inner = outer.getElementById("inner").attachShadow({ mode: "open" });
inner.innerHTML = "<slot></slot>";
Такую сборку показывает последняя кнопка демо: содержимое компонента проходит через оба слота и показывается.
Частые ошибки с тегом shadow
| Ошибка | Что получится | Как исправить |
|---|---|---|
<shadow></shadow> внутри Shadow DOM | Содержимое компонента не показывается, его высота равна 0 | Записать <slot></slot> |
Свойство shadow: 0 2px 4px gray в CSS | Такого свойства нет, браузер запись игнорирует, тени нет | Писать box-shadow для блока или text-shadow для текста |
createShadowRoot() вместо attachShadow() | Ошибка TypeError: такого метода в браузере больше нет | Писать attachShadow({ mode: "open" }) |