Using the Stylesheet Service

The stylesheet service allows extensions to manage user and UA stylesheets without having to touch userContent.css or userChrome.css files. The API is defined in nsIStyleSheetService.idl.

The stylesheets registered with this API apply to all documents; Firefox 18 extended nsIDOMWindowUtils with loadAdditionalStyleSheet() and removeAdditionalStyleSheet() to manage stylesheets for a specific document (bug 737003).

The examples in this document are all written in JavaScript using XPCOM.

Using the API

The string "chrome://myext/content/myext.css" in the examples below is just an example. Replace it with the URL of the CSS file you want to load.

You can replace USER_SHEET with AGENT_SHEET or AUTHOR_SHEET, depending where in the CSS Cascade you want the sheet to be placed. See the CSS Specification for more details. Note that UA stylesheets are allowed to do certain unsafe things that user stylesheets are not allowed to do. In particular, they can apply styles to native anonymous elements and to CSS anonymous boxes. Getting such styles wrong can easily lead to very incorrect behavior, including crashes. Be very careful with your CSS when using AGENT_SHEET stylesheets.

Adding a stylesheet

To use the stylesheet service, you get a reference to the service, create a URI and pass the URI to the stylesheet service's loadAndRegisterSheet method.

var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"]
                    .getService(Components.interfaces.nsIStyleSheetService);
var ios = Components.classes["@mozilla.org/network/io-service;1"]
                    .getService(Components.interfaces.nsIIOService);
var uri = ios.newURI("chrome://myext/content/myext.css", null, null);
sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
Note: loadAndRegisterSheet will load the stylesheet synchronously, so you should only call this method using local URIs.

Determining whether a sheet has been loaded

If you are writing an extension and adding your stylesheet in an onload handler, you'll want to see if your sheet has already been added. If you don't check, you will wind up adding your sheet once per window load.

var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"]
                    .getService(Components.interfaces.nsIStyleSheetService);
var ios = Components.classes["@mozilla.org/network/io-service;1"]
                    .getService(Components.interfaces.nsIIOService);
var uri = ios.newURI("chrome://myext/content/myext.css", null, null);
if(!sss.sheetRegistered(uri, sss.USER_SHEET))
  sss.loadAndRegisterSheet(uri, sss.USER_SHEET);

Removing a previously registered stylesheet

If you wish to remove a stylesheet that you previously registered, simply use the unregisterSheet method.

var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"]
                    .getService(Components.interfaces.nsIStyleSheetService);
var ios = Components.classes["@mozilla.org/network/io-service;1"]
                    .getService(Components.interfaces.nsIIOService);
var u = ios.newURI("chrome://myext/content/myext.css", null, null);
if(sss.sheetRegistered(u, sss.USER_SHEET))
  sss.unregisterSheet(u, sss.USER_SHEET);

Registering stylesheets on startup via the category manager

Stylesheets may also be registered on startup via the agent-style-sheets and user-style-sheets categories. The category names are ignored, and the values are the URIs from which to load the stylesheets. The order the sheets are applied in is undefined.

Usage notes

  • Stylesheets added using this service get applied to both chrome and content documents. Remember to declare the correct namespace if you want to apply stylesheets to XUL documents.
  • Registered style sheets are not remembered across restarts.
  • loadAndRegisterSheet fails if CSS contains #id. '#' must be percent-encoded, details see bug 659650.

Historical information

nsIStyleSheetService was introduced in Firefox 1.5. In Firefox 1.5 and 2, adding and removing such style sheets takes effect upon the next load of a page. In Firefox 3, the changes take effect immediately, though some declarations (especially those affecting XUL) won't work until a reload.

Backwards compatibility

You can check for the availability and the functionality of the stylesheet service:

if("@mozilla.org/content/style-sheet-service;1" in Components.classes)
{
  if(Components.ID('{41d979dc-ea03-4235-86ff-1e3c090c5630}')
               .equals(Components.interfaces.nsIStyleSheetService))
  {
    // stylesheet service is available, but changes won't apply until reload
    // (Firefox 1.5 and 2 behaviour)
  }
  else
  {
    // stylesheet service is available and changes will apply immediately
    // (Firefox 3 behaviour)
  }
}
else
{
  // stylesheet service is not available (pre-Firefox 1.5 behaviour)
}