vuejs / vue-loader

📦 Webpack loader for Vue.js components
MIT License
4.99k stars 914 forks source link

Scoped Style Sheets Leaking Styles #1091

Open angeltcj opened 6 years ago

angeltcj commented 6 years ago

Version

13.5.0

Reproduction link

https://codesandbox.io/s/vnkl6y2737?module=%2FApp.vue

Steps to reproduce

Currently, the scope of style sheets is achieved by adding an attr selector to the last compound selector (aka sequence of simple selectors).

It works just fine in most cases. However, not on complex selectors (more specifically those which contain combinators).

Take the .a .b selector as an example. It becomes .a [data-v-xxx].b. It works as expected in most cases, but not all:

<div class="a"></div>
  <template>
    <!-- wrongly matches the selector -->
    <div class="b"></div>
  </template>
</div>

Note that even though the matched element is inside the component, it depends on an element which is outside. Not supposed to happen. Also note that it can happen with all the 4 combinators;

What is expected?

That selectors of scoped style sheets only match elements if all of the elements involved in the match are inside the component.

What is actually happening?

Even though the matched element is always inside the component, the other elements involved in the match (that made it possible) may not be.


The solution is actually very simple: instead of adding the attr selector only to the last compound selector, add it to both the first and last compound selectors (adding to all would be redundant) to make sure all elements involved in the match are actually inside of it. .a .b would become [data-v-xxx].a [data-v-xxx].b.

Problem solved. But... now we have another problem: selectors specificity. Some selectors will receive one extra attr selector while others will receive two. This means that it may change the specificity order of selectors. To overcome this issue, we need to make sure all selectors will receive the same amount of specificity, which means .a should become .a[data-v-xxx][data-v-xxx]. This might look like a hack but it's totally valid.

From the W3C CSS3 Selectors Specification: "Repeated occurrances of the same simple selector are allowed and do increase specificity".

Jinjiang commented 6 years ago

I have opened a PR to fix it. And yes the selectors specificity becomes a problem in this way. So maybe more discussion needed here. Thanks.