nonopolarity
nonopolarity

Reputation: 150976

Why doesn't Svelte scope the tag under a class but use individual tag.class to style a component?

When a component has some CSS styles, it is natural to use

.my-component-01 h1 { ... }
.my-component-01 h2 { ... }

to scope the styles, but Svelte uses

h1.svelte-hlsza1{color:orange}
h2.svelte-hlsza1{background:yellow}

Is it more robust to actually scope it under a certain class (the top method) instead, because at least inside the HTML markup, the compiled code can just be:

<div class="svelte-hlsza1">
  <h1> ...
  <h2> ...

instead of repeating the class name every time. (and I think the specificity is the same: 1 class and 1 tag name).

Upvotes: 0

Views: 1372

Answers (2)

JHeth
JHeth

Reputation: 8346

You're correct that the level of specificity is the same but this rule:

.my-component-01 h1 { ... }

is assuming that there is an element that wraps the h1, in Svelte this is never the case. There is no default parent HTML element to components and there should not be.

If you inspect this REPL for example; despite one of the h1 tags originating from an imported component both h1 tags are right next to one another in the compiled markup like so:

<body>
  <h1 class="svelte-1k0q8ta">This is green</h1>
  <h1 class="svelte-1wsvnfu">This is red</h1>
</body>

If the natural way were to be the case then Svelte would have to modify the compiled markup to be something like this:

<body>
  <someelement class="my-component-01">
    <h1>This is green</h1>
  </someelement>
  <someelement class="my-component-02">
    <h1>This is red</h1>
  </someelement>
</body>

This would cause unpredictable results when using css-flex or grid which depend on parent-child relationships. So although the repeated classnames for elements may be annoying for someone who inspects the browser often (most users don't) it's a necessary evil that allows CSS to work as expected.

Upvotes: 2

rixo
rixo

Reputation: 25001

Because Svelte doesn't require a single top level element.

<!-- no problem for Svelte -->
<h1>...</h1>
<h2>...</h2>

In fact it doesn't even require elements at all.

<script>...</script>
<!-- this is the end of the component (still no problem for Svelte) -->

Whatever... Without a root element, the single wrapping class strategy is not applicable.

Also, doing so would not scope only to the current component, but to the current component and its children. Consider this example:

<!-- Scoped.svelte -->
<style>
   span { color: red }
</style>

<div>
  <span>I should be red</span>
</div>

<slot />
<!-- App.svelte -->
<script>
  import Scoped from './Scoped.svelte'
</script>

<Scoped>
  <span>I should not be red</span>
</Scoped>

The <span> in App.svelte is not part of the Scoped component, but it is a child of it, in the DOM.

Note: if scoping to the current component and its children is what you want, the trick is to use the :global pseudo selector:

<style>
  /* note that you do need a wrapping element, this time, to do that */
  div :global(span) { color: blue }
</style>

The div selector style gets scoped, so we're only targeting children of this component (DOM wise), not above.

Upvotes: 4

Related Questions