#javascript #web-component
#javascript #веб-компонент
Вопрос:
У меня есть два пользовательских элемента:
<name-card data-color="#000000"></name-card>
<name-card data-color="#80B88C"></name-card>
который я применю data-color
к стилю.
Из того, что я задавал вопрос ранее, как получить cssRules, я получил ответ и добавил его attachedCallback()
для динамических изменений.
Но он просто показывает правильный цвет в chrome, другой браузер применил последний цвет, который относится #80B88C
к обоим.
Я проверил цикл в attachedCallback()
for(i = 0; i < rules.length; i ){
if(rules[i].selectorText === '.base'){
rules[i].style.background = bgColor;
}
}
и оба изменили правильный цвет, но я до сих пор понятия не имею, почему они будут применять последний цвет к стилю обоих элементов в safari и firefox.
Ответ №1:
Это связано с тем, что полизаполнение не может полностью реализовать изоляцию css.
Таким образом, таблица стилей CSS, которую вы добавляете в полизаполненный теневой DOM, фактически применяется ко всему документу. Когда одно и то же правило имени используется дважды, выигрывает последнее. Вот почему вы наблюдаете такое поведение в Safari и Firefox.
В вашем случае существует обходной путь для решения этой проблемы, который касается ::before
::after
псевдоэлементов и:
Текущее решение
- Создайте более конкретный
cssRule
, который включает определенный цвет:
Внутри attachedCallback()
функции:
sheet.insertRule( '[data-color=' bgColor '] .base::before { background: ' bgColor ' ; }', sheet.length )
Будущее решение
Когда будет реализована спецификация CSS 3 для attr()
всех свойств:
- Распространите цвет на целевые элементы и используйте функцию
attr()
CSS, чтобы применить правильный цвет, переданный атрибутом (data-color
в вашем примере).
Преимущество этого решения в том, что оно работает так же, как с полизаполнением и собственной реализацией, и с неограниченным количеством цветов.
В attachedCallback()
функции:
var targets = this.querySelectorAll( '.base' )
for ( var i = 0 ; i < targets.length ; i )
{
targets[i].dataset.color = bgColor
}
В <style>
элементе:
.base::before {
background: attr( data-color )
}
var proto = Object.create( HTMLElement.prototype )
proto.createdCallback = function ()
{
this.createShadowRoot()
var tmpl = document.querySelector( 'template' )
this.shadowRoot.appendChild( tmpl.content.cloneNode( true ) )
}
proto.attachedCallback = function ()
{
//get custom color
var bgColor = this.dataset.color
//add it to the top-level inside Shadow DOM
this.shadowRoot.querySelector( 'section' ).dataset.color = bgColor
//change the stylesheet in the next microtask
var style = this.shadowRoot.querySelector( 'style' )
setTimeout( function ()
{
var sheet = style.sheet
sheet.insertRule( '[data-color=' bgColor
'] .base::after { background: ' bgColor ' ; }'
, sheet.cssRules.length )
} )
}
document.registerElement( 'name-card', { prototype: proto } )
<name-card data-color="red"></name-card>
<name-card data-color="green"></name-card>
<template>
<style>
.base::after {
content: '-postfix' ;
}
</style>
<section>
<div>Custom Element</div>
<span class="base">Base element</span>
</section>
</template>
Комментарии:
1. Большое вам спасибо, сделали мой день. Но я использую решение cssRules, потому что мне нужно изменить стиль псевдоэлементов…. Я не могу изменить
::after
или::before
использовать ваше решение.2.Кажется, если я хочу исправить эту проблему, единственный способ — переписать css, используя
div
вместо:after
:before
right ? Тогда я могу использовать решение 1.3. Я не могу использовать
background: attr(data-color)
, он показывает недопустимое значение свойства — желтый треугольник. Кажется, cssattr()
просто работаетcontent
.4. Вы правы, это есть в спецификации, но еще не реализовано в borwsers! Таким образом, обходным путем является использование старого 2-го решения. Я обновляю свой ответ.
5.
insertRule()
вернемся к проблеме, просто работает в Chrome. safari и firefox показывают, что победит последний цвет. Применил цвет к обоим.