5
<title>StyleSheet</title>
6
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Maven+Pro:400,700">
7
<link rel="stylesheet" href="../../build/cssgrids/grids-min.css">
8
<link rel="stylesheet" href="../assets/css/main.css">
9
<link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
10
<script src="../../build/yui/yui-min.js"></script>
18
<a href="#toc" class="jump">Jump to Table of Contents</a>
22
<div class="yui3-u-3-4">
24
<div class="content"><div class="intro component">
26
The StyleSheet module normalizes the dynamic creation and modification
27
of CSS stylesheets on a page. This makes it easy to manage the
28
development, storage, and reapplication of personalized user
29
stylesheets. Because it targets styles at the CSS level, it also
30
allows you to modify styles applied to a CSS pseudo-element such as
31
<code>p::first-letter</code>, or pseudo-class such as
36
StyleSheet is capable of creating new stylesheets from scratch or
37
modifying existing stylesheets held as properties of
38
<code><link></code> or <code><style></code> elements. It
39
should be noted that not all browsers support reading or modifying
40
external stylesheets from other domains.
44
<h2 id="getting-started">Getting Started</h2>
47
To include the source files for StyleSheet and its dependencies, first load
48
the YUI seed file if you haven't already loaded it.
51
<pre class="code prettyprint"><script src="http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js"></script></pre>
55
Next, create a new YUI instance for your application and populate it with the
56
modules you need by specifying them as arguments to the <code>YUI().use()</code> method.
57
YUI will automatically load any dependencies required by the modules you
61
<pre class="code prettyprint"><script>
62
// Create a new YUI instance and populate it with the required modules.
63
YUI().use('stylesheet', function (Y) {
64
// StyleSheet is available and ready for use. Add implementation
65
// code here.
67
</script></pre>
71
For more information on creating YUI instances and on the
72
<a href="http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_use"><code>use()</code> method</a>, see the
73
documentation for the <a href="../yui/index.html">YUI Global Object</a>.
77
<h2 id="using">Using the StyleSheet Utility</h2>
79
<h3 id="instantiating">Instantiating a <code>Y.StyleSheet</code></h3>
82
The <code>Y.StyleSheet</code> constructor is written to support both
83
function syntax and normal constructor syntax making the <code>new</code>
84
prefix unnecessary (but harmless).
88
The constructor has no required parameters. Passing no arguments will
89
create a new, empty StyleSheet instance.
92
<pre class="code prettyprint">// These are equivalent; both create new empty StyleSheets
93
var myStyleSheet = new Y.StyleSheet();
95
var myOtherStyleSheet = Y.StyleSheet();</pre>
99
To seed a new StyleSheet with a number of CSS rules, you can pass the
100
constructor any of the following:
105
a <code><style></code> or <code><link></code> node
109
the id of a <code><style></code> or <code><link></code>
112
<li>a string of CSS</li>
115
<pre class="code prettyprint"><link id="local" type="text/css" rel="stylesheet" href="local_file.css">
116
<style id="styleblock" type="text/css">
120
</style></pre>
123
<pre class="code prettyprint">YUI().use('node','stylesheet', function (Y) {
125
// Node or HTMLElement reference for a style or locally sourced link element
126
var sheet = Y.StyleSheet(Y.one("#styleblock"));
127
sheet = Y.StyleSheet(Y.DOM.byId('local'));
129
// OR the id of a style element or locally sourced link element
130
sheet = Y.StyleSheet('#local');
132
// OR string of css text
133
var css = ".moduleX .alert { background: #fcc; font-weight: bold; } " +
134
".moduleX .warn { background: #eec; } " +
135
".hide_messages .moduleX .alert, " +
136
".hide_messages .moduleX .warn { display: none; }";
138
sheet = new Y.StyleSheet(css);
146
href="http://en.wikipedia.org/wiki/Same_origin_policy">Same Origin
147
policy</a> prevents access in some browsers to the style data of
148
<code><link></code> elements with <code>href</code>s pointing to
149
other domains. Attempts to seed a <code>Y.StyleSheet</code> instance with
150
a cross-domain <code><link></code> may result in a security
154
<pre class="code prettyprint"><link id="remote" type="text/css" rel="stylesheet" href="http://other.domain.com/remote_file.css"></pre>
157
<pre class="code prettyprint">// ERROR - Same Origin Policy prevents access to remote stylesheets
158
var styleSheet = Y.StyleSheet('remote');</pre>
161
<h3 id="registry">Getting a StyleSheet by registered name</h3>
164
<code>Y.StyleSheet</code> supports registering instances by name allowing
165
them to be recalled by that same name elsewhere in your code. Internally,
166
<code>Y.StyleSheet</code> maintains a registry of all created StyleSheet
167
instances, using a unique generated id that the host node is tagged with.
168
This allows future attempts to create a StyleSheet instance from the same
169
node to return the previously created instance associated with that id.
173
Register a StyleSheet instance manually using the static
174
<code>register</code> method or pass the desired name as a second parameter
178
<pre class="code prettyprint">var sheetA = Y.StyleSheet('my_stylesheet');
180
// Create a registry alias to sheetA. We'll call it bob.
181
Y.StyleSheet.register(sheetA, 'bob');
183
// Create another StyleSheet passing the name as the second parameter
184
var css = ".some .css { white-space: pre-wrap; color: pink; }";
185
var sheetB = Y.StyleSheet(css, 'my sheet');
187
// Meanwhile, elsewhere in your code
189
// sheetA is the same instance as sheet1 and sheet2
190
var sheet1 = Y.StyleSheet(Y.one('#my_stylesheet')),
191
sheet2 = Y.StyleSheet('bob');
193
// sheetB is the same instance as sheet3
194
var sheet3 = Y.StyleSheet('my sheet');</pre>
198
If an unregistered name is passed as the <em>first</em> argument to the
199
constructor, a new empty StyleSheet will be created and registered with
200
that name. This allows you to use the following code pattern:
203
<pre class="code prettyprint">// Whichever of these executes first, an empty StyleSheet will be created
204
// and registered as 'MyApp'.
206
// In one area of your app
207
Y.StyleSheet('MyApp').set('.module .messages', { display: 'none' });
211
// In another area of your app
212
Y.StyleSheet('MyApp').unset('.module .messages','display');</pre>
215
<h3 id="first_param">Summary of how the constructor handles the first argument</h3>
218
When nothing is passed as the first argument, a new StyleSheet instance is
223
When a <code><style></code> or <code><link></code> element is
224
passed as the first argument, it is inspected for the id stamp that
225
StyleSheet tags known host nodes with. If it finds one, it will return the
226
associated StyleSheet from the registry. If not, it will stamp the node
227
and seed the instance from the node's CSS content.
231
When a string is passed as the first argument, StyleSheet does the
232
following things in order:
237
Check the registry for an instance associated to that name. If found,
241
Check the DOM for a <code><style></code> or
242
<code><link></code> node with that id. If found, check the
243
registry for an instance associated to its tagged id if present. If
244
found, return that instance. If not, use that node to seed a new
248
Check the string for a curly brace { character. If found, create a new
249
instance seeded with the string as initial <code>cssText</code>.
252
Create a new empty StyleSheet and register the instance by the provided
257
<h3 id="set">Creating and modifying CSS style rules</h3>
260
The core method of StyleSheet instances is <code>set(selector,
261
style_properties)</code>. It will create or alter a CSS rule using the
262
property:value pairs in <code>style_properties</code> targeting the
263
provided <code>selector</code>. In essence, it looks very much like
264
natural CSS syntax, <em>except style properties must be in JavaScript's
268
<pre class="code prettyprint">Y.StyleSheet('MyApp').set(
269
"q.uoted select.or[str=ing]", {
270
fontSize : "150%", // note the camel casing
271
background : "#030 url(/images/bg_image.png) scroll repeat-y top left",
272
cssFloat : "left",
278
Rather than continually add new rules that will override one another,
279
StyleSheet manages one rule per selector and modifies them in place. This
280
may be relevant if you have two or more rules with selectors of the same
285
As with regular CSS syntax, comma-separated selectors are supported, but
286
internally StyleSheet splits them up into individual rules because browser
287
support for multiple selectors is not consistent. This means calling
288
<code>set(..)</code> with such a selector string <em>will incur multiple
289
repaints or reflows</em>, but limited to the number of atomic
293
<pre class="code prettyprint">// This is valid, but will trigger 3 reflows
294
Y.StyleSheet('MyApp').set(
295
'.foo, .bar, .baz', {
296
borderRight: "1em solid #f00"
300
<h3 id="normalized_properties">Some style properties are normalized</h3>
303
Two style properties have differing implementation between browsers, namely
304
<code>float</code> and <code>opacity</code>. StyleSheet instances will
305
normalize these properties for you.
309
Because "float" is a reserved word in JavaScript, it is supported
310
by the name <code>cssFloat</code> in W3C compliant browsers and
311
<code>styleFloat</code> in IE. StyleSheet will accept any of these to set
312
the <code>float</code> property.
315
<pre class="code prettyprint">// Any of these will work
316
Y.StyleSheet('MyApp').set('.foo', {
317
"float" : "left", // "float" must be quoted
318
cssFloat : "right",
319
styleFloat : "none"
324
IE does not support the <code>opacity</code> style property, but has
325
equivalent functionality offered by its proprietary <code>filter</code>
326
property, though using a different value syntax. StyleSheet will translate
327
<code>opacity</code> to <code>filter</code> for IE, but it <em>will
328
not</em> translate <code>filter</code> to <code>opacity</code> for
329
W3C-compliant browsers.
332
<h3 id="unset">Removing and resetting CSS style rules</h3>
335
When you want to remove a particular rule or style property from affecting
336
the cascade, use <code>unset(selector,propert[y|ies])</code>.
340
<code>unset(..)</code> can be called in any of the following ways, with the
346
<code>unset('.foo')</code> — removes the rule associated to the
350
<code>unset('.foo','font')</code> — unsets the <code>font</code>
351
property and any child properties (e.g.
352
'font-weight','font-variant','font-size','line-height', and
353
'font-family'). If there are no set properties left, the rule is
357
<code>unset('.foo',['font','border',...])</code> — same as above,
358
but the rule is modified only once with the final applicable
359
<code>cssText</code>.
364
It is important to note that there is a difference between setting a style
365
property to its default value and unsetting it. The former can be achieved
366
by calling <code>set(selector, { property: "auto" })</code> (or
367
the respective default value for that property).
371
However, as the CSS is reapplied to the page, the "auto" value
372
will override any value for that property that may have cascaded in from
373
another rule. This is different than removing the property assignment
374
entirely, as this allows cascading values through.
377
<pre class="code prettyprint">Y.StyleSheet('MyApp').set('.foo', { background: 'auto' });
379
// is NOT the same as
381
Y.StyleSheet('MyApp').unset('.foo','background');</pre>
384
<h3 id="not_selector">A note on selector strings</h3>
387
Though the StyleSheet Utility takes selector strings as input to its API,
388
it <em>does not</em> leverage the YUI selector engine. YUI's selector
389
functionality supplements native CSS support for DOM access, but
390
accomplishes this through efficient DOM traversal. Since the StyleSheet
391
Utility uses the browser's built-in stylesheet and rule objects, it can not
392
handle selectors that are not supported by the browser's native CSS
396
<pre class="code prettyprint">// This will not cause a style change in IE 6, for example
397
Y.StyleSheet('MyApp').set('input[type=checkbox]:checked', {
398
verticalAlign : 'super'
402
<h3 id="disable">Disabling and enabling a StyleSheet</h3>
405
Disabling a StyleSheet effectively turns it off; no CSS from that
406
stylesheet is applied to the page. Disabling a StyleSheet does not remove
407
the host node from the page, and style can be reapplied by enabling the
412
When StyleSheets are disabled, it is still possible to change their style
413
rules via <code>set</code> and <code>unset</code>.
416
<pre class="code prettyprint">var sheet = Y.StyleSheet(styleNode);
419
sheet.set('.foo', { backgroundColor: '#900', color: '#fff' });
420
sheet.set('.bar', { borderBottomColor: '#369' });
421
sheet.unset('.baz');
422
sheet.enable();</pre>
425
<h3 id="static">Static methods</h3>
428
<code>Y.StyleSheet</code> exposes a few static methods.
431
<div class="apisummary">
442
<pre class="code prettyprint">Y.StyleSheet.register(instance, name)</pre>
445
<td>Use to assign a named registry entry for a StyleSheet instance.</td>
449
<pre class="code prettyprint">Y.StyleSheet.toCssText(property_obj, starting_cssText)</pre>
452
<td>Use to translate an object of style property:value pairs to a single <code>cssText</code> string. The optional second argument is a <code>cssText</code> string of a style's "before" state.</td>
459
<code>Y.StyleSheet.toCssText</code> is used internally to assemble the
460
<code>cssText</code> strings for updating the stylesheet rules. However,
461
it may also be helpful for avoiding reflow overhead when substantially
462
modifying a single element's style.
465
<pre class="code prettyprint">var el = Y.one('some_element'),
466
changes = { color : '#684', fontWeight: 'bold', padding: '2em' },
467
currentStyle = el.getStyle('cssText');
469
el.setStyle('cssText',
470
Y.StyleSheet.toCssText(changes, currentStyle));</pre>
473
<h2 id="mechanism">How <code>Y.StyleSheet</code> works</h2>
476
Browsers grant access via the DOM API to stylesheets included in markup as
477
<code><link></code> or <code><style></code> elements. Despite
478
differing implementations across the browser spectrum, they all support
479
adding, removing, and modifying CSS rules.
483
CSS rules are comprised of a selector and collection of style
484
property:value pairs enclosed in curly braces.
487
<pre class="code prettyprint">/* | This is a CSS rule |
488
| selectorText | style properties | */
489
div.this-is a .rule { font-color: #f00; }</pre>
493
In JavaScript, each rule object has a <code>selectorText</code> property
494
and a <code>style</code> property that operates in the same way as the
495
<code>style</code> property on regular DOM elements, such as
496
<code><p></code> or <code><strong></code> elements.
500
Arguably the most valuable property of the style collection is
501
<code>cssText</code> which corresponds to the serialized summary of
502
property:value pairs applied by this collection (e.g. "font-size: 100%;
503
color: #FF0000;"). The reason this property is important is that
504
modifications to the string value will cause changes to repopulate the
505
individual style properties <em>while only triggering a single repaint or
506
reflow</em> by the browser.
509
<pre class="code prettyprint">var el = document.getElementById('some_element');
511
el.style.borderBottom = '3px solid #eee'; // reflow
512
el.style.borderTop = '3px solid #ccc'; // another reflow
513
el.style.fontWeight = 'bold'; // another reflow
515
// Vs. three changes in one reflow
516
el.style.cssText += '; border-bottom: 3px solid #eee; border-top: 3px solid #ccc; font-weight: bold';</pre>
520
<code>Y.StyleSheet</code> leverages this mechanism in addition to applying
521
modifications at the CSS rule level rather than modifying each targeted DOM
522
node directly. This means changing multiple style properties on multiple
523
elements (that can be identified by a single selector) will only ever incur
524
one repaint or reflow.
528
It must be noted that all reflows are not the same. The scope of a reflow
529
is greatly affected by what element triggered it. For example, changing a
530
style of an absolutely positioned element will trigger a very limited
531
reflow because the browser understands that not much <em>could</em> change
532
as a result. Stylesheet modifications on the other hand are not tied to an
533
element, but the page as a whole. The CSS cascade must be recalculated and
534
applied, resulting in a full page reflow. This means it may be more
535
efficient to individually update many elements than to change the
539
<h2 id="knownissues">Known Issues</h2>
542
<strong>Unable to set style values with
543
<code>!important</code></strong>.
547
CSS syntax for declaring that a style value has <code>important</code>
548
priority is to include the <code>!important</code> flag after the
552
<pre class="code prettyprint">.some-class {
553
color: #000 !important;
558
However, the DOM API for modifying stylesheets does not parse out the
559
<code>!important</code> flag from the assigned value string, and thus
560
considers the entire string to be an invalid value.
563
<pre class="code prettyprint">el.style.color = "#000 !important"; // Error</pre>
567
StyleSheet will support <code>!important</code> in the value string in a
568
future release, but for now the only way to assign an
569
<code>!important</code> style is by creating a new StyleSheet, passing a
570
CSS text string to the constructor.
573
<pre class="code prettyprint">var sheet = new Y.StyleSheet();
574
sheet.set(".foo", { color: "#000 !important" }); // FAIL
576
new Y.StyleSheet(".foo { color: #000 !important; }"); // WORKS</pre>
582
<div class="yui3-u-1-4">
583
<div class="sidebar">
585
<div id="toc" class="sidebox">
587
<h2 class="no-toc">Table of Contents</h2>
593
<a href="#getting-started">Getting Started</a>
596
<a href="#using">Using the StyleSheet Utility</a>
599
<a href="#instantiating">Instantiating a <code>Y.StyleSheet</code></a>
602
<a href="#registry">Getting a StyleSheet by registered name</a>
605
<a href="#first_param">Summary of how the constructor handles the first argument</a>
608
<a href="#set">Creating and modifying CSS style rules</a>
611
<a href="#normalized_properties">Some style properties are normalized</a>
614
<a href="#unset">Removing and resetting CSS style rules</a>
617
<a href="#not_selector">A note on selector strings</a>
620
<a href="#disable">Disabling and enabling a StyleSheet</a>
623
<a href="#static">Static methods</a>
628
<a href="#mechanism">How <code>Y.StyleSheet</code> works</a>
631
<a href="#knownissues">Known Issues</a>
639
<div class="sidebox">
641
<h2 class="no-toc">Examples</h2>
645
<ul class="examples">
648
<li data-description="Use StyleSheet to adjust the CSS rules applying a page theme from user input">
649
<a href="stylesheet-theme.html">Adjusting a Page Theme on the Fly</a>
661
<div class="sidebox">
663
<h2 class="no-toc">Examples That Use This Component</h2>
667
<ul class="examples">
672
<li data-description="Example Photo Browser application.">
673
<a href="../dd/photo-browser.html">Photo Browser</a>
686
<script src="../assets/vendor/prettify/prettify-min.js"></script>
687
<script>prettyPrint();</script>