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.
<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
<script src="../../build/yui/yui-min.js"></script>
<script>
// 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,
alignOn: [],
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.one('#theme_form input[type=submit]').remove();
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);
}
});
</script>
CSS
This is the CSS added to the page to skin the Overlay and its content.
<style>
/* 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(../assets/stylesheet/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 #cde;
-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;
}
</style>