26

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
  • 1,035
  • 3
  • 12
  • 20

8 Answers8

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,218
  • 2
  • 31
  • 43
21

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
  • 211
  • 2
  • 4
  • Update: as of now supported in Chromium but not in Safari – David Min Jun 19 '22 at 19:25
  • Now (mid-2022) available [on most browsers](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet#browser_compatibility); only Safari is still holding out. Now let's hope for a constructor for `CSSStyleRule` objects, to bring an end to 'injecting source code'. – Jim Danner Sep 04 '22 at 20:28
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,399
  • 29
  • 31
regality
  • 6,496
  • 6
  • 29
  • 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,518
  • 16
  • 21
Simon A. Eugster
  • 4,114
  • 4
  • 36
  • 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
  • 84,080
  • 19
  • 162
  • 191
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
  • 557
  • 5
  • 15
  • 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,542
  • 1
  • 26
  • 23
  • 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
  • 2
    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
0

Safari support CSSStyleSheet since 16.4 : https://developer.apple.com/documentation/safari-release-notes/safari-16_4-release-notes#CSS-API

Simon
  • 1
  • 1