为什么 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 按预期工作的必要之恶。
当一个组件有一些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 按预期工作的必要之恶。