YUI 3.x Home -

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).

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.

  1. <!-- The original body content is above -->
  2. <div id="form_container">
  3. <form class="yui-widget-bd" id="theme_form" action="#" method="get">
  4. <fieldset>
  5. <h3>Update Theme</h3>
  6. <label for="font_size">Font size:</label>
  7. <input type="text" size="3" id="font_size" value="16px">
  8.  
  9. <label for="heading_color">Heading color:</label>
  10. <input type="text" size="12" id="heading_color" value="#005A9C">
  11.  
  12. <label for="link_hover">Link hover backgound:</label>
  13. <input type="text" size="12" id="link_hover" value="#ffa">
  14. </fieldset>
  15. <input type="submit">
  16. </form>
  17. </div>
<!-- The original body content is above -->
<div id="form_container">
    <form class="yui-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

  1. // Create a new YUI instance, requiring stylesheet, overlay, slider, and the
  2. // dd-plugin to make the overlay draggable
  3. YUI({base:"../../build/", timeout: 10000}).use("stylesheet", "overlay", "slider", "dd-plugin", function (Y) {
  4.  
  5. var myStyleSheet = new Y.StyleSheet(),
  6. overlayContent = Y.one('#form_container'),
  7. overlay,
  8. slider,
  9. fontSizeInput,
  10.  
  11. // Create the Overlay, using the form container as the contentBox.
  12. // The form is assigned a class yui-widget-bd that will be automatically
  13. // discovered by Overlay to populate the Overlay's body section.
  14. // The overlay is positioned in the top right corner, but made draggable
  15. // using Y.Plugin.Drag, provided by the dd-plugin module.
  16. overlay = new Y.Overlay({
  17. contentBox: overlayContent,
  18. width: '225px',
  19. align: { points: [ Y.WidgetPositionExt.TR, Y.WidgetPositionExt.TR ] },
  20. plugins: [ Y.Plugin.Drag ]
  21. }).render();
  22.  
  23. // Slider needs a parent element to have the sam skin class for UI skinning
  24. overlayContent.addClass('yui-skin-sam');
  25.  
  26. // Progressively enhance the font-size input with a Slider
  27. fontSizeInput = Y.one('#font_size');
  28. fontSizeInput.set('type','hidden');
  29. fontSizeInput.get('parentNode').insertBefore(
  30. Y.Node.create('6 <div id="font_slider"></div> 36'),
  31. fontSizeInput);
  32.  
  33. // Create a Slider to contain font size between 6px and 36px, using the
  34. // page's current font size as the initial value.
  35. // Set up an event subscriber during construction to update the replaced
  36. // input field's value and apply the change to the StyleSheet
  37. slider = new Y.Slider({
  38. boundingBox: '#font_slider',
  39. railSize: '100px',
  40. thumbImage: Y.config.base + '/slider/assets/skins/sam/thumb-classic-x.png',
  41. min: 6,
  42. max: 36,
  43. value: parseInt(Y.one('body').getStyle('fontSize')) || 13,
  44. after: {
  45. valueChange: function (e) {
  46. var size = e.newVal + 'px';
  47.  
  48. this.get('thumb').set('title', size);
  49. fontSizeInput.set('value', size);
  50.  
  51. myStyleSheet.set('body', { fontSize: size });
  52. }
  53. }
  54. }).render();
  55.  
  56. // The color inputs are assigned keyup listeners that will update the
  57. // StyleSheet if the current input value is a valid CSS color value
  58.  
  59. // The heading input affects all h1s, h2, and h3s
  60. Y.on('keyup', function (e) {
  61. var color = this.get('value');
  62.  
  63. if (isValidColor(color)) {
  64. myStyleSheet.set('h1, h2, h3', { color: color });
  65. }
  66. }, '#heading_color');
  67.  
  68. // The link hover affects the background color of links when they are
  69. // hovered. There is no way other than via stylesheet modification to
  70. // change pseudo-class styles.
  71. Y.on('keyup', function (e) {
  72. var color = this.get('value');
  73.  
  74. if (isValidColor(color)) {
  75. myStyleSheet.set('a:hover', { backgroundColor: color });
  76. }
  77. }, '#link_hover');
  78.  
  79. // Progressive form enhancement complete, now prevent the form from
  80. // submitting normally.
  81. Y.on('submit', function (e) {
  82. e.halt();
  83. }, '#theme_form');
  84.  
  85. // A rudimentary validator to make sure we're not trying to set
  86. // invalid color values in StyleSheet.
  87. function isValidColor(v) {
  88. return /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(v) ||
  89. /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/.test(v) ||
  90. /^[a-z]{3,}$/i.test(v);
  91. }
  92.  
  93. });
// Create a new YUI instance, requiring stylesheet, overlay, slider, and the
// dd-plugin to make the overlay draggable
YUI({base:"../../build/", timeout: 10000}).use("stylesheet", "overlay", "slider", "dd-plugin", function (Y) {
 
    var myStyleSheet = new Y.StyleSheet(),
        overlayContent = Y.one('#form_container'),
        overlay,
        slider,
        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({
        contentBox: overlayContent,
        width: '225px',
        align: { points: [ Y.WidgetPositionExt.TR, Y.WidgetPositionExt.TR ] },
        plugins: [ Y.Plugin.Drag ]
    }).render();
 
    // Slider needs a parent element to have the sam skin class for UI skinning
    overlayContent.addClass('yui-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 <div id="font_slider"></div> 36'),
        fontSizeInput);
 
    // 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({
        boundingBox: '#font_slider',
        railSize: '100px',
        thumbImage: Y.config.base + '/slider/assets/skins/sam/thumb-classic-x.png',
        min: 6,
        max: 36,
        value: parseInt(Y.one('body').getStyle('fontSize')) || 13,
        after: {
            valueChange: function (e) {
                var size = e.newVal + 'px';
 
                this.get('thumb').set('title', size);
                fontSizeInput.set('value', size);
 
                myStyleSheet.set('body', { fontSize: size });
            }
        }
    }).render();
 
    // 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.

  1. /* For supporting browsers, the overlay is rendered semi-transparent with
  2.  * fancy rounded corners */
  3. .yui-overlay {
  4. background: rgba(128,128,128,0.3);
  5. -moz-border-radius: 10px;
  6. -webkit-border-radius: 10px;
  7. border-radius: 10px;
  8. padding: 7px;
  9. cursor: move;
  10. }
  11.  
  12. .yui-overlay-content {
  13. background: rgba(205,205,205,0.3);
  14. -moz-border-radius: 10px;
  15. -webkit-border-radius: 10px;
  16. border-radius: 10px;
  17. padding: 1px;
  18. }
  19.  
  20. .yui-overlay form {
  21. background: #f2fbff url(gradient-promo.png) repeat-x scroll 0 0;
  22. border: 2px solid #fff;
  23. -moz-border-radius: 10px;
  24. -webkit-border-radius: 10px;
  25. border-radius: 10px;
  26. margin: 0;
  27. padding: 0;
  28. font-size: 13px;
  29. }
  30.  
  31. .yui-overlay fieldset {
  32. border: 1px solid #bcd;
  33. -moz-border-radius: 10px;
  34. -webkit-border-radius: 10px;
  35. border-radius: 10px;
  36. margin: 0;
  37. padding: 20px;
  38. }
  39.  
  40. .yui-overlay h3 {
  41. border-bottom: 2px solid #fff;
  42. color: #479;
  43. background: transparent;
  44. margin: 0;
  45. font-size: 175%;
  46. }
  47.  
  48. .yui-overlay label {
  49. display: block;
  50. margin: 1.3em 0 0.5ex;
  51. font-weight: bold;
  52. color: #003;
  53. }
  54.  
  55. .yui-overlay p {
  56. margin: 2em 0 0;
  57. }
  58.  
  59. /* override the move cursor for the Slider */
  60. .yui-overlay .yui-slider:hover {
  61. cursor: default;
  62. }
/* For supporting browsers, the overlay is rendered semi-transparent with
 * fancy rounded corners */
.yui-overlay {
    background: rgba(128,128,128,0.3);
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    padding: 7px;
    cursor: move;
}
 
.yui-overlay-content {
    background: rgba(205,205,205,0.3);
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    padding: 1px;
} 
 
.yui-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;
}
 
.yui-overlay fieldset {
    border: 1px solid #bcd;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    margin: 0;
    padding: 20px;
}
 
.yui-overlay h3 {
    border-bottom: 2px solid #fff;
    color: #479;
    background: transparent;
    margin: 0;
    font-size: 175%;
}
 
.yui-overlay label {
    display: block;
    margin: 1.3em 0 0.5ex;
    font-weight: bold;
    color: #003;
}
 
.yui-overlay p {
    margin: 2em 0 0;
}
 
/* override the move cursor for the Slider */
.yui-overlay .yui-slider:hover {
    cursor: default;
}

Copyright © 2009 Yahoo! Inc. All rights reserved.

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