-
Notifications
You must be signed in to change notification settings - Fork 40
过程式修饰规则
过程式(procedural)修饰过滤的概念是从 uBlock Origin(uBO)1.8.0 版本开始引入的。
过程式修饰过滤首次实现是在被修订为允许链接/递归使用过程式操作符的 1.11.0+ 版本。抛开常识,它在可链接(chained)的操作符数量,或可递归的层级方面没有任何限制,但 1.17.5rc1 之前的版本不支持在过程式选择符后面链接原生的 CSS 选择符。
请仅在普通 CSS 选择符无效的情况下使用过程式修饰规则。
常规的修饰规则是 声明式 (declairative) 的,即作为一条 CSS 规则内的选择符来使用,并通过 style
标签的元素被各浏览器处理。
过程式 表示 Javascript 代码会查找它必须隐藏的 DOM 元素。一条过程式修饰规则会使用修饰规则 操作符 来告诉 uBO 如何查找或筛选 DOM 元素,以便找到目标 DOM 元素。
-
过程式修饰规则始终必须是专用的,即必须附带所生效的站点主机名作为前缀。如果一条过程式修饰规则是通用的,即在任何网站均生效,则 uBO 会忽略这条规则。举例来说,一条好规则必须是专用的,比如这样:
example.com##body > div:has-text(Sponsored)
;一条坏规则是因为它是通用的,比如这样:##body > div:has-text(Sponsored)
。而元素选择器始终会为规则自动添加主机名作为前缀以确保规则是专用的。 -
高效的过程式修饰规则(或任何修饰规则)的定义是其作用结果只会访问最少的节点集合。元素选择器的输入框会显示与当前规则匹配的元素数量。元素选择器只考虑第一个换行符之前所输入的文本,其余部分则保持不变。你可以利用这个功能拆分你的规则来找到规则前半部分节点集合的数量:只有具有最少数量节点集合的修饰规则才是最高效的。
-
目前还不支持在一条规则里将多个过程式选择符连接在一起。
example.com##p:has(img),div:has-text(advert)
这样的规则还无法正常使用(#453)。 -
使用 CSSTree 库的全新修饰规则解析器。新的解析器不再使用浏览器 DOM 来校验修饰规则是否有效,而是使用 JS 库和 CSSTree。这意味着规则列表作者得更加仔细,确保修饰规则是真实有效的。因为现在不能保证一条针对特定浏览器及其版本生效的修饰规则也能在其他浏览器,或该浏览器的其他版本中生效。新的解析器带来了破坏性的改变,且这种改变没法回头。部分现有的过程式修饰规则会失效,具体请见相应的 commit 消息。
-
你应当使用引号避免过程式修饰规则操作符中的参数产生问题。现在引号被解释的方式接近于 AdGuard 文档中关于引号的使用方式,除了以下 uBO 特有的:
- 如果参数不触发解析器,可以不使用引号
- 引号可以使用
"
,也可以使用'
- 使用引号时,在参数里相同引号的实例必须被转义,即
'这是一个单引号:\''
,或"这是一个双引号:\""
,\
的实例必须被转义(按照 AdGuard 的文档)。根据这个 commit 消息,转义时不带引号是无效的,所以##sidebar > div.side-content:has-text(Adoring Anya\'s twitter)
这条是无效的,但###sidebar > div.side-content:has-text(/Adoring Anya\'s twitter/)
还是有效的。
这个操作符是 uBO 1.15.0 中 :if(...)
出现语义上变动,两者类似
- 描述:选择 subject 元素,当且仅当满足在 subject 元素的上下文(context)里对 arg 进行估值(evaluate)后返回一个或多个元素这个条件。
- 是否可链接(Chainable):是。
- subject:可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
- arg:可以是在 subject 元素的上下文中估值了的有效的普通 CSS 选择符或过程式修饰规则。
- 示例:
mobile.twitter.com##main [role="region"] > [role="grid"] > [role="rowgroup"] [role="row"]:has(div:last-of-type span:has-text(/^Promoted by/))
strikeout.me##body > div:has(img[alt="AdBlock Alert"])
-
yandex.ru##.serp-item:has(:scope .organic > .organic__subtitle > .label_color_yellow)
-:scope
强制要求.organic
在.serp-item
内部匹配(为什么需要:scope
,通用的:scope
文档) -
strdef.world##div[style]:has(> a[href="https://www.streamdefence.com/index.php"])
->
强制要求a
必须是div[style]
的直接子孙节点
这个 :has(arg)
操作符实际上是 CSS4 计划实现的伪类,但现阶段还不被任何浏览器支持(2022年8月30日之后的基于 Chromium 105+ 稳定通道的浏览器已经支持了)。与其他浏览器厂商等待提供支持不同的是,uBO 现在就以过程式操作符的形式提供了对 :has(arg)
的支持。
也可参见::upward()
vs :has()
- 描述:选择 subject 元素,当满足 subject 元素或它的子孙元素内包含 needle 文本这个条件。
- 是否可链接:是。
- subject:可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
-
needle:必须是可找到的文本或正则表达式。如果是正则表达式,你可以选择同时或分别使用
i
和m
标记(1.15 版本)。
现在 :has-text()
可以在空字符串前后添加引号来匹配该空字符串(1.45.3b10 版本新增):##foo:has-text("")
- 示例:
-
example.com##body > div:last-of-type span:has-text(/^Promoted by/)
:以 “Promoted by” 打头 -
example.com##body > div:last-of-type span:has-text(/^Promoted by/i)
:以 “Promoted by” 打头,忽略大小写 -
example.com##body > div:last-of-type span:has-text(Promoted by)
: 在任意位置出现 “Promoted by”
-
- 描述:允许通过其属性添加一个元素,特别是属性是随机的。
- 是否可链接:是。
- subject:可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
-
arg:以
name="value"
或"name"="value"
形式的声明,其他name
是属性名,value
是属性值(可选的),name
和value
可以是文本或正则表达式。
该操作符从 uBO 1.45.3b10 版本开始引入,
它解决了 uBlockOrigin/uBlock-issues#2329 (comment) 提到的随机生成属性值的问题。
所支持的语法与 AdGuard 文档中提到的一样:
虽然是推荐使用引号,但如果参数不触发解析器导致失败或者不产生歧义,uBO 不作强制要求。
- 示例:
k-rauta.fi##button:matches-attr(class="/[\w]{7}/")
k-rauta.fi##button:matches-attr("class"="/[\w]{7}/")
来自 https://www.k-rauta.fi/tuote/valmistasoite-hole-in-1-250ml/6408070100905
- 选择 subject 元素,当且仅当满足对 arg 进行估值的结果是一个或多个元素这个条件。
- 是否可链接:是。
- subject:可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
-
arg:以
name: value
形式的声明,其中name
是一个有效的 CSS style 属性,value
是该 style 属性期望的值。value
可以是文本或正则表达式。- 文本:值必须 严格 匹配浏览器的 getComputedStyle 方法所返回的属性值。
- 正则表达式:你可以选择同时或分别使用
i
和m
标记(1.15 版本)。
- 示例:
extratorrent.*##body > div[class]:matches-css(position: absolute)
facet.wp.pl##div[class^="_"]:matches-css(background-image: /^url\("data:image/png;base64,/)
和 :matches-css(...)
一样,除了是对 subject 元素的 :before
伪类查找对应的 style 属性。
和 :matches-css(...)
一样,除了是对 subject 元素的 :after
伪类查找对应的 style 属性。
- 描述:允许对媒体进行查询缩小修饰规则生效范围。有可能的话它会被转换为声明式样式表。在过程式修饰规则里最好是用作最后一个操作符。
- 是否可链接:是。
- subject:可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
- arg: 任何通过 CSSTree 支持的 媒体类型。
- 示例:
example.com###target-1 > .target-2:matches-media((min-width: 800px))
example.com###target-3 > .target-4:matches-media((min-width: 1920px) and (min-height: 930px)):style(color: red !important)
-
github.com##pre:matches-media(print):style(white-space:pre-line !important;)
- 在 PDF 中禁止打印滚动条
该操作符从 uBO 1.43.1b8 版本开始引入,详见 feature request #2185。
- 描述:可根据当前文档位置路径和查询进一步缩小生效的范围。在过程式修饰规则里最好是用作第一个操作符。
- 是否可链接:是。
- subject:可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
- arg:可在路径+查询里的任何位置找到的普通文本,或对路径+查询进行测试的正则表达式。
- 示例:
-
example.com##:matches-path(/shop) p
规则会在访问https://example.com/shop/stuff
时隐藏所有p
元素,但在访问https://example.com/
或example.com
上的其他任何页面时不不隐藏,只要 URL 的路径不包含/shop
字样。如仅匹配主页面而不匹配任何它的子页面,可使用:example.com##:matches-path(/^/$/) p
-
该操作符从 uBO 1.37.3b13 开始引入,源自 feature request #1690。
这是一条要么全通过要么全不通过类型的操作符,它的开启或关闭的行为取决于 arg 是否匹配当前位置的路径。arg 可以是可在路径的任何位置找到的普通文本,或对路径进行测试的正则表达式。
修饰规则可以做到比整个域名更精确的生效范围,而 :matches-path()
这条新操作符还可根据当前文档位置的路径进一步缩小生效范围。
通常这个过程式操作符会用作过程式修饰规则里的第一个操作符,为的是确保不再进行其他进一步的匹配,即不必再对当前文档位置的当前路径进行匹配。
- 描述:其文本长度大于或等于
n
的 DOM 元素将被选中。 - 是否可链接:是。
- subject:可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
- n: 正数,subject 中 DOM 元素的最小文本长度。
- 示例:
- 基于正则表达式的规则:
quoka.de##^script:has-text(/[\w\W]{35000}/)
可被重写为:quoka.de##^script:min-text-length(35000)
。
- 基于正则表达式的规则:
该操作符经过与规则列表维护人员内部讨论[1]后从 uBO 1.20.1b2 开始引入,旨在能根据最小文本长度使用 HTML 过滤来移除内联脚本元素。
[1] https://github.com/orgs/uBlockOrigin/teams/ublock-filters-volunteers/discussions/194?from_comment=65
- 描述:选择 subject 元素,当且仅当对 arg 进行估值的结果为零元素。
- 是否可链接:是。
- subject:可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
- arg:一条在 subject 元素的上下文中估值了的过程式修饰规则。
该操作符从 uBO 1.17.5b9 开始引入,旨在提高对 AdGuard 过滤规则语法的兼容性。
它的作用是取消其他的过程式操作符。例如 :not(:has(.foo))
生效场景是没有任何子孙选择符匹配 .foo
。
请注意如果 arg 是有效的 CSS 选择符,则 uBO 不会将 :not
这个操作符视作过程式操作符,而是视作 CSS 选择符的一部分。这样就可以完整兼容现有的
CSS :not(...)
伪类。
实验性操作符。
- 描述:选择当前所选元素 以外 的所有元素。
- 是否可链接:是。
- subject: 可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
- 示例:
twitter.com##:matches-path(/^/home/) [data-testid="primaryColumn"]:others()
nature.com##:matches-path(/^/articles//) :is(.c-breadcrumbs,.c-article-main-column):others()
该操作符从 uBO 1.41.1b2 版本开始引入。
对于任何在 others()
内的元素,使用 others()
操作符的结果是选择以下元素之外的所有元素:
- 一个 subject 元素的后代元素
- 一个 subject 元素的祖先元素
所选的元素包括一个 subject 元素的兄弟元素,除非 这些兄弟元素是另一个 subject 元素的后代或祖先。
虽然这个操作符不太可能出现在默认的规则列表,但它开启了一道大门,可以创建专门的规则列表,其所选元素 以外 的任何元素都被隐藏起来,类似于“阅读模式”。
相关的讨论:
- 描述:查询与当前选中节点相关的祖先节点。
- 是否可链接:是。
- subject: 可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
-
arg:
-
= 1 且 < 256 的正数值,表示与当前选中节点的距离。
- 有效的普通 CSS 选择符。
-
- 示例:
- 现有的规则:
fastbay.org##.detLink:has-text(VPN):xpath(../../..)
可以重写为fastbay.org##.detLink:has-text(VPN):upward(3)
gorhill.github.io###pcf #a19 b:upward(2)
gorhill.github.io###pcf #a20 b:upward(.fail)
- 现有的规则:
该选择符从 uBO 1.25.3b0 版本开始引入,是 :nth-ancestor(n)
选择符的演进版。
也可以参见::upward()
vs :has()
该操作符仍处于实验阶段。
- 描述:可建立一条透传型(Pass-through)规则,用于修改过程式修饰规则引擎的行为,方式为所匹配的元素有一个或多个属性发生变化时强制引擎重新估值。
- 是否可链接:是。
- subject:可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
- arg:用逗号分隔的一系列属性名。如不填写参数则表示监测任意一个属性的变化。
示例:
-
测试样例,它使用
ameshkov.github.io###testdiv:watch-attr(id):has(p)
这条规则来检测id
的变化。 example.com##.j-mini-player[class]:watch-attr(class):remove-attr(class)
该操作符从 uBO 1.17.5rc3 开始引入。
它是用于解决 uBlockOrigin/uBlock-issues#341 (comment) 中提到的问题(叠加框的使用有两种目的,这两种目的是根据子节点中的 class 名区分的)。
过程式修饰规则默认仅在子树中的节点被添加或删除的情况下重新估值,考虑到性能因素,uBO 并不监测任何属性的变化。这类规则可要求 uBO 的过程式修饰引擎监测指定属性发生的变化。
- 描述:通过对使用 subject 作为上下文节点(可选的)和 arg 作为表达式的 XPath 进行估值来创建新的元素集合。
- 是否可链接:是。
- subject:可选。可以是一个普通的 CSS 选择符,也可以是一条过程式修饰规则。
- arg:一条有效的 XPath 表达式。
- 示例:
facebook.com##:xpath(//div[@id="stream_pagelet"]//div[starts-with(@id,"hyperfeed_story_id_")][.//h6//span/text()="People You May Know"])
:xpath(...)
操作符和其他操作符有所不同。其他操作符是用来查找到结果元素集合,而 :xpath(...)
操作符既可以创建结果元素集合也可以查找到已有的结果元素集合。因此,这里的 subject 是可选的。例如,:xpath(...)
操作符可以用来创建由 subject 元素所有祖先元素组成的新的结果元素集合,而这是普通 CSS 选择符或其他过程式操作符所无法做到的。
uBlock Origin - 一款支持 Chromium、Firefox 和 Safari 的高效过滤工具,快速且简洁