Inject CSS stylesheet as string using Javascript

2019-01-08 23:11发布

问题:

I'm developing a Chrome extension, and I'd like users to be able to add their own CSS styles to change the appearance of the extension's pages (not web pages). I've looked into using document.stylesheets, but it seems like it wants the rules to be split up, and won't let you inject a complete stylesheet. Is there a solution that would let me use a string to create a new stylesheet on a page?

I'm currently not using jQuery or similar, so pure Javascript solutions would be preferable.

回答1:

You could create a style element and add the string as the innerHTML. Something like this:

function addStyleString(str) {
    var node = document.createElement('style');
    node.innerHTML = str;
    document.body.appendChild(node);
}

addStyleString('body { color: red }');
addStyleString('body { background: silver }');
// This way allows you to add CSS in multiple passes

(Important edit: Be aware that IE9 and below only allows up to 32 stylesheets, so watch out when using the above snippet. The number was increased to 4095 in IE10.)

If, when a user adds new CSS, you want to remove the old styles and add the new, you can switch the function up so you have a reference to one node.

(function() {
    var node = document.createElement('style');
    document.body.appendChild(node);
    window.addStyleString = function(str) {
        node.innerHTML = str;
    }
}());

addStyleString('body { color: red }');
addStyleString('body { background: silver }');
// This way will remove the old style when the new one is added


回答2:

Thanks to this guy, I was able to find the correct answer. Here's how it's done:

function addCss(rule) {
  let css = document.createElement('style');
  css.type = 'text/css';
  if (css.styleSheet) css.styleSheet.cssText = rule; // Support for IE
  else css.appendChild(document.createTextNode(rule)); // Support for the rest
  document.getElementsByTagName("head")[0].appendChild(css);
}

// CSS rules
let rule  = '.red {background-color: red}';
    rule += '.blue {background-color: blue}';

// Load the rules and execute after the DOM loads
window.onload = function() {addCss(rule)};

fiddle



回答3:

I had this same need recently and wrote a function to do the same as Liam's, except to also allow for multiple lines of CSS.

injectCSS(function(){/*
    .ui-button {
        border: 3px solid #0f0;
        font-weight: bold;
        color: #f00;
    }
    .ui-panel {
        border: 1px solid #0f0;
        background-color: #eee;
        margin: 1em;
    }
*/});

// or the following for one line

injectCSS('.case2 { border: 3px solid #00f; } ');

The source of this function. You can download from the Github repo. Or see some more example usage here.

My preference is to use it with RequireJS, but it also will work as a global function in the absence of an AMD loader.