Insert CSS at document_start from a Content Script - How?

4,494 views
Skip to first unread message

Matt Kruse

unread,
Mar 9, 2012, 12:56:46 PM3/9/12
to Chromium-extensions
I want to programmatically (via js) write out CSS to the page at
document_start from a content script, so the page doesn't "flicker"
from the old styles to the new styles when my js kicks in.

How can I do this? Do I need to go back to the background page and use
insertCSS()? I can't find a clean example.

I can't include the CSS reference in the manifest, because the CSS
content is conditionally generated via the js.

Actually, what really happens is:
1. The user clicks some options, and CSS is generated
2. The css is stored in window.localStorage (not background page)
3. When the content script is run on reload, it checks localstorage
for css, and inserts it.

I want to insert it BEFORE the page paints, not after. I do the
localStorage trick for performance, and because the call back to the
background page is async, and the page will paint before the response
comes back.

Any ideas? Thanks!

Matt Kruse

Don Schmitt

unread,
Mar 9, 2012, 3:59:04 PM3/9/12
to Matt Kruse, Chromium-extensions
Your document_start content script should be able to append a CSS <style>
element to the documentElement which I believe is always available at
document_start.

Any ideas? Thanks!

Matt Kruse

--
You received this message because you are subscribed to the Google Groups
"Chromium-extensions" group.
To post to this group, send email to chromium-...@chromium.org.
To unsubscribe from this group, send email to
chromium-extens...@chromium.org.
For more options, visit this group at
http://groups.google.com/a/chromium.org/group/chromium-extensions/?hl=en.

Devin

unread,
Mar 10, 2012, 1:30:53 PM3/10/12
to Chromium-extensions
I went crazy about this flicker thing in my extension.

Here's the *best* way to go about it, promise.

In the manifest, inject a js file on document_start:

    "content_scripts": [
       {
          "all_frames": false,
         "js": [ "start.js", "main.js" ],
         "matches": [ "*://*.domain.com/*" ], //over match urls, you
can be more precise in start.js
         "run_at": "document_start"
       }
    ],

This JS file can do any programatic things you need, including full
regex pattern matching not capable in the manifest matching. If you
have some base css that doesn't change based on user actions, isn't
customizable and doesn't depend on settings, append a <link> to this
main.css in your extension directory:

    var link = document.createElement('link');
    link.href = chrome.extension.getURL('main.css');
    link.id = 'Your Stylish!';
    link.type = 'text/css';
    link.rel = 'stylesheet';
    document.documentElement.insertBefore(link);

If you have anything that depends on settings, you may do something
like this:

    var customStyles = document.createElement('style');
    customStyles.innerHTML =
       'body { background-color: ' +
          localStorage.get('background-color') +
       '}';
    document.documentElement.insertBefore(customStyles);

Using this method, you can completely get rid of any flicker!

Feel free to follow me on twitter or github @DevinRhode2

Mohamed Mansour

unread,
Mar 10, 2012, 3:21:04 PM3/10/12
to Devin, Chromium-extensions
I usually do this, which works great for Content Scripts (taken from GreaseMonkey):

InjectionUtils.addGlobalStyle = function(css) {
  try {
    var elmHead, elmStyle;
    elmHead = document.getElementsByTagName('head')[0];
    elmStyle = document.createElement('style');
    elmStyle.type = 'text/css';
    elmHead.appendChild(elmStyle);
    elmStyle.innerHTML = css;
  }
  catch (e) {
    if (!document.styleSheets.length) {
      document.createStyleSheet();
    }
    document.styleSheets[0].cssText += css;
  }
};


Then you can add  your CSS  programmatically like:

InjectionUtils.addGlobalStyle(
  '#crx-circle-filter-injection-textfield {border: 1px solid #ccc;background-color: white;}' +
  '#crx-circle-filter-injection-textfield input {outline: none; border: 0px;}' +
  '.crx-circle-filter-injection-selected { background-image: -webkit-linear-gradient(top,#4d90fe,#4787ed);}' +
  '.crx-circle-filter-injection-selected > div { background-color: transparent;}'
);

Kind regards,
Mohamed Mansour




Don Schmitt

unread,
Mar 10, 2012, 5:16:14 PM3/10/12
to Mohamed Mansour, Devin, Chromium-extensions

You can't count on using the <head> element in a document_start content script.  The trick is to use document.documentElement and append your style element to that.

 

Regards,

- Don

eriq

unread,
Mar 9, 2012, 1:33:35 PM3/9/12
to Chromium-extensions, Matt Kruse
We are working on that right now:
http://code.google.com/p/chromium/issues/detail?id=107286

The plan is that when this is completed you can add a "runAt"
parameter
to insertCSS/executeScript, which you can set to "document_start".
Reply all
Reply to author
Forward
0 new messages