sheetify icon indicating copy to clipboard operation
sheetify copied to clipboard

Styles bleed through

Open simplesmiler opened this issue 9 years ago • 2 comments

Example:

/* comment.css */
:host .header {
  color: blue;
}
/* article.css */
:host .header {
  color: red;
}
<article class="_article-hash">
  <h1 class="header">Article title</h1>
  <section class="comments">
    <article class="_comment-hash">
      <h2 class="header">Comment title</h2>
    </article>
  <section>
</article>

Comment header will be either red or blue, depending on the order of file inclusion. You can guard with > selectors, but this makes your CSS dependent on the exact DOM structure.

Shadow DOM naturally does not suffer from this. BEM does not suffer from this, due to using unique names. CSS Modules does not suffer from this, due to rewriting all class names. Vue implementation of scoped styles does not suffer from this, due to rewriting HTML too and using different prefixing technique (<div class="header" _article-hash> and .header[_article-hash]).

simplesmiler avatar Jun 28 '16 15:06 simplesmiler

Oops, yeah - good point, thanks for finding this and reporting it. Bit swamped with work right now, so don't quite have time to fix this. What do you propose the solution is to this?

yoshuawuyts avatar Jun 28 '16 16:06 yoshuawuyts

The simplest solution I can think of is following the Vue approach with a slight change:

:host -> ._hash .compound > .selector => .compound._hash > .selector._hash.

<article class="${articleHash}">
  <h1 class="${articleHash} header">Article title</h1>
  <section class="${articleHash} comments">
    <article class="${commentHash}">
      <h2 class="${commentHash} header">Comment title</h2>
    </article>
  <section>
</article>

This way whenever you reference a "local" class, you need to add the hash. But to do this manually is still cumbersome and error-prone.


Another solution is following the CSS Modules approach and rewriting classes:

:host -> ._host-hash .compound > .selector => ._compound-hash > ._selector-hash.

<article class="${article.$host}">
  <h1 class="${article.header}">Article title</h1>
  <section class="${article.comments}">
    <article class="${comment.$host}">
      <h2 class="${comment.header}">Comment title</h2>
    </article>
  <section>
</article>

With this approach the library needs to worry about case, because JavaScript does not support the - in the names of variables. So the library either:

  • Needs to promote using camelCase classes, like CSS Modules does (otherwise developer would have to write something like class="${comment['snake-case']}", which is far from being nice),
  • Needs to promote snake-case and convert to camelCase internally.

simplesmiler avatar Jun 28 '16 16:06 simplesmiler