23

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(), all what 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. What i want to know is that, can i create such object directly with javascript?

ayanamist
  • 982
  • 3
  • 10
  • 19

7 Answers7

21

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

WickyNilliams
  • 5,082
  • 2
  • 28
  • 43
16

There's a brand new 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];

Note that currently this only works on Chrome Canary, but hopefully other browsers will implement this feature soon.

Dabolus
  • 161
  • 1
  • 4
7

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);
user2683246
  • 3,169
  • 27
  • 30
regality
  • 6,428
  • 6
  • 28
  • 26
  • Sorry, but i have said i know this method. I'm wondering whether i can create this object directly with javascript or not. – ayanamist Nov 21 '11 at 09:25
  • 4
    Don't use `innerText`, it's not part of any standard and doesn't have full browser compatibility. Use `s.appendChild(document.createTextNode(styles))` for full compat. – Andy E Nov 21 '11 at 10:14
  • @regality I want to create this object like `new CSSStyleSheet`, your method just pollutes DOM. – ayanamist Nov 22 '11 at 09:47
5

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!

enigmaticPhysicist
  • 1,230
  • 13
  • 19
Simon A. Eugster
  • 3,950
  • 4
  • 35
  • 31
3

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.

Community
  • 1
  • 1
Shawn Chin
  • 79,172
  • 18
  • 156
  • 188
2

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.

StaticBug
  • 535
  • 3
  • 14
  • To create an *empty* object, you might rather want to use `Object.create(Object.getPrototypeOf(document.styleSheets[0]))` here – but adding the object does not seem to be allowed. – Simon A. Eugster Jul 02 '13 at 10:20
  • 1
    Great, but once I create it, how do I insert it into my document? –  Sep 25 '14 at 17:10
2

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.

filip
  • 3,284
  • 1
  • 25
  • 22
  • 1
    Perhaps you can elaborate? Instead of posting one line of rather cryptic code? – Martin Tournoij Feb 17 '14 at 00:40
  • It's the answer to the question and so any comment would have been unnecessary in my eyes. The statement returns a new instance of CSSStyleSheet and that's it. – filip Feb 17 '14 at 03:45
  • 1
    Great, now I have a new object, how do I insert it into my document? –  Sep 25 '14 at 17:12
  • While this looks like a good Idea, the resulting object is not usable as expected and throws an error - at least in Chrome and Firefox. – kirschkern Jan 11 '19 at 11:28