9

I am writing a chrome extension that needs to iterate over ALL stylesheets in the page it is injected into and modify certain styles.

I iterate/modify styles for example like this:

const iterate = (doc, f) => {
  for (const styleSheet of doc.styleSheets) {
    const rules = styleSheet.rules || styleSheet.cssRules;
    if (!rules) continue;
    for (const cssRule of rules) {
      if (!cssRule.style) continue;
      const selector = cssRule.selectorText, style = cssRule.style;
      if (!selector || !style.cssText) continue;
      f(style);
    }
  }
}

document.addEventListener("DOMContentLoaded", e => {
  setTimeout(() => {
    iterate(document, style => {
      if (style.getPropertyValue('background-color')) style.setProperty('background-color', 'yellow');
    });
  }, 1000);
});
div {
  background-color: red;
}
<div>hello</div>

The problem I am having is that it seems that external css do not get included.

For example if I inject my extension into stackoverflow.com, which has:

<link rel="stylesheet" type="text/css" href="https://cdn.sstatic.net/Sites/stackoverflow/all.css?v=cfd0b49a38a7">

Then the styles from all.css are not iterated over.

How can I iterate/modifies external styles ?

Note 1 - I tried to manually fetch those links rel and put them into internal style tags but that breaks any relative urls in those files (i.e, background-image: url('path/image.jpg') )

Note 2 - my manifest has "permissions": [ "http://*/*", "https://*/*" ]

Note 3 - as this is for a Chrome extension I am happy with a Chrome only solution

10
  • 1
    Have you tried using the function loadCSSCors from this answer ? Commented Nov 19, 2017 at 4:18
  • FWIW you can use a lightweight css parser or do a straight text replace... Commented Nov 19, 2017 at 5:42
  • 1
    You can use loadCSSCors function + some regular expression to replace relative paths to absolute paths in external CSS files. Commented Nov 19, 2017 at 18:00
  • 1
    Do you want to modify external styles? Why you just don't create your own style with the same rule and override the external? Commented Nov 23, 2017 at 11:03
  • 1
    Due to CORS, I believe the only way to get around this is to use a middleman server to get the contents of the stylesheet. Commented Nov 27, 2017 at 18:35

2 Answers 2

0

This may be a mistake in your sample code, but it is apparent that it is unlikely to inject and fetch your stylesheet prior to the DOMContentLoaded event + 1 second. Try changing your setTimeout wait to 20 seconds and see what happens.

If this solves your problem then the next step is to create a better solution that waits until your stylesheet shows up before iterating.

Sign up to request clarification or add additional context in comments.

1 Comment

the code was just to demonstrate the functionality of iterate ... ofcourse it will not be there in an actual extension
0

Your extension’s permissions don't override the pages’ permission for content that's already on the page, like the stylesheet you're trying to read and modify.

What you can do is fetch the external stylesheets, like:

const response = await fetch('https://cdn.sstatic.net/Sites/stackoverflow/all.css');
const css = await response.text();
const style = document.createElement('style');
style.textContent = css;

Then you can iterate the rules in this new style element and inject only the necessary styles into the page, so you probably won't have to worry about changing relatives URLs in the stylesheet. If that's a problem you'd also have to manually rewrite those URLs as well.

Note: Nowadays you'll probably also encounter CORB issues with the code above, so you'll have to fetch through the background: https://stackoverflow.com/a/56929473/288906

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.