🎯 一句话总结
:scope
和@scope
二者都是指向被引用的元素本身。
:scope
是伪类用在 CSS / JS 选择器中。@scope
是新的 CSS 语法,类似社区的 CSS Module,用在 style 标签内。
下面从实际使用场景来说明。
:scope
用在 CSS 中 💅
假设有 HTML 结构如下,想让其本身是蓝色,子元素 p 是红色。
html
<section>
<p>...</p> // <- 目标
<div>
<p>...</p>
</div>
</section>
可以用这样一种 CSS 新范式来写:
html
<section>
<style>
@scope {...}
</style>
...
</section>
@scope
将范围限制在元素内部,:scope
指向元素本身,二者组合堪称完美!
html
<section>
<style>
@scope {
:scope { color: blue; } /* 选择 section 本身 */
:scope > p { color: red; } /* 选择子元素而非嵌套元素 */
}
</style>
<p>第一个子元素 color 为 red</p>
<div>
<p>第二个子元素继承 color 为 blue</p>
</div>
</section>
@scope
仅将样式限制在它所在的 DOM 节点的子元素上,而 :scope
选择器是一种为节点本身设置样式的方法。
这种写法下,即使我们用了很通用的 tag 选择器,仅却仅影响当前范围内的 p
,相当于 CSS Module。 在 section
之外的元素不受任何影响,隔绝仿若孤岛, 即非 red
也非 blue。
那和嵌套有何区别?
不用 @scope
和 :scope
原来我们需要这么写.
首先得给 section 增加 .parent
否则无法在 CSS 中选中。
html
<section class="parent">
...
然后嵌套:
html
<style>
.parent {
color: red
& > p:first-child {
color: red
}
}
</style>
嵌套写法的缺点:
- 需要增加 class ,而这个 class 如果仅为了 css,就显得有些多余,有时它只是一个临时起的名字,之所以存在只是因为没有其他方法。而"命名是计算机科学中最难的两件事之一"。
- 维护性差 :仔细观察
@scope
发现样式和 HTML 是紧密相连的,好处是不会出现臃肿的无用的 CSS,甚至以后都不敢删除(这也是 Vue 的单文件优于 React 的原因之一)。 - 会增加CSS权重 :而
@scope
并不会改变其权重,比如@scope { p }
p 仍然是0, 0, 1
:scope
用在 JS 中
比如,我们已经有一个元素(这是我们的前提),想获取其直接子元素。
html
<div id="parent">
<p>...</p> // <- 目标
<p>...</p>
</div>
假设我们已经获取到了 parent 元素
js
parent.querySelect('...') // 这里如何写能获取到第一个 p
注意下面写法是不对的,会报错非法的 CSS selector
js
parent.querySelect('> p') // ❌
Uncaught DOMException: Element.querySelector: '> div' is not a valid selector
答案:可以用 :scope
,因为它可以指代本身。
js
parent.querySelect(':scope > p')
🧠 总结
1 :scope
匹配的元素取决于它的使用上下文:
- 当在样式表的根级别使用时,
:scope
等效于:root
- 当在
@scope
块中使用时,:scope
匹配块所定义的作用域的根。 - 当在 DOM API 调用(例如
querySelector()
、querySelectorAll()
、matches()
或Element.closest()
)中使用时,:scope
匹配调用此类方法的元素。
2 @scope
CSS 规则使你能够选择特定 DOM 子树中的元素,精确地定位元素,而无需编写难以覆盖的过于具体的选择器 ,也无需将选择器与 DOM 结构过于紧密地耦合。
📚 参考
- picostitch.com/blog/2024/1...
- :scope MDN developer.mozilla.org/zh-CN/docs/...
- @scope MDN developer.mozilla.org/en-US/docs/...
🔍 扩展
除了 :scope
还有哪些特殊的伪类? 以下是一些类似的伪类选择器:
-
:root
:- 表示文档的根元素,通常是
<html>
元素。 - 示例:
:root { background-color: white; }
- 表示文档的根元素,通常是
-
:host
:- 在 Shadow DOM 中使用,表示 Shadow DOM 的宿主元素。
- 示例:
:host { display: block; }
-
:host-context()
:- 在 Shadow DOM 中使用,表示宿主元素的上下文环境。
- 示例:
:host-context(.dark-theme) { background-color: black; }
-
:is()
:- 用于组合多个选择器,匹配其中任意一个。权重取其中最大的。
- 示例:
:is(#header.header, #footer) h1 { color: green; }
权重为1-1-1
:is(#header.header, #footer)
权重为#header.header
的权重即1-1-0
- 加
h1
的0-0-1
,整体权重为1-1-1
-
:where()
:- 与
:is()
类似,但被其包裹的选择器的特异性或权重为 0,或者说不会增加权重 ,这也就是为何 antd 选择使用 where 而非 is 的原因。其次:where
还有一个好处内部存在无效的选择器并不会导致整体失效,is 同样如此。 - 示例:
:where(#header, #footer) h1 { color: green; }
即使存在 id 选择器,其整体权重仍然为h1 的权重0-0-1
。即便header h1 { color: violet; }
甚至h1 { color: violet; }
也能轻松将其覆盖。
- 与
无效的选择器并不会导致整体失效,`:is` 同样如此
-
:not()
:- 用于排除特定的选择器。
- 示例:
:not(.class1) { color: green; }
-
:has()
:- 用于选择包含特定子元素的元素。
- 示例:
:has(> .child) { background-color: yellow; }
-
:empty
:- 匹配没有子元素的元素(包括没有文本节点)。
- 示例:
p:empty { display: none }
隐藏所有空节点避免影响布局
这些内置关键词和伪类选择器在 CSS 中提供了强大的选择器功能,可以帮助开发者更精确地控制样式。