Переопределить стили в элементе shadow-root
Есть ли способ изменить стили, найденные в теневом элементе? В частности, расширить/переписать некоторые свойства, найденные в классе CSS? Я использую расширение Chrome под названием Beanote, которое не обновлялось с апреля (2017 года), и есть неприятная ошибка, которую я хотел бы исправить. Я обнаружил, что одна строка CSS исправляет это достаточно для меня, но я затрудняюсь применить его, не заходя внутрь самого элемента тени и непосредственно редактируя эти стили в инструментах разработки.
Я ищу способ для этого:
/*global css rule*/
.the-class-name { property-name: my-value; }
переписать это:
/* style tag inside the shadow-root */
.the-class-name { property-name: bad-value; }
Большинство ресурсов, которые я нашел в Интернете с запросами, включающими shadow-root override style
или edit shadow-root styling
shadow-root override style
edit shadow-root styling
имели какое-то отношение к :host
который, если он предназначен для этого, не работает для моих нужд или устаревших функций, таких как ::shadow
.
Ответы
Ответ 1
Из-за изоляции стилей, которая является функцией Shadow DOM, вы не можете определить глобальное правило CSS, которое будет применяться в области Shadow DOM.
Это может быть возможно с переменными CSS, но они должны быть явно реализованы в затененном компоненте (что не имеет место с этой сторонней библиотекой).
Обходной путь - внедрить линию стиля непосредственно в теневой DOM.
//host is the element that holds the shadow root:
var style = document.createElement( 'style' )
style.innerHTML = '.the-class-name { property-name: my-value; }'
host.shadowRoot.appendChild( style )
NB: это будет работать только если Shadow DOM mode
установлен в положение 'open'
.
Обновление 2019 года для Chrome 73+ и Opera 60+
Теперь можно напрямую создать экземпляр объекта CSSStyleSheet и связать его с Shadow DOM или документом:
var sheet = new CSSStyleSheet
sheet.replaceSync( '.color { color: pink }')
host.shadowRoot.adoptedStyleSheets = [ sheet ]
Ответ 2
Ionic V4 выберите пример изменения цвета значка вниз
document.querySelector('#my-select').shadowRoot.querySelector('.select-icon-inner').setAttribute('style', 'opacity:1');
ionViewDidEnter() {
document.querySelector('#my-select').shadowRoot.querySelector('.select-icon-inner').setAttribute('style', 'opacity:1');
}
Если вы хотите перезаписать сгенерированный по умолчанию стиль shadowRoot, тогда вам нужно вызвать функцию js после полной загрузки страницы.
Ответ 3
Продолжая предыдущие ответы.
Внешние стили всегда побеждают стили, определенные в Shadow DOM, т.е. Когда вы добавляете глобальное правило стиля, которое ссылается на стилизуемый вами компонент. Смотрите: https://developers.google.com/web/fundamentals/web-components/shadowdom#stylefromoutside
Это будет зависеть от того, был ли встроен теневой DOM элементов с styleSheet
, или если он принял таблицу стилей с использованием adoptedStyleSheets
.
Если элемент был встроен в элемент, вы можете добавить или вставить правило в существующую таблицу стилей, используя addRule
или insertRule
. Это также работает для таблиц стилей, добавленных с adopedStyleSheets
.
Как упоминалось в предыдущем ответе, вы можете вместо этого добавить новую таблицу стилей в список принятых таблиц стилей. Это также работает, когда shadowRoot содержит встроенную styleSheet
, так как adoptedStyleSheets
имеет приоритет, и styleSheetList
не может быть изменен напрямую, так как это свойство только для чтения.
assert(myElement.shadowRoot.styleSheets.length != 0);
myElement.shadowRoot.styleSheets[0].addRule(':host', 'display: none;');
assert(myElement.shadowRoot.adoptedStyleSheets.length != 0);
'myElement.shadowRoot.adoptedStyleSheets[0].addRule(':host', 'display: none;');'
const sheet = new CSSStyleSheet();
sheet.replaceSync(':host { display: none; }');
const elemStyleSheets = myElement.shadowRoot.adoptedStyleSheets;
// Append your style to the existing style sheet.
myElement.shadowRoot.adoptedStyleSheets = [...elemStyleSheets, sheet];
// Or if just overwriting a style set in the embedded 'styleSheet'
myElement.shadowRoot.adoptedStyleSheets = [sheet];
Ответ 4
Я хотел бы поддержать ответ, данный @Renato в одном из комментариев, поскольку он указывает на хороший, IMHO, способ решения проблемы настройки веб-компонента из хост-приложения.
@Supersharp прав в том факте, что внешние правила CSS не распространяются в Shadow Root, а по замыслу.
Переменные CSS - это хорошее направление, но из моего личного опыта это немного излишне для значения единственного использования, И да, они ДОЛЖНЫ поддерживаться, если WebComponent заранее.
Распространение свойств через :host
через наследование (в точности как упомянуто @Renato), IMHO, является совершенно правильным шаблоном, выровненным по дизайну API:
- Пользовательские элементы (
:host
's) CSS-правила по дизайну могут быть переопределены внешними правилами -
:host
children, внутреннее содержимое Shadow DOM, МОЖЕТ наследовать CSS-правила :host
, по умолчанию или по явному правилу - и это тоже по замыслу
Я бы сказал, что, где это применимо, этот подход лучше использовать перед рассмотрением внедрения таблицы стилей CSS, и он также не страдает только ограничением open
режима.
Конечно, этот подход не поможет, когда:
- Внутренние элементы не наследуют соответствующие правила от
:host
- Структура WebComponent довольно сложна, так что единственное
:host
просто не может помочь им всем
Тем не менее, опять же из моего собственного опыта, простые компоненты с желаемыми переопределяемыми правилами CSS могут извлечь большую пользу из ненавязчивого шаблона распространения правил через :host
.