如何真正隔离 Google Chrome 扩展中的样式表?

     2023-02-25     16

关键词:

【中文标题】如何真正隔离 Google Chrome 扩展中的样式表?【英文标题】:How to really isolate stylesheets in the Google Chrome extension? 【发布时间】:2012-09-28 19:00:15 【问题描述】:

我编写了一个谷歌浏览器扩展程序,它会弹出一个带有自动完成字段的对话框,它有自己的风格,但是在某些网站上我的 CSS 完全被破坏了,看起来不太好。

我知道使用 iFrame 隔离样式,但在 Google Chrome 扩展程序中,无法以这种方式隔离我的 HTML 和 CSS。另一种方法是将我所有的东西包装到一个单独的 div 中,并使用它自己的 id 和该 id 的相对样式,我这样做了,但它似乎不适用于某些具有“硬”标签样式重载或“!重要的”指令在 CSS 代码中。

所以,我想知道有没有什么方法可以真正以方便的方式隔离我的样式,或者重载每个小的 CSS 属性来修复每个站点的一个或另一个样式问题是我的坏事?

顺便说一句:我将清单设置为在“document_end”加载所有内容,但我发现它并没有应用于样式表,而样式表每次都在 DOM 准备好时加载。

【问题讨论】:

你试过these methods吗?两者的结合应该足够了。确保您的选择器足够具体。 谢谢罗伯!是的,我试过这个,但它似乎不适用于每个站点。我知道即使我看到“计算样式”(在 GC DevTools 中)显示的所有页面都是我在 CSS 中设置的,例如“list-style: none !important;”,它仍然会继续向我显示带有“光盘”标记的列表。而且,是的 - 我的样式在清单中设置,就像在您的建议中一样,它是在创建 DOM 后通过嵌入到头部动态加载的。也许还有其他方法可以隔离 Google Chrome 扩展中的样式?我的意思是清单中的一些秘密“禁用继承:开启”选项或类似的东西? 我最后的建议怎么样?增加选择器的specifity。如果您控制要设置样式的元素,则添加 style="prop:val!important" 将具有最高优先级 - 例如参见 jsfiddle.net/rytkL。 在此处查看我对类似问题的回答:***.com/questions/10608924/…。有几种方法,但我详细介绍的一种可能是最简单和最可靠的...... :) 【参考方案1】:

由于我最近经历了这个问题的挑战,我想分享一些我认为有价值的信息。

首先,Rob W 的答案是正确的。 Shadow DOM 是解决这个问题的正确方法。然而,就我而言,我不仅需要 CSS 隔离,还需要 JavaScript 事件。例如,如果用户单击位于隔离 HTML 中的按钮会发生什么?仅使用 Shadow DOM 就变得非常丑陋,但我们有另一种 Web 组件技术,自定义元素,可以救援。除了在撰写本文时,chrome 中有一个错误会阻止 chrome 扩展中的自定义元素。请参阅我的问题 here 和 here 和 the bug here。

那么这会给我们带来什么影响呢?我相信今天最好的解决方案是 IFrame,这就是我所采用的。 shahalpk 链接的文章很棒,但它仅描述了该过程的一部分。我是这样做的:

首先,为您的独立小部件创建一个 html 文件和 js 文件。这些文件中的所有内容都将在 iframe 中的隔离环境中运行。请务必从 html 文件中获取您的 js 文件。

//iframe.js
var button = document.querySelector('.my-button');
button.addEventListener('click', function() 
    // do useful things
);

//iframe.html
<style>
/* css */
</style>
<button class='my-button'>Hi there</button>
<script src='iframe.js'></script> 

接下来,在您的内容脚本中,在 javascript 中创建一个 iframe 元素。您需要在 javascript 中执行此操作,因为您必须使用 chrome.extension.getURL 才能获取您的 iframe html 文件:

var iframe = document.createElement('iframe');
iframe.src = chrome.extension.getURL("iframe.html");
document.body.appendChild(iframe);

就是这样。

要记住一点:如果需要在 iframe 和其余内容脚本之间进行通信,则需要 chrome.runtime.sendMessage() 到后台页面,然后 chrome.tabs.sendMessage 从背景页面回到选项卡。他们不能直接交流。

编辑:我写了一篇博文,详细介绍了我在这个过程中学到的一切,包括一个完整的示例 chrome 扩展和许多指向不同信息的链接:

https://apitman.com/3/#chrome-extension-content-script-stylesheet-isolation

如果我的博客出现故障,这里是原始帖子的来源:

Blog post

Example source

【讨论】:

顺便说一句,如该博客文章中所述,您可能需要查看我的 chromeps 库来处理消息传递。这个blog post 解释了它【参考方案2】:

要么使用all

.some-selector 
    all: initial;


.some-selector * 
    all: unset;

或使用 Shadow DOM

图书馆

function Widget(nodeName, appendTo)
  this.outer = document.createElement(nodeName || 'DIV');
  this.outer.className = 'extension-widget-' + chrome.runtime.id;
  this.inner = this.outer.createShadowRoot();
  (appendTo || document.body).appendChild(this.outer);


Widget.prototype.show = function()
  this.outer.style.display = 'block';
  return this;
;

Widget.prototype.hide = function()
  this.outer.style.display = 'none';
  return this;
;

用法

var myWidget = new Widget();
myWidget.inner.innerHTML = '<h1>myWidget</h1>';

您可以通过myWidget.inner 和外部通过myWidget.outer 访问小部件内容。

样式

/* 
 * Reset Widget Wrapper Element 
 */
.extension-widget-__MSG_@@extension_id__ 
  background: none;
  border: none;
  bottom: auto;
  box-shadow: none;
  color: black;
  cursor: auto;
  display: inline;
  float: none;
  font-family : "Helvetica Neue", "Helvetica", "Arial", sans-serif;
  font-size: inherit;
  font-style: normal;
  font-variant: normal;
  font-weight: normal;
  height: auto;
  left: auto;
  letter-spacing: 0;
  line-height: 100%;
  margin: 0;
  max-height: none;
  max-width: none;
  min-height: 0;
  min-width: 0;
  opacity: 1;
  padding: 0;
  position: static;
  right: auto;
  text-align: left;
  text-decoration: none;
  text-indent: 0;
  text-shadow: none;
  text-transform: none;
  top: auto;
  vertical-align: baseline;
  white-space: normal;
  width: auto;
  z-index: 2147483648;


/* 
 * Add your own styles here 
 * but always prefix them with:
 * 
 *   .extension-widget-__MSG_@@extension_id__ 
 *   
 */

.extension-widget-__MSG_@@extension_id__
  position: fixed;
  top: 100px;
  margin: 0 auto;
  left: 0;
  right: 0;
  width: 500px;


.extension-widget-__MSG_@@extension_id__::shadow h1 
  display: block;
  margin: 0 auto;
  padding: 20px;
  background-color: yellow;
  border: 10px solid green;
  font-size: 20px;
  text-align: center;

【讨论】:

Shadow DOM 在事件处理方面非常棘手。我正在尝试使用 React + Shadow DOM 来隔离扩展,但仍然无法将事件处理程序绑定到内部 DOM。 我也做了同样的事情。最后我意识到 react 和 shadow dom 不能很好地协同工作。在封装方面,好的旧 iframe 仍然是最佳选择。 很高兴听到有人和我在一起。但似乎如果您使用的是 iframe,主机和 iframe 内容之间的消息传递可能会非常困难。你是怎么做到的?【参考方案3】:

我最近创建了 Boundary,一个 CSS+JS 库来解决这样的问题。 Boundary 创建的元素与现有网页的 CSS 完全分离。

以创建对话框为例。安装 Boundary 后,您可以在内容脚本中执行此操作

var dialog = Boundary.createBox("yourDialogID", "yourDialogClassName");

Boundary.loadBoxCSS("#yourDialogID", "style-for-elems-in-dialog.css");

Boundary.appendToBox(
    "#yourDialogID",
    "<button id='submit_button'>submit</button>"
);

Boundary.find("#submit_button").click(function() 
  // some js after button is clicked.
);

#yourDialogID 中的元素不会受到现有网页的影响。 find() 函数返回一个常规的 jQuery DOM 元素,所以你可以用它做任何你想做的事情。

希望这会有所帮助。如果您有任何问题,请告诉我。

https://github.com/liviavinci/Boundary

【讨论】:

好!现在这是一个更好的答案。 (虽然要去掉sn-p标签,但没用) @Xan 这是我第一次在 *** 上发布答案,非常感谢您的指导! 这对用户事件响应良好吗?【参考方案4】:

在提出问题时,您唯一的选择是使用 iframe 或 specificity 非常高的样式表,并明确设置所有可能影响样式的属性。最后一种方法很麻烦,因为总会有一些属性被你忽略。因此,隔离样式表的唯一可用方法是使用 iframe。

这个问题的解决方案 - 没有 iframe 的样式隔离 - 是 Shadow DOM (since Chrome 25)。您可以在HTML5 Rocks 找到教程。有关使用 Shadow DOM 隔离样式的真实 Chrome 扩展程序,请参阅Display #Anchors (source code here)。

【讨论】:

Display #Anchors 扩展非常方便(例如,用于链接到 Chrome 扩展文档的特定部分;)) 也使用 Sass 之类的:#myid .all-my-extension-styles ... 可能会解决这个问题? @rob-w 你的答案似乎有点复杂。你能给出简化代码来注入一个元素并在其他元素的顶部覆盖它吗? 我能够创建一个 shadowDOM 元素,但是一旦加载它就会被页面覆盖。例如,在 Medium 编辑器中,它会显示一秒钟的阴影元素并隐藏。我能够在开发工具中检查元素。【参考方案5】:

使用 iframe。这是一种解决方法,但效果很好。

Maxime 写了一封article on it。

【讨论】:

如何检测 Chrome 中是不是安装了 Google Cast 扩展程序?

】如何检测Chrome中是不是安装了GoogleCast扩展程序?【英文标题】:HowtodetectifGoogleCastextensionisinstalledinChrome?如何检测Chrome中是否安装了GoogleCast扩展程序?【发布时间】:2015-12-2709:12:12【问题描述】:我正在开发一个GoogleCast发件... 查看详情

在 Google Chrome 扩展程序中使用 SSH

...想通过ssh将此文件发送到我本地网络中的另一台计算机。如何在我的chrome扩展程序中设置和使用ssh连接?【问题讨论】:可能重复:***.com 查看详情

如何在 Chrome 扩展程序 browser_action 中登录 Google?

】如何在Chrome扩展程序browser_action中登录Google?【英文标题】:HowcanIsignintoGoogleinsideaChromeExtensionbrowser_action?【发布时间】:2020-04-1919:26:40【问题描述】:我试图让这一切尽可能简单,以便它可以成为处于相同情况的其他人的资源... 查看详情

如何在 chrome 扩展中加载 Google Analytics 和 Facebook SDK?

】如何在chrome扩展中加载GoogleAnalytics和FacebookSDK?【英文标题】:HowtoloadGoogleAnalyticsandFacebookSDKinchromeextension?【发布时间】:2013-12-1722:02:44【问题描述】:我正在使用Kango框架开发一个chrome扩展,我希望同时使用GoogleAnalytics和facebo... 查看详情

如何使用 Chrome 扩展程序自动保存 Google Chrome 开发者工具的网络面板日志?

】如何使用Chrome扩展程序自动保存GoogleChrome开发者工具的网络面板日志?【英文标题】:HowtoautomatesavingthelogofNetworkpanelofGoogleChromeDevelopertoolsusingChromeextension?【发布时间】:2016-08-1600:51:02【问题描述】:假设我打开一个网络应用... 查看详情

Google Chrome 扩展程序 - 单击工具栏图标时打开新选项卡

...选项卡(例如:f.html)?我看到了thisquestion,但它并没有真正 查看详情

从脚本安装 Google Chrome 扩展

...(crx文件),但我不想将它上传到Chrome网上应用店。现在如何以编程方式(使用JavaScript或chromeAPI)在Googlechrome中安装此crx文件?我到处搜索,唯一的解决方案 查看详情

是否可以通过扩展从另一个进程外部触发 Google Chrome 中的 Javascript?

】是否可以通过扩展从另一个进程外部触发GoogleChrome中的Javascript?【英文标题】:IsitpossibletoexternallytriggerJavascriptinGoogleChromefromanotherprocess,maybeviaanextension?【发布时间】:2010-11-0818:28:27【问题描述】:我希望我的机器上的本地进... 查看详情

检测 Google Chrome 扩展的 browser_action 表单中的按钮点击

】检测GoogleChrome扩展的browser_action表单中的按钮点击【英文标题】:Detectabuttonclickinthebrowser_actionformofaGoogleChromeExtension【发布时间】:2021-12-2720:10:58【问题描述】:如此简单的事情怎么会如此不可能?我想要做的就是单击我的扩... 查看详情

如何在chrome上可以登录google

1.Ghelper的下载.解压(http://ghelper.xyz/)2.在谷歌浏览器==>更多工具==>扩展程序==>加载已解压的扩展程序(添加刚才下载的Ghelper)3.Ghelper按照注册流程,注册账号,登录接下来就可以登录Google网站了 查看详情

扩展 Google chrome 以显示证书列表

...间】:2017-05-3108:32:30【问题描述】:任何人都可以帮助我如何放置,任何人都有解决方案来做到这一点。【问题讨论】:【参考方案1】:Chrome扩展中没有任何机制可以:枚举已安装的证书。查看给定连接的证书详细信息。最接... 查看详情

如何在浏览器中获取 Google Cloud Translation API 的身份验证令牌(chrome 扩展)

】如何在浏览器中获取GoogleCloudTranslationAPI的身份验证令牌(chrome扩展)【英文标题】:HowtogetanauthenticationtokenforGoogleCloudTranslationAPIwithinbrowser(chromeextension)【发布时间】:2019-01-2501:31:43【问题描述】:我正在尝试制作一个使用Googl... 查看详情

Chrome扩展程序中的无Chrome窗口?

...为TypeFu的Web应用程序。让我吃惊的是他们居然创造了一个真正的无铬窗。我正在考虑是否可以在Chrome扩展程序中执行此操作,因为在大多数情况下它们使用相同的API。但是,我找不到任何可以让我做出 查看详情

oauth Chrome 扩展 Google App Engine

】oauthChrome扩展GoogleAppEngine【英文标题】:oauthChromeExtensionGoogleAppEngine【发布时间】:2013-11-0210:32:19【问题描述】:有没有人幸运地让GoogleChrome扩展程序和GoogleApp引擎之间的OAuth运行良好(或者其他任何事情?)。我已经完成了所... 查看详情

如何在我的 Google Chrome 扩展程序中将信息从 Background.js 传递到 autofill.js?

】如何在我的GoogleChrome扩展程序中将信息从Background.js传递到autofill.js?【英文标题】:HowcanIpassinformationfromBackground.jstoautofill.jsinmyGoogleChromeextension?【发布时间】:2014-04-0701:28:51【问题描述】:我制作了一个GoogleChrome扩展程序,当... 查看详情

在 google-chrome 扩展中加载 iframe(错误:协议必须匹配)

】在google-chrome扩展中加载iframe(错误:协议必须匹配)【英文标题】:Loadingiframeingoogle-chromeextension(Error:Protocolsmustmatch)【发布时间】:2012-12-2622:30:08【问题描述】:manifest.json中的代码:"name":"Test","version":"1.0","manifest_version":2,"des... 查看详情

如何同步 chrome 扩展选项

】如何同步chrome扩展选项【英文标题】:Howtosyncchromeextensionoptions【发布时间】:2011-05-1123:06:46【问题描述】:我制作了一个带有选项页面的Chrome扩展程序。数据保存在本地存储中并且可以正常工作。Chrome不会将本地存储同步到... 查看详情

如何与电子中的chrome扩展背景页面通信?

】如何与电子中的chrome扩展背景页面通信?【英文标题】:Howtocommunicatewithchromeextensionbackgroundpageinelectron?【发布时间】:2022-01-2101:31:49【问题描述】:由于电子没有实现chrome.runtime.onMessageExternal。我们如何在main或renderer进程中与c... 查看详情