4

Is there any way to disable/enable a CSS content script from a browserAction or pageAction icon? I'm talking about the kind of script that runs a CSS content script, as defined in the manifest, on a specific set of matched pages. So, if the manifest includes:

"content_scripts": [
  {
    "matches": [ "*://*.somewhere.com/*" ],
    "css": ["somewhere.css"]
  }
]

which would inject somewhere.css on somewhere.com. Is there any way to write a browserAction or pageAction options popup that could fully enable or disable the CSS content script?

I know that I could write a JavaScript content script that listens to such an options popup and then adds/subtracts CSS rules and/or classes to the page. But I want this CSS inserted before the page is rendered and as far as I can tell the only way to do that is with a CSS content script.

But, is there a way to fully enable or disable the extension—which only has a CSS content script—from the popup? I can't see a way to do this.

mix
  • 6,943
  • 15
  • 61
  • 90

2 Answers2

3

No, unfortunately, there is no way to turn off injection of a manifest.json content_script (either CSS or JavaScript). The specified code will be injected in all matching URLs.

In order to have complete control over injecting, or not injecting, you will need to perform the injection via tabs.insertCSS() and/or tabs.executeScript. Injecting, or not injecting, scripts and CSS with these methods is fully under the control of the JavaScript in your extension. It is certainly possible to get similar functionality using these methods to what you obtain with manifest.json content_script entries, but with more control and complexity.

Depending on what, exactly, you are wanting to do, a more appropriate way to accomplish it may be to use a chrome.declarativeContent onPageChanged rule which includes a RequestContentScript action. However, there are mixed indications as to this being actually supported on stable builds of Chrome. In addition, it does not have the capability to provide a runAt property. Thus, it may not be suitable for what you are doing.

Makyen
  • 31,849
  • 12
  • 86
  • 121
  • But am I correct that the only way to get the CSS inserted before the DOM is constructed or displayed is to inject it from the manifest.json file? That's why I'm hoping to keep it there rather than move to `tabs.insertCSS()`. – mix Dec 11 '16 at 04:51
  • I'm going to need to do some more testing to see if you are correct. – Makyen Dec 11 '16 at 05:23
  • I appreciate your researching it. I'm trying to avoid the flash that happens when styles get added after the DOM has rendered. For example, let's say I'm going to hide all of the images using a CSS style such as `img { opacity:0; }`; in this case I don't want to see the images briefly before they disappear. Instead I just never want to see them. Injecting via the CSS content script accomplishes this. – mix Dec 11 '16 at 06:14
  • @mix Testing indicates that you can inject with `tabs.executeScript()` with `runAt:'document_start'` *prior to* the injection that occurs with a *manifest.json* `content_script` with `run_at:"document_start"`. Definitely, prior to `document.head` and `document.body` existing (i.e. they are both `null` at that time). I have not tested with `tabs.insertCSS` as there is no easy way to be certain when the injection occurs wrt. the state of the DOM, but my expectation is that it would be similar (The `content_script` doc mentions that CSS is injected prior to scripts). – Makyen Dec 11 '16 at 07:08
  • @mix, It should be noted that it is a bit convoluted to get the timing such the `tabs.executeScript()` actually injects the script such that the content script runs prior to the start of the document. It does, however, appear that doing so can be consistently accomplished (in the limited testing I have performed). – Makyen Dec 12 '16 at 18:46
1

You can't change the content of manifest.json, once you specify content_scripts in there, they'll always be loaded.

If you need more flexibility when injecting content scripts, you have to use the new contentScripts.register() Firefox API and its Chrome polyfill to register and unregister scripts.

The API however requires a page reload to inject and remove the CSS. You can use the instant chrome.tabs.insertCSS instead, but you still can't remove the CSS without a reload.


Additionally, I wrote 2 modules to help with the whole process: add/remove domains + inject CSS or JS


Note: DO NOT use chrome.declarativeContent because it's basically unused and unsupported, and it specifically breaks with CSS

fregante
  • 29,050
  • 14
  • 119
  • 159