YUI 3: StyleSheet
The StyleSheet module normalizes the dynamic creation and modification of CSS stylesheets on a page. This makes it easy to manage the development, storage, and reapplication of personalized user stylesheets. Because it targets styles at the CSS level, it also allows you to modify styles applied to a CSS pseudo-element such as p::first-letter, or pseudo-class such as a:hover.
StyleSheet is capable of creating new stylesheets from scratch or modifying existing stylesheets held as properties of <link> or <style> elements. It should be noted that not all browsers support reading or modifying external stylesheets from other domains.
More Information
- Examples: StyleSheet Utility in action.
- API Documentation: View the full API documentation for the StyleSheet Utility.
- Download: StyleSheet Utility as part of the full YUI Library.
- Free Hosting on our fast edge servers with combo-loading.
- License: BSD.
Getting Started
Include Dependencies
The easiest way to include the source files for Stylesheet and its dependencies is to add the YUI seed file to your page, using the following script tag, and allow the YUI instance to download any additional files which may be required:
<script src="http://yui.yahooapis.com/3.0.0/build/yui/yui-min.js"></script>
<script src="http://yui.yahooapis.com/3.0.0/build/yui/yui-min.js"></script>The YUI instance will automatically pull down Stylesheet's source files and any missing dependencies when the stylesheet module is used. This helps you avoid having to manually manage the list of files needed on your page to support multiple components while also optimizing your initial page weight by loading files only when they are required.
If you do want to include file dependencies manually on your page, the YUI Dependency Configurator can be used to determine the list of files you need to include in order to use Stylesheet.
The YUI Instance
Once you have the YUI seed file on your page (yui-min.js), you can
create a new YUI instance for your application to use and populate it
with the modules you need, specified as the first set of arguments to the
use method:
// Create new YUI instance, and populate it with the required modules YUI().use('stylesheet', function(Y) { // Stylesheet available, and ready for use. });
// Create new YUI instance, and populate it with the required modules YUI().use('stylesheet', function(Y) { // Stylesheet available, and ready for use. });
The last argument passed to use is a callback function. The callback function will be invoked as soon as the YUI instance is done downloading any required files missing from your page. Once those files are loaded, your local YUI instance will be supplemented with the classes which make up the stylesheet module and any modules it depends on. A reference to the populated YUI instance (Y) is passed back to your callback function. Within your callback, then, you can start writing your application code based on your own custom instance of YUI.
For more information on creating instances of YUI and the
use method, see the
YUI Global object documentation.
Using the StyleSheet Utility
This section will address how to create and use Y.StyleSheet instances and includes:
- Instantiating
Y.StyleSheet - Getting a StyleSheet by registered name
- Creating and modifying CSS style rules
- Removing and resetting CSS style rules
- A note on selector strings
- Disabling and enabling a StyleSheet
- Static methods
Instantiating a Y.StyleSheet
The Y.StyleSheet constructor is written to support both function syntax and normal constructor syntax making the new prefix unnecessary (but harmless).
The constructor has no required parameters. Passing no arguments will create a new, empty StyleSheet instance.
// These are equivalent; both create new empty StyleSheets var myStyleSheet = new Y.StyleSheet(); var myOtherStyleSheet = Y.StyleSheet();
// These are equivalent; both create new empty StyleSheets var myStyleSheet = new Y.StyleSheet(); var myOtherStyleSheet = Y.StyleSheet();
To seed a new StyleSheet with a number of CSS rules, you can pass the constructor any of the following:
- a
<style>or<link>node reference, - the id of a
<style>or<link>node, or - a string of CSS
<link id="local" type="text/css" rel="stylesheet" href="local_file.css"> <style id="styleblock" type="text/css"> .some select.or { margin-right: 2em; } </style>
<link id="local" type="text/css" rel="stylesheet" href="local_file.css"> <style id="styleblock" type="text/css"> .some select.or { margin-right: 2em; } </style>
YUI().use('node','stylesheet', function (Y) { // Node or HTMLElement reference for a style or locally sourced link element var sheet = Y.StyleSheet(Y.one("#styleblock")); sheet = Y.StyleSheet(Y.DOM.byId('local')); // OR the id of a style element or locally sourced link element sheet = Y.StyleSheet('#local'); // OR string of css text var css = ".moduleX .alert { background: #fcc; font-weight: bold; } " + ".moduleX .warn { background: #eec; } " + ".hide_messages .moduleX .alert, " + ".hide_messages .moduleX .warn { display: none; }"; sheet = new Y.StyleSheet(css); //... });
YUI().use('node','stylesheet', function (Y) { // Node or HTMLElement reference for a style or locally sourced link element var sheet = Y.StyleSheet(Y.one("#styleblock")); sheet = Y.StyleSheet(Y.DOM.byId('local')); // OR the id of a style element or locally sourced link element sheet = Y.StyleSheet('#local'); // OR string of css text var css = ".moduleX .alert { background: #fcc; font-weight: bold; } " + ".moduleX .warn { background: #eec; } " + ".hide_messages .moduleX .alert, " + ".hide_messages .moduleX .warn { display: none; }"; sheet = new Y.StyleSheet(css); //... });
Be aware that the Same Origin policy
prevents access in some browsers to the style data of <link>
elements with hrefs pointing to other domains. Attempts to seed a
Y.StyleSheet instance with a cross-domain
<link> may result in a security error.
<link id="remote" type="text/css" rel="stylesheet" href="http://other.domain.com/remote_file.css">
<link id="remote" type="text/css" rel="stylesheet" href="http://other.domain.com/remote_file.css">
// ERROR - Same Origin Policy prevents access to remote stylesheets var styleSheet = Y.StyleSheet('remote');
// ERROR - Same Origin Policy prevents access to remote stylesheets var styleSheet = Y.StyleSheet('remote');
Getting a StyleSheet by registered name
Y.StyleSheet supports registering instances by name allowing them to be recalled by that same name elsewhere in your code. Internally, Y.StyleSheet maintains a registry of all created StyleSheet instances, using a unique generated id that the host node is tagged with. This allows future attempts to create a StyleSheet instance from the same node to return the previously created instance associated with that id.
Register a StyleSheet instance manually using the static register method or pass the desired name as a second parameter to the constructor.
var sheetA = Y.StyleSheet('my_stylesheet'); // Create a registry alias to sheetA. We'll call it bob. Y.StyleSheet.register(sheetA, 'bob'); // Create another StyleSheet passing the name as the second parameter var css = ".some .css { white-space: pre-wrap; color: pink; }"; var sheetB = Y.StyleSheet(css, 'my sheet'); // Meanwhile, elsewhere in your code // sheetA is the same instance as sheet1 and sheet2 var sheet1 = Y.StyleSheet(Y.one('#my_stylesheet')), sheet2 = Y.StyleSheet('bob'); // sheetB is the same instance as sheet3 var sheet3 = Y.StyleSheet('my sheet');
var sheetA = Y.StyleSheet('my_stylesheet'); // Create a registry alias to sheetA. We'll call it bob. Y.StyleSheet.register(sheetA, 'bob'); // Create another StyleSheet passing the name as the second parameter var css = ".some .css { white-space: pre-wrap; color: pink; }"; var sheetB = Y.StyleSheet(css, 'my sheet'); // Meanwhile, elsewhere in your code // sheetA is the same instance as sheet1 and sheet2 var sheet1 = Y.StyleSheet(Y.one('#my_stylesheet')), sheet2 = Y.StyleSheet('bob'); // sheetB is the same instance as sheet3 var sheet3 = Y.StyleSheet('my sheet');
If an unregistered name is passed as the first argument to the constructor, a new empty StyleSheet will be created and registered with that name. This allows you to use the following code pattern:
// Whichever of these executes first, an empty StyleSheet will be created // and registered as 'MyApp'. // In one area of your app Y.StyleSheet('MyApp').set('.module .messages', { display: 'none' }); //... // In another area of your app Y.StyleSheet('MyApp').unset('.module .messages','display');
// Whichever of these executes first, an empty StyleSheet will be created // and registered as 'MyApp'. // In one area of your app Y.StyleSheet('MyApp').set('.module .messages', { display: 'none' }); //... // In another area of your app Y.StyleSheet('MyApp').unset('.module .messages','display');
Summary of how the constructor handles the first argument
When nothing is passed as the first argument, a new StyleSheet instance is created.
When a <style> or <link> element is passed as the first argument, it is inspected for the id stamp that StyleSheet tags known host nodes with. If it finds one, it will return the associated StyleSheet from the registry. If not, it will stamp the node and seed the instance from the node's CSS content.
When a string is passed as the first argument, StyleSheet does the following things in order:
- Check the registry for an instance associated to that name. If found, return the instance.
- Check the DOM for a
<style>or<link>node with that id. If found, check the registry for an instance associated to its tagged id if present. If found, return that instance. If not, use that node to seed a new StyleSheet instance. - Check the string for a curly brace { character. If found, create a new instance seeded with the string as initial
cssText. - Create a new empty StyleSheet and register the instance by the provided string
Creating and modifying CSS style rules
The core method of StyleSheet instances is set(selector, style_properties). It will create or alter a CSS rule using the property:value pairs in style_properties targeting the provided selector. In essence, it looks very much like natural CSS syntax, except style properties must be in JavaScript's camelCase.
Y.StyleSheet('MyApp').set( "q.uoted select.or[str=ing]", { fontSize : "150%", // note the camel casing background : "#030 url(/images/bg_image.png) scroll repeat-y top left", cssFloat : "left", opacity : 0.5 });
Y.StyleSheet('MyApp').set( "q.uoted select.or[str=ing]", { fontSize : "150%", // note the camel casing background : "#030 url(/images/bg_image.png) scroll repeat-y top left", cssFloat : "left", opacity : 0.5 });
Rather than continually add new rules that will override one another, StyleSheet manages one rule per selector and modifies them in place. This may be relevant if you have two or more rules with selectors of the same specificity.
As with regular CSS syntax, comma-separated selectors are supported, but internally StyleSheet splits them up into individual rules because browser support for multiple selectors is not consistent. This means calling set(..) with such a selector string will incur multiple repaints or reflows, but limited to the number of atomic selectors.
// This is valid, but will trigger 3 reflows Y.StyleSheet('MyApp').set( '.foo, .bar, .baz', { borderRight: "1em solid #f00" });
// This is valid, but will trigger 3 reflows Y.StyleSheet('MyApp').set( '.foo, .bar, .baz', { borderRight: "1em solid #f00" });
Some style properties are normalized
Two style properties have differing implementation between browsers, namely float and opacity. StyleSheet instances will normalize these properties for you.
Because "float" is a reserved word in JavaScript, it is supported by the name cssFloat in W3C compliant browsers and styleFloat in IE. StyleSheet will accept any of these to set the float property.
// Any of these will work Y.StyleSheet('MyApp').set('.foo', { "float" : "left", // "float" must be quoted cssFloat : "right", styleFloat : "none" });
// Any of these will work Y.StyleSheet('MyApp').set('.foo', { "float" : "left", // "float" must be quoted cssFloat : "right", styleFloat : "none" });
IE does not support the opacity style property, but has equivalent functionality offered by its proprietary filter property, though using a different value syntax. StyleSheet will translate opacity to filter for IE, but it will not translate filter to opacity for W3C-compliant browsers.
Removing and resetting CSS style rules
When you want to remove a particular rule or style property from effecting the cascade, use unset(selector,propert[y|ies]).
unset(..) can be called in any of the following ways, with the noted result:
unset('.foo')— removes the rule associated to the selector entirelyunset('.foo','font')— unsets thefontproperty and any child properties (e.g. 'font-weight','font-variant','font-size','line-height', and 'font-family'). If there are no set properties left, the rule is removed.unset('.foo',['font','border',...])— same as above, but the rule is modified only once with the final applicablecssText.
It is important to note that there is a difference between setting a style property to its default value and unsetting it. The former can be achieved by calling set(selector, { property: "auto" }) (or the respective default value for that property).
However, as the CSS is reapplied to the page, the "auto" value will override any value for that property that may have cascaded in from another rule. This is different than removing the property assignment entirely, as this allows cascading values through.
Y.StyleSheet('MyApp').set('.foo', { background: 'auto' }); // is NOT the same as Y.StyleSheet('MyApp').unset('.foo','background');
Y.StyleSheet('MyApp').set('.foo', { background: 'auto' }); // is NOT the same as Y.StyleSheet('MyApp').unset('.foo','background');
A note on selector strings
Though the StyleSheet Utility takes selector strings as input to its API, it does not leverage the YUI selector engine. YUI's selector functionality supplements native CSS support for DOM access, but accomplishes this through efficient DOM traversal. Since the StyleSheet Utility uses the browser's built-in stylesheet and rule objects, it can not handle selectors that are not supported by the browser's native CSS parser.
// This will not cause a style change in IE 6, for example Y.StyleSheet('MyApp').set('input[type=checkbox]:checked', { verticalAlign : 'super' });
// This will not cause a style change in IE 6, for example Y.StyleSheet('MyApp').set('input[type=checkbox]:checked', { verticalAlign : 'super' });
Disabling and enabling a StyleSheet
Disabling a StyleSheet effectively turns it off; no CSS from that stylesheet is applied to the page. Disabling a StyleSheet does not remove the host node from the page, and style can be reapplied by enabling the StyleSheet again.
When StyleSheets are disabled, it is still possible to change their style rules via set and unset.
var sheet = Y.StyleSheet(styleNode); sheet.disable(); sheet.set('.foo', { backgroundColor: '#900', color: '#fff' }); sheet.set('.bar', { borderBottomColor: '#369' }); sheet.unset('.baz'); sheet.enable();
var sheet = Y.StyleSheet(styleNode); sheet.disable(); sheet.set('.foo', { backgroundColor: '#900', color: '#fff' }); sheet.set('.bar', { borderBottomColor: '#369' }); sheet.unset('.baz'); sheet.enable();
Static methods
Y.StyleSheet exposes a few static methods.
| Method | Use for |
|---|---|
register(instance, name) |
Use to assign a named registry entry for a StyleSheet instance. |
toCssText(property_obj, starting_cssText) |
Use to translate an object of style property:value pairs to a single cssText string. The optional second argument is a cssText string of a style's "before" state. |
Y.StyleSheet.toCssText is used internally to assemble the cssText strings for updating the stylesheet rules. However, it may also be helpful for avoiding reflow overhead when substantially modifying a single element's style.
var el = Y.one('some_element'), changes = { color : '#684', fontWeight: 'bold', padding: '2em' }, currentStyle = el.getStyle('cssText'); el.setStyle('cssText', Y.StyleSheet.toCssText(changes, currentStyle));
var el = Y.one('some_element'), changes = { color : '#684', fontWeight: 'bold', padding: '2em' }, currentStyle = el.getStyle('cssText'); el.setStyle('cssText', Y.StyleSheet.toCssText(changes, currentStyle));
How Y.StyleSheet works
Browsers grant access via the DOM API to stylesheets included in markup as <link> or <style> elements. Despite differing implementations across the browser spectrum, they all support adding, removing, and modifying CSS rules.
CSS rules are comprised of a selector and collection of style property:value pairs enclosed in curly braces.
/* | This is a CSS rule | | selectorText | style properties | */ div.this-is a .rule { font-color: #f00; }
/* | This is a CSS rule | | selectorText | style properties | */ div.this-is a .rule { font-color: #f00; }
In JavaScript, each rule object has a selectorText property and a style property that operates in the same way as the style property on regular DOM elements, such as <p> or <strong> elements.
Arguably the most valuable property of the style collection is cssText which corresponds to the serialized summary of property:value pairs applied by this collection (e.g. "font-size: 100%; color: #FF0000;"). The reason this property is important is that modifications to the string value will cause changes to repopulate the individual style properties while only triggering a single repaint or reflow by the browser.
var el = document.getElementById('some_element'); el.style.borderBottom = '3px solid #eee'; // reflow el.style.borderTop = '3px solid #ccc'; // another reflow el.style.fontWeight = 'bold'; // another reflow // Vs. three changes in one reflow el.style.cssText += '; border-bottom: 3px solid #eee; border-top: 3px solid #ccc; font-weight: bold';
var el = document.getElementById('some_element'); el.style.borderBottom = '3px solid #eee'; // reflow el.style.borderTop = '3px solid #ccc'; // another reflow el.style.fontWeight = 'bold'; // another reflow // Vs. three changes in one reflow el.style.cssText += '; border-bottom: 3px solid #eee; border-top: 3px solid #ccc; font-weight: bold';
Y.StyleSheet leverages this mechanism in addition to applying modifications at the CSS rule level rather than modifying each targeted DOM node directly. This means changing multiple style properties on multiple elements (that can be identified by a single selector) will only ever incur one repaint or reflow.
It must be noted that all reflows are not the same. The scope of a reflow is greatly affected by what element triggered it. For example, changing a style of an absolutely positioned element will trigger a very limited reflow because the browser understands that not much could change as a result. Stylesheet modifications on the other hand are not tied to an element, but the page as a whole. The CSS cascade must be recalculated and applied, resulting in a full page reflow. This means it may be more efficient to individually update many elements than to change the stylesheet.
Support & Community
Forums & Blog
YUI 3 discussion forums are hosted on YUILibrary.com.
In addition, please visit the YUIBlog for updates and articles about the YUI Library written by the library's developers.
Filing Bugs & Feature Requests
The YUI Library's public bug tracking and feature request repositories are located on the YUILibrary.com site. Before filing new feature requests or bug reports, please review our reporting guidelines.

