简体   繁体   中英

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>

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>

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.

To be honest, I can't agree to the example as its layout doesn't seem proper to me. The text "I am not." is innerHTML-text of the body element, if I'm not misleaded. If one properly puts this text into an element for its own -- as done with the text "I am in a shadow root," --, lets say by <p style="display:flex;align-items:center;height:50px;background:lightgreen">And I am not.</p> , you won't see the effect described.

I see the point of the question, but I don't see the relevance. It just reminds us to correctly layout our documents as intended in the specifications, also to avoid presumably implementation-dependend side-effects. If one doesn't use a hammer as intended, stuff may get broken, I suppose.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM