Safari не поддерживает пользовательские встроенные элементы и совместимость с ними
Браузер Safari не поддерживает пользовательские встроенные элементы, только автономные пользовательские элементы.
Давайте уточним, cуществует два вида пользовательских элементов(веб-компонентов):
- Автономные пользовательские элементы – «полностью новые» элементы, расширяющие абстрактный класс
HTMLElement. - Пользовательские встроенные элементы – элементы, расширяющие встроенные, например кнопку
HTMLButtonElementи т.п.

Поддержка браузерами Custom Elements
То есть Safari по умолчанию поддерживает только следующие веб-компоненты в формате HTML:
<ui-tips></ui-tips> <ui-drop></ui-drop> <ui-tab></ui-tab> <ui-lighttip></ui-lighttip>
Веб-компоненты, расширяющие собственные элементы HTML с помощью атрибута is, не поддерживаются:
<input is="ui-color"> <select is="ui-select"></select> <form is="ui-form"></form> <table is="ui-table"></table>
Из-за этого возникает проблема: UI-компоненты станут слишком многословными и муторными, если они могут быть реализованы только с использованием автономныХ пользовательских элементов.
Таким образом, лучшее решение — сделать так, чтобы браузер Safari также поддерживал разработку встроенных веб-компонентов.
Как это сделать?
Polyfill для встроенных веб-компонентов
Решение относительно простое, есть специальный полифилл, для тех случаев, когда поддерживаются автономные веб-компоненты, но не встроенные веб-компоненты, в основном для браузера Safari.
index.js — это несжатая версия, а es.js — сжатая версия.
Конечно же, правильнее было бы определять, поддерживает ли браузер пользователя встроенные веб-компоненты:
class AnyClass extends HTMLBRElement {
constructor () {
super();
this.someMethod = true;
}
}
if (!customElements.get('any-class')) {
customElements.define('any-class', AnyClass, {
extends: 'br'
});
}
const isSupportBuildIn = document.createElement('br', {
is: 'any-class'
}).someMethod;
Значение isSupportBuildIn будет true, если браузер поддерживает встроенные веб-компоненты, и undefined, если браузер не поддерживает.
Оптимизированный код JS можно посмотреть тут.
Проблемы с поддержкой
Этот Polyfill действительно удивителен, исходный код веб-компонентов не нуждается в каких-либо изменениях, функция компонента отлично поддерживается в браузере Safari, и все компоненты работают хорошо.
Но уже при использовании обнаруживается проблема, когда компоненты передаются со ссылками.
Например, у нас есть следующий код:
<script src="safari-polyfill.js">
<script type="module" src="my-components.js">
<script type="module">
myComponent.someMethod();
</script>
Метод myComponent.someMethod() отлично работает в браузерах, поддерживающих встроенные веб-компоненты. В то же время в Safari он сообщает об ошибке, и undefined не может быть выполнен как функция.
Причина этого в том, что реализация safari-polyfill.js имеет ограничение, из-за которого инициализация пользовательских элементов происходит позже, чем в нативных браузерах.
То есть в Safari при выполнении метода myComponent.someMethod() элемент myComponent еще не стал встроенным веб-компонентом.
В результате выполнение завершится ошибкой.
Можно использовать обходной путь: инициировать пользовательское событие 'connected' в функции connectedCallback (браузер вызывает этот метод при добавлении элемента в документ), чтобы элемент уже был разделен на компоненты, когда код выполняется путем привязки события connected.
connectedCallback () {
this.dispatchEvent(new CustomEvent('connected'), {
detail: {
type: 'my-components'
}
});
}
и тогда наш код будет выглядеть так:
<script src="safari-polyfill.js">
<script type="module" src="my-components.js">
<script type="module">
myComponent.addEventListener('connected', function () {
this.someMethod();
});
</script>
Это гарантирует, что веб-компонент уже будет инициализирован к моменту выполнения метода someMethod().
Ссылки по теме:
1. Оригинал статьи https://www.sobyte.net/post/2021-08/safari-buildin-custom-element-polyfill/
Последняя редакция 28 января, 2023 в 05:01