javascriptcssweb-component

getComputedStyle() returns nothing, but getComputedStyle().getPropertyValue() returns as expected


I am trying to move an element from the light DOM to the shadow DOM, but when I do so the styling isn't copying over. I tried to fix this by setting the newElement.style = window.getComputedStyle(elem), but this hasn't seemed to work. The styles should be:

.card {
    color: #ff0;
    font-size: 3rem;
    font-weight: 600;
    border: 3px solid blueviolet;
    background-color: greenyellow;
}

but the styles don't apply and when I print the getComputedStyle() to console what I see is: all the values are empty

However, when I loop through the properties of getComputedStyle() with .getPropertyValue() like so:

for(let property of style){
    console.log(`property: ${property}, value: ${style.getPropertyValue(property)}`);
}

what I get in the console is: the correct values

So I'm confused as to why getComputedStyle() doesn't contain the values, but using getComputedStyle().getPropertyValue() returns the correct values. I'm sure I'm missing something obvious, as I couldn't find another post about this anywhere.

Any help would be greatly appreciated, thanks in advance.

EDIT: I've taken the code provided by Danny below and modified it to better show the issue I'm facing:

<style>
  .card {
    color: yellow;
    background: green;
  }
</style>

<my-element>
  <div class="card">lightDOM reflected to shadowDOM</div>
</my-element>

<script>
  customElements.define("my-element", class extends HTMLElement {
    constructor(){
        super().attachShadow({mode:"open"}).innerHTML = ``;
    }
    connectedCallback() {
      setTimeout(() => { // wait till innerHTML is parsed
        let card = this.children[0]; // Get the light DOM Card element
        this.shadowRoot.appendChild(card.cloneNode(true)); // Append it to the shadowDOM
        let style = window.getComputedStyle(card); // Get style of the Light DOM Card
        this.shadowRoot.querySelector('.card').style = style; // Set the ShadowDOM card style equal to the Light DOM Style
        console.log(style);
        console.log(style.color);      // yellow = rgb:255,255,0
        console.log(style.background); // green  = rgb:0,128,0
        card.remove(); // Remove the card from the Light DOM to prevent duplication
      })
    }
  })
</script>

Notice that the styling above doesn't apply even though it seems to be exactly as the docs specify: "The returned object is the same CSSStyleDeclaration type as the object returned from the element's style property. However, the two objects have different purposes:


Solution

  • From MDN Documentation:

    The Window.getComputedStyle() method returns an object containing the values of all CSS properties of an element, after applying active stylesheets and resolving any basic computation those values may contain. Individual CSS property values are accessed through APIs provided by the object, or by indexing with CSS property names.

    It's stated that you need to use API functions, such as getPropertyValue() to get the value of it.

    Ref: https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle

    If you want to print all of the CSS styles from a specific element you may just iterate all the attributes like this:

    function dumpCSSText(element){
      var s = '';
      var o = getComputedStyle(element);
      for(var i = 0; i < o.length; i++){
        s+=o[i] + ': ' + o.getPropertyValue(o[i])+';\n';
      }
      return s;
    }
    
    var e = document.querySelector('.card');
    console.log(dumpCSSText(e));
    .card {
        color: #ff0;
        font-size: 3rem;
        font-weight: 600;
        border: 3px solid blueviolet;
        background-color: greenyellow;
    }
    <div class="card"></div>