ayanamist
ayanamist

Reputation: 1174

Can I dynamically create a CSSStyleSheet object and insert it?

I know document.styleSheets which consists of all valid style sheets in a page. I want to know whether I can create a new one and append it to present list via JavaScript.

I have tried document.styleSheets[0].constructor, document.styleSheets[0].__proto__.constructor, new CSSStyleSheet, CSSStyleSheet(), and all I get from Chrome is:

TypeError: Illegal constructor.

CSSStyleSheet.constructor() returned a pure object but I expect a CSSStyleSheet object.

I know I can create a link/style element and append it, then modify it. Can I create such objects directly with JavaScript?

Upvotes: 33

Views: 23904

Answers (8)

Dabolus
Dabolus

Reputation: 271

There's a proposal that makes it possible to directly call the CSSStyleSheet constructor. Doing what you want to looks like this:

// Construct the CSSStyleSheet
const stylesheet = new CSSStyleSheet();

// Add some CSS
stylesheet.replaceSync('body { background: #000 !important; }')
// OR stylesheet.replace, which returns a Promise instead

// Tell the document to adopt your new stylesheet.
// Note that this also works with Shadow Roots.
document.adoptedStyleSheets = [stylesheet];

Upvotes: 27

Simon A. Eugster
Simon A. Eugster

Reputation: 4264

Yes, you can. The document.styleSheets cannot be modified directly, but you can add an entry by adding a new style tag to your document:

// Create the style element
var elem = $('<style id="lwuiStyle"></style>');
$('head').append(elem);

// Find its CSSStyleSheet entry in document.styleSheets
var yourSheet = null;
for (var sheet of document.styleSheets) {
    if (sheet.ownerNode == elem[0]) {
        yourSheet = sheet;
        break;
    }
}

// Test it by changing the background colour
yourSheet.insertRule('body {background-color: #fa0}', yourSheet.cssRules.length);

If you run Firefox, you can directly test this in Scratchpad: Copy the code, press Shift+F4, paste it, and run the code with Ctrl+L. Have fun!

Upvotes: 5

regality
regality

Reputation: 6554

If you are trying to write the css inside of javascript, do this:

var s = document.createElement('style');
s.type = 'text/css';
s.innerText = 'body { background: #222; } /*... more css ..*/';
document.head.appendChild(s);

Whereas if you are trying to load a stylesheet from the server:

var s = document.createElement('link');
s.type = 'text/css';
s.rel = 'stylesheet';
s.href = '/url/to/css/file.css';
document.head.appendChild(s);

Upvotes: 7

WickyNilliams
WickyNilliams

Reputation: 5308

I know you said you didn't want to create an element, but that's genuinely the only way to do it. A few people have detailed this approach above, but i notice nobody covered off that HTMLStyleElement and HTMLLinkElement both have a neat sheet property to get direct access to their CSSStyleSheet:

var style = document.createElement("style");
document.head.appendChild(style); // must append before you can access sheet property
var sheet = style.sheet;

console.log(sheet instanceof CSSStyleSheet);

Much simpler than searching through document.styleSheets

Upvotes: 22

filip
filip

Reputation: 3646

Object.create(CSSStyleSheet.prototype)

gives you back an empty instance of CSSStyleSheet. In other words, it does exactly what you would expect new CSSStyleSheet to do.

Object.create is available in any browser with ECMAScript 5 support. Find a compatibility table here.

Upvotes: 2

StaticBug
StaticBug

Reputation: 577

Did you try this:

var myCSSStyleSheetIbj = Object.create(document.styleSheets[0])

Assuming that document.styleSheets[0] is a CSSStyleSheet Object, Actually if you replace document.styleSheets[0] with any CSSStyleSheet it would work.

Upvotes: 2

Shawn Chin
Shawn Chin

Reputation: 86934

As far as I know, the only approach that comes close to what you're asking for is the IE-only document.createStyleSheet([url] [,index]) method which you can use to create up to 31* styleSheet objects (after which you'll still need to manually create style elements and append them to document).

This answer shows how you can define the createStyleSheet() method for non-IE browsers but as you'd expect it does so by appending link/style elements (which for some reason you're trying to avoid).


* IE 6 to 9 is limited to 31 imported stylesheets due to 5-bit field used for storing sheet IDs. In IE10 this limit has been raised to 4095.

Upvotes: 4

Related Questions