стиль веб-компонента применен ко всем в safari и Firefox с использованием webcomponentsjs

#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) , он показывает недопустимое значение свойства — желтый треугольник. Кажется, css attr() просто работает content .

4. Вы правы, это есть в спецификации, но еще не реализовано в borwsers! Таким образом, обходным путем является использование старого 2-го решения. Я обновляю свой ответ.

5. insertRule() вернемся к проблеме, просто работает в Chrome. safari и firefox показывают, что победит последний цвет. Применил цвет к обоим.