Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do display:flex do not respect shadow root border?

If you toggle display:flex on a shadow root child it also affects the element outside. (All big browsers behave like this.) Why?

There is a web component with a shadow root:

<web-comp style="display: inline-block;"></web-comp>

Inside the shadow root there is a div with display:flex:

div.style="display:flex; align-items:center; height:50px;"

The complete example:

class demo extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({mode: 'open'});
    
    const div = document.createElement('div');
    div.innerHTML= "I am in a shadow root!"
    div.style="display:flex;align-items:center;height:50px;background:lightblue"
    shadow.appendChild(div);
  }
}
customElements.define('web-comp', demo);
  <h3>flexbox styles do not respect shadow root border</h3>

   <web-comp style="display: inline-block;"></web-comp>
And I am not.

   <button onclick="document.querySelector('web-comp').shadowRoot.querySelector('div').style.alignItems='baseline'">
   Click to change 'align-items' of div in shadow root.
   </button>
like image 859
danyball Avatar asked Oct 16 '25 05:10

danyball


2 Answers

I understand your confusion as this actually does look like styles from within the shadow root “bleeding out” their shadow boundaries.

However, all the spec guarantees is that rules declared inside the shadow root don’t apply to elements outside. It does not prevent second-order layout effects to affect the rendering of outside elements.

One trivial example where this happens is when an element inside shadow root changes size:

const hasShadow = document.querySelector('.has-shadow');
const shadow = hasShadow.attachShadow({mode: 'closed'});
const div = document.createElement('div');
while(hasShadow.firstChild) {
div.append(hasShadow.firstChild);
}
shadow.append(div);
document.querySelector('button').addEventListener('click', () => {
div.style.height = `${Math.random()*100+25}px`;
});
.wrapper {
  display: flex;
}
.has-shadow {
background: rebeccapurple;
}
.no-shadow {
background: red;
}
<button>Change shadow size</button>
<div class="wrapper">
  <div class="has-shadow">I can haz shadow</div>
  <div class="no-shadow">I can haz light</div>
</div>

Here, when the element in shadow root changes its height, the element outside also has to change height. This may be obvious because we encounter it all the time that we don’t give it much thought.

What’s happening in your case is very similar, just not with height but with baseline.

Because your shadow-root-containing element is set to inline block, it takes part in a baseline-sharing group, the same one that also contains the text “And I am not.”

Now, why, you may ask, does the baseline-sharing group extend into the inner <div>. Doesn’t that generate a block, since it is set to display: flex, not display: inline-flex? Well, this is true, but, inside an inline-block element, this does not break out of the baseline-sharing group. There is nothing special about the shadow root in this, non-shadow elements behave the same way:

<div style="display: inline-block;">
  <div style="display:flex;align-items:center;height:50px;background:lightblue">
    I am in an inline-block!
  </div>
</div>
And I am not.
like image 52
Raphael Schweikert Avatar answered Oct 18 '25 20:10

Raphael Schweikert


Yes, there is an effect, but normal behaviour for inline-block elements with fixed height,

See the green margins. Its the display-block and fixed DIV height that make you think flex affects the <span> elements. It has nothing to do with those elements being Web Components. You can replace the Web Components with DIVs. It is standard CSS Block behavior

<style>
  web-comp {
    display: inline-block;
    background: lightgreen;
    padding: 1em; /* becomes the "margin" above <span> */
  }
  span { background: pink }
</style>
<h3>Click the light green boxes</h3>
<div style="background:green">
  <web-comp></web-comp>
  <span>span</span>
  <span>span</span>
  <span>span</span>
  <web-comp></web-comp>
  <span>span</span>
  <span>span</span>
</div>

<script>
  customElements.define('web-comp', class extends HTMLElement {
    connectedCallback() {
      this.attachShadow({mode:'open'})
          .append(this.div = document.createElement('div'));
      this.div.style = "display:flex;height:60px";
      this.DIValign("center");
      this.onclick = () => {
        if (this.div.style.alignItems == "center") this.DIValign("baseline");
        else this.DIValign("center");
      };
    }
    DIValign(val) {
      this.div.innerHTML = ` align-items: ${this.div.style.alignItems = val}`;
    }
  })
</script>
like image 25
Danny '365CSI' Engelman Avatar answered Oct 18 '25 20:10

Danny '365CSI' Engelman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!