YUI 3.x Home -

Site Search (YDN & YUIBlog):

# YUI Library Examples: StyleSheet: Adjusting a page theme on the fly

## StyleSheet: Adjusting a page theme on the fly

In this example, we'll use a snapshot of the W3C HTML 4.01 specification for Style Sheets and add a custom dynamic StyleSheet to apply some color and font size changes.

A Progressive enhancement strategy is used to extract a static form on the page into a draggable Overlay. Additionally, one of the form inputs is replaced with a Slider. Enter any valid CSS color value into the other inputs (e.g. `#123456`, `#135`, `rgb(0,0,0)`, or `red`).

View example in new window.

### Full code listing

#### Markup

The markup as stated above is a local snapshot of the HTML 4.01 spec, but with the following markup added to the end of the `<body>` to show a progressive enhancement model.

    <!-- The original body content is above --><div id="form_container">    <form class="yui3-widget-bd" id="theme_form" action="#" method="get">        <fieldset>            <h3>Update Theme</h3>            <label for="font_size">Font size:</label>            <input type="text" size="3" id="font_size" value="16px">             <label for="heading_color">Heading color:</label>            <input type="text" size="12" id="heading_color" value="#005A9C">             <label for="link_hover">Link hover backgound:</label>            <input type="text" size="12" id="link_hover" value="#ffa">        </fieldset>        <input type="submit">    </form></div>

    <!-- The original body content is above -->
    <div id="form_container">
        <form class="yui3-widget-bd" id="theme_form" action="#" method="get">
            <fieldset>
                <h3>Update Theme</h3>
                <label for="font_size">Font size:</label>
                <input type="text" size="3" id="font_size" value="16px">

                <label for="heading_color">Heading color:</label>
                <input type="text" size="12" id="heading_color" value="#005A9C">

                <label for="link_hover">Link hover backgound:</label>
                <input type="text" size="12" id="link_hover" value="#ffa">
            </fieldset>
            <input type="submit">
        </form>
    </div>

<!-- The original body content is above --> <div id="form_container"> <form class="yui3-widget-bd" id="theme_form" action="#" method="get"> <fieldset> <h3>Update Theme</h3> <label for="font_size">Font size:</label> <input type="text" size="3" id="font_size" value="16px"> <label for="heading_color">Heading color:</label> <input type="text" size="12" id="heading_color" value="#005A9C"> <label for="link_hover">Link hover backgound:</label> <input type="text" size="12" id="link_hover" value="#ffa"> </fieldset> <input type="submit"> </form> </div>

#### JavaScript

    // Create a new YUI instance, requiring stylesheet, overlay, slider, and the// dd-plugin to make the overlay draggableYUI().use("stylesheet", "overlay", "slider", "dd-plugin", function (Y) {     var myStyleSheet = new Y.StyleSheet(),        overlayContent = Y.one('#form_container'),        overlay,        slider,        slider_container,        fontSizeInput,     // Create the Overlay, using the form container as the contentBox.    // The form is assigned a class yui-widget-bd that will be automatically    // discovered by Overlay to populate the Overlay's body section.    // The overlay is positioned in the top right corner, but made draggable    // using Y.Plugin.Drag, provided by the dd-plugin module.    overlay = new Y.Overlay({        srcNode: overlayContent,        width: '225px',        align: { points: [ Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.TR ] },        plugins: [ Y.Plugin.Drag ]    }).render();     // Slider needs a parent element to have the sam skin class for UI skinning    overlayContent.addClass('yui3-skin-sam');     // Progressively enhance the font-size input with a Slider    fontSizeInput = Y.one('#font_size');    fontSizeInput.set('type','hidden');    fontSizeInput.get('parentNode').insertBefore(        Y.Node.create('6 <span></span> 36'),        fontSizeInput);     slider_container = fontSizeInput.previous( "span" );     // Create a Slider to contain font size between 6px and 36px, using the    // page's current font size as the initial value.    // Set up an event subscriber during construction to update the replaced    // input field's value and apply the change to the StyleSheet    slider = new Y.Slider({        length: '100px',        min: 6,        max: 36,        value: parseInt(Y.one('body').getStyle('fontSize')) || 13,        after: {            valueChange: function (e) {                var size = e.newVal + 'px';                 this.thumb.set('title', size);                fontSizeInput.set('value', size);                 myStyleSheet.set('body', { fontSize: size });            }        }    }).render( slider_container );     // The color inputs are assigned keyup listeners that will update the    // StyleSheet if the current input value is a valid CSS color value     // The heading input affects all h1s, h2, and h3s    Y.on('keyup', function (e) {        var color = this.get('value');         if (isValidColor(color)) {            myStyleSheet.set('h1, h2, h3', { color: color });        }    }, '#heading_color');     // The link hover affects the background color of links when they are    // hovered.  There is no way other than via stylesheet modification to    // change pseudo-class styles.    Y.on('keyup', function (e) {        var color = this.get('value');         if (isValidColor(color)) {            myStyleSheet.set('a:hover', { backgroundColor: color });        }    }, '#link_hover');     // Progressive form enhancement complete, now prevent the form from    // submitting normally.    Y.on('submit', function (e) {        e.halt();    }, '#theme_form'); 	// A rudimentary validator to make sure we're not trying to set	// invalid color values in StyleSheet.	function isValidColor(v) {        return /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(v) ||               /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/.test(v) ||               /^[a-z]{3,}$/i.test(v);	} });

    // Create a new YUI instance, requiring stylesheet, overlay, slider, and the
    // dd-plugin to make the overlay draggable
    YUI().use("stylesheet", "overlay", "slider", "dd-plugin", function (Y) {

        var myStyleSheet = new Y.StyleSheet(),
            overlayContent = Y.one('#form_container'),
            overlay,
            slider,
            slider_container,
            fontSizeInput,

        // Create the Overlay, using the form container as the contentBox.
        // The form is assigned a class yui-widget-bd that will be automatically
        // discovered by Overlay to populate the Overlay's body section.
        // The overlay is positioned in the top right corner, but made draggable
        // using Y.Plugin.Drag, provided by the dd-plugin module.
        overlay = new Y.Overlay({
            srcNode: overlayContent,
            width: '225px',
            align: { points: [ Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.TR ] },
            plugins: [ Y.Plugin.Drag ]
        }).render();

        // Slider needs a parent element to have the sam skin class for UI skinning
        overlayContent.addClass('yui3-skin-sam');

        // Progressively enhance the font-size input with a Slider
        fontSizeInput = Y.one('#font_size');
        fontSizeInput.set('type','hidden');
        fontSizeInput.get('parentNode').insertBefore(
            Y.Node.create('6 <span></span> 36'),
            fontSizeInput);

        slider_container = fontSizeInput.previous( "span" );

        // Create a Slider to contain font size between 6px and 36px, using the
        // page's current font size as the initial value.
        // Set up an event subscriber during construction to update the replaced
        // input field's value and apply the change to the StyleSheet
        slider = new Y.Slider({
            length: '100px',
            min: 6,
            max: 36,
            value: parseInt(Y.one('body').getStyle('fontSize')) || 13,
            after: {
                valueChange: function (e) {
                    var size = e.newVal + 'px';

                    this.thumb.set('title', size);
                    fontSizeInput.set('value', size);

                    myStyleSheet.set('body', { fontSize: size });
                }
            }
        }).render( slider_container );

        // The color inputs are assigned keyup listeners that will update the
        // StyleSheet if the current input value is a valid CSS color value

        // The heading input affects all h1s, h2, and h3s
        Y.on('keyup', function (e) {
            var color = this.get('value');

            if (isValidColor(color)) {
                myStyleSheet.set('h1, h2, h3', { color: color });
            }
        }, '#heading_color');

        // The link hover affects the background color of links when they are
        // hovered.  There is no way other than via stylesheet modification to
        // change pseudo-class styles.
        Y.on('keyup', function (e) {
            var color = this.get('value');

            if (isValidColor(color)) {
                myStyleSheet.set('a:hover', { backgroundColor: color });
            }
        }, '#link_hover');

        // Progressive form enhancement complete, now prevent the form from
        // submitting normally.
        Y.on('submit', function (e) {
            e.halt();
        }, '#theme_form');

    	// A rudimentary validator to make sure we're not trying to set
    	// invalid color values in StyleSheet.
    	function isValidColor(v) {
            return /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(v) ||
                   /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/.test(v) ||
                   /^[a-z]{3,}$/i.test(v);
    	}

    });

// Create a new YUI instance, requiring stylesheet, overlay, slider, and the // dd-plugin to make the overlay draggable YUI().use("stylesheet", "overlay", "slider", "dd-plugin", function (Y) { var myStyleSheet = new Y.StyleSheet(), overlayContent = Y.one('#form_container'), overlay, slider, slider_container, fontSizeInput, // Create the Overlay, using the form container as the contentBox. // The form is assigned a class yui-widget-bd that will be automatically // discovered by Overlay to populate the Overlay's body section. // The overlay is positioned in the top right corner, but made draggable // using Y.Plugin.Drag, provided by the dd-plugin module. overlay = new Y.Overlay({ srcNode: overlayContent, width: '225px', align: { points: [ Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.TR ] }, plugins: [ Y.Plugin.Drag ] }).render(); // Slider needs a parent element to have the sam skin class for UI skinning overlayContent.addClass('yui3-skin-sam'); // Progressively enhance the font-size input with a Slider fontSizeInput = Y.one('#font_size'); fontSizeInput.set('type','hidden'); fontSizeInput.get('parentNode').insertBefore( Y.Node.create('6 <span></span> 36'), fontSizeInput); slider_container = fontSizeInput.previous( "span" ); // Create a Slider to contain font size between 6px and 36px, using the // page's current font size as the initial value. // Set up an event subscriber during construction to update the replaced // input field's value and apply the change to the StyleSheet slider = new Y.Slider({ length: '100px', min: 6, max: 36, value: parseInt(Y.one('body').getStyle('fontSize')) || 13, after: { valueChange: function (e) { var size = e.newVal + 'px'; this.thumb.set('title', size); fontSizeInput.set('value', size); myStyleSheet.set('body', { fontSize: size }); } } }).render( slider_container ); // The color inputs are assigned keyup listeners that will update the // StyleSheet if the current input value is a valid CSS color value // The heading input affects all h1s, h2, and h3s Y.on('keyup', function (e) { var color = this.get('value'); if (isValidColor(color)) { myStyleSheet.set('h1, h2, h3', { color: color }); } }, '#heading_color'); // The link hover affects the background color of links when they are // hovered. There is no way other than via stylesheet modification to // change pseudo-class styles. Y.on('keyup', function (e) { var color = this.get('value'); if (isValidColor(color)) { myStyleSheet.set('a:hover', { backgroundColor: color }); } }, '#link_hover'); // Progressive form enhancement complete, now prevent the form from // submitting normally. Y.on('submit', function (e) { e.halt(); }, '#theme_form'); // A rudimentary validator to make sure we're not trying to set // invalid color values in StyleSheet. function isValidColor(v) { return /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(v) || /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/.test(v) || /^[a-z]{3,}$/i.test(v); } });

#### CSS

This is the CSS added to the page to skin the Overlay and its content.

    /* For supporting browsers, the overlay is rendered semi-transparent with * fancy rounded corners */.yui3-overlay {    background: rgba(128,128,128,0.3);    -moz-border-radius: 10px;    -webkit-border-radius: 10px;    border-radius: 10px;    padding: 7px;    cursor: move;} .yui3-overlay-content {    background: rgba(205,205,205,0.3);    -moz-border-radius: 10px;    -webkit-border-radius: 10px;    border-radius: 10px;    padding: 1px;}  .yui3-overlay form {    background: #f2fbff url(gradient-promo.png) repeat-x scroll 0 0;    border: 2px solid #fff;    -moz-border-radius: 10px;    -webkit-border-radius: 10px;    border-radius: 10px;    margin: 0;    padding: 0;    font-size: 13px;} .yui3-overlay fieldset {    border: 1px solid #bcd;    -moz-border-radius: 10px;    -webkit-border-radius: 10px;    border-radius: 10px;    margin: 0;    padding: 20px;} .yui3-overlay h3 {    border-bottom: 2px solid #fff;    color: #479;    background: transparent;    margin: 0;    font-size: 175%;} .yui3-overlay label {    display: block;    margin: 1.3em 0 0.5ex;    font-weight: bold;    color: #003;} .yui3-overlay p {    margin: 2em 0 0;} /* override the move cursor for the Slider */.yui3-overlay .yui3-slider:hover {    cursor: default;}

    /* For supporting browsers, the overlay is rendered semi-transparent with
     * fancy rounded corners */
    .yui3-overlay {
        background: rgba(128,128,128,0.3);
        -moz-border-radius: 10px;
        -webkit-border-radius: 10px;
        border-radius: 10px;
        padding: 7px;
        cursor: move;
    }

    .yui3-overlay-content {
        background: rgba(205,205,205,0.3);
        -moz-border-radius: 10px;
        -webkit-border-radius: 10px;
        border-radius: 10px;
        padding: 1px;
    }

    .yui3-overlay form {
        background: #f2fbff url(gradient-promo.png) repeat-x scroll 0 0;
        border: 2px solid #fff;
        -moz-border-radius: 10px;
        -webkit-border-radius: 10px;
        border-radius: 10px;
        margin: 0;
        padding: 0;
        font-size: 13px;
    }

    .yui3-overlay fieldset {
        border: 1px solid #bcd;
        -moz-border-radius: 10px;
        -webkit-border-radius: 10px;
        border-radius: 10px;
        margin: 0;
        padding: 20px;
    }

    .yui3-overlay h3 {
        border-bottom: 2px solid #fff;
        color: #479;
        background: transparent;
        margin: 0;
        font-size: 175%;
    }

    .yui3-overlay label {
        display: block;
        margin: 1.3em 0 0.5ex;
        font-weight: bold;
        color: #003;
    }

    .yui3-overlay p {
        margin: 2em 0 0;
    }

    /* override the move cursor for the Slider */
    .yui3-overlay .yui3-slider:hover {
        cursor: default;
    }

/* For supporting browsers, the overlay is rendered semi-transparent with * fancy rounded corners */ .yui3-overlay { background: rgba(128,128,128,0.3); -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; padding: 7px; cursor: move; } .yui3-overlay-content { background: rgba(205,205,205,0.3); -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; padding: 1px; } .yui3-overlay form { background: #f2fbff url(gradient-promo.png) repeat-x scroll 0 0; border: 2px solid #fff; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; margin: 0; padding: 0; font-size: 13px; } .yui3-overlay fieldset { border: 1px solid #bcd; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; margin: 0; padding: 20px; } .yui3-overlay h3 { border-bottom: 2px solid #fff; color: #479; background: transparent; margin: 0; font-size: 175%; } .yui3-overlay label { display: block; margin: 1.3em 0 0.5ex; font-weight: bold; color: #003; } .yui3-overlay p { margin: 2em 0 0; } /* override the move cursor for the Slider */ .yui3-overlay .yui3-slider:hover { cursor: default; }

Copyright © 2010 Yahoo! Inc. All rights reserved.

Privacy Policy - Terms of Service - Copyright Policy - Job Openings