Переопределить стили в элементе 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.