【问题标题】:Select CSS Parent `selector` in iOS Content Blocking在 iOS 内容阻止中选择 CSS Parent `selector`
【发布时间】:2022-04-30 05:14:38
【问题描述】:

我正在设置一些内容拦截器 (https://developer.apple.com/documentation/safariservices/creating_a_content_blocker)

我正在测试的 HTML 看起来像这样:

<div class="<random>">
  <div>
    <div>
      <div>
        <a class="bad" />

现在,我想知道是否可以有一个 CSS 选择器来选择 .bad,然后删除整个 .random div 块。

我尝试过类似的方法:

  {
    "action": {
      "type": "css-display-none",
      "selector": "div > div > div > div >a[href*='speedtest.net']"
    },
    "trigger": {
      "url-filter": "^https?:\/+([^\/:]+\\.)?google.*[:\/]"
    }
  }

div:has(a)

似乎没有任何效果。

有人知道这是否可能吗?我什至找不到任何地方说明苹果对此支持什么(CSS4?)

【问题讨论】:

标签: css ios iphone safari-content-blocker


【解决方案1】:

现在 Safari 和 Safari iOS 支持更新:: has。来源:caniuse

css 中目前没有父选择器,尽管它是最需要的 CSS 功能之一。

尚未实施的简单原因是性能问题。 https://snook.ca/archives/html_and_css/css-parent-selectors

目前我们在 CSS 中最接近父选择器的是:focus-within,如果元素或其任何后代被聚焦,它将匹配一个元素。但是在你的情况下它没有用。

您提到的父选择器的建议实现是:has,它是第 4 级 CSS 选择器的一部分。

https://www.w3.org/TR/selectors-4/

虽然它还没有在任何浏览器中实现,但它现在是 Safari 技术预览的一部分,所以我们可能有一天会得到它。 不过,它还不是 iOS 技术预览的一部分,可能仍需要很长时间。

https://caniuse.com/css-has

即使没有 CSS 父选择器,您所描述的也可以通过 Safari 扩展程序中的 Javascript 轻松实现。

但是,您需要授予 Safari 扩展程序权限才能在网页中注入脚本。

用户必须接受权限。如果他们拒绝,您将无法通过 javascript 访问页面 DOM。

您可以通过进入 Xcode 项目的 manifest.json 来做到这一点:AppName =&gt; Shared (Extension) =&gt; Ressources =&gt; manifest

您需要在 content_scripts 中添加

"content_scripts": [{
    "js": [ "content.js" ],
    "matches": [ "<all_urls>" ]
}]

您还可以像以前一样使用正则表达式选择您希望扩展程序可以访问的网站。

https://developer.apple.com/documentation/safariservices/safari_web_extensions/managing_safari_web_extension_permissions

然后在content.js 文件中,您可以添加您的javascript 代码来随意编辑网页。

这里有一个函数可以用来移除坏元素的父元素:

const removeBadElementParent = () =>{
    const badElements = document.querySelectorAll('.bad-class-name')
    if(badElements.length === 0) return;
    
    badElements.forEach(element =>{
        if(!element instanceof HTMLElement) return;
        const parent = element.parentElement;
        
        if(!parent instanceof HTMLElement) return;
        parent.style.display = 'none'
    })
}

您不想立即使用它,但仅在 DOM 加载后才使用,因此您需要像这样调用它:

if( document.readyState !== 'loading' ) {
    removeBadElementParent();
} else {
    document.addEventListener("DOMContentLoaded", function(event) {
        removeBadElementParent();
    });
}

但是,大多数网站都会对 DOM 进行更改,并且可能会在 DOMContentLoaded 事件触发后添加错误元素。所以你需要添加一个变异观察者来检查 DOM 什么时候改变:

const onDOMMutation = (callback) =>{
    MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    const observer = new MutationObserver(function(mutations, observer) {
        callback();
    });

    observer.observe(document, {
      subtree: true,
      attributes: true
    });
}

你可以这样调用它而不是直接调用removeBadElementParent函数:

if( document.readyState !== 'loading' ) {
    onDOMMutation(removeBadElementParent);
} else {
    document.addEventListener("DOMContentLoaded", function(event) {
        onDOMMutation(removeBadElementParent);
    });
}

https://developer.apple.com/documentation/safariservices/safari_app_extensions/injecting_a_script_into_a_webpage

【讨论】:

  • OP 正在尝试使用内容阻止程序根据其 URL 阻止来自页面的特定内容。我认为他不能在其他页面上注入或执行任何 javascript。
  • Safari(或任何浏览器)扩展程序可以在任何网页上注入 JavaScript,只要它具有正确的权限。当您授予扩展程序查看和修改内容的权限时,这就是您所允许的。
猜你喜欢
  • 2019-05-10
  • 2021-10-02
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 2018-05-21
  • 2016-02-18
  • 2020-05-27
  • 2015-12-24
相关资源
最近更新 更多