为什么 Svelte 不将标签的范围限定在 class 下,而是使用单独的 tag.class 来设置组件样式?

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

当一个组件有一些CSS样式时,自然要用

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

确定样式范围,但 Svelte 使用

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

将其实际限定在某个 class(顶级方法)下是否更稳健,因为至少在 HTML 标记内,编译后的代码可以是:

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

而不是每次都重复 class 名称。 (而且我认为特异性是相同的:1 class 和 1 个标签名称)。

因为 Svelte 不需要单个顶级元素。

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

事实上,它甚至根本不需要元素。

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

随便...如果没有根元素,单个包装 class 策略不适用。

此外,这样做不仅会作用于当前组件,还会作用于当前组件 及其子组件 。考虑这个例子:

<!-- 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>

App.svelte 中的 <span> 不是 Scoped 组件的 部分,但它是它的子组件,在 DOM.

注意:如果您希望限定当前组件及其子组件的范围,技巧是使用 :global 伪选择器:

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

div 选择器样式有作用域,所以我们只针对此组件的子项(DOM 明智),而不是以上。

你是对的,特异性水平是一样的,但是这个规则:

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

假设有一个元素包裹了 h1,在 Svelte 中从来没有这种情况。组件没有默认的父 HTML 元素,也不应该有。

例如,如果您检查此 REPL;尽管其中一个 h1 标签源自导入的组件,但两个 h1 标签在编译后的标记中彼此相邻,如下所示:

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

如果采用自然方式,则 Svelte 必须将编译后的标记修改为如下所示:

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

当使用依赖于父子关系的 css-flex 或网格时,这会导致不可预知的结果。因此,尽管元素的重复类名对于经常检查浏览器的人来说可能很烦人(大多数用户不这样做),但它是允许 CSS 按预期工作的必要之恶。