Skip to content

Instantly share code, notes, and snippets.

@miracle2k
Created January 14, 2012 20:14
Show Gist options
  • Save miracle2k/1612729 to your computer and use it in GitHub Desktop.
Save miracle2k/1612729 to your computer and use it in GitHub Desktop.
Optional variations in CSS
The idea is two provide optional variations for your stylesheet, for
presentation purposes, and have a switcher built into the page to
enable/disable them.
Usage - include the Javascript code in your page:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="cssoptions.js"></script>
Note that jQuery >= 1.7 is required.
This will search all stylesheets for rules that match "html.opt*". If you
are using Sass, you can generate these sort of rules with particular ease:
header
ul
width: auto
html.opt-full-width-nav &
width: 100%
Pressing F9 in the browser will then bring up a switcher window:
http://michael.elsdoerfer.name/cssoptions/cssoptions.png
An example using Sass to generate multiple color variations:
$color-options: purple #8E73C7, pink #C25377, black #292929, blue #4F67B8
@each $item in $color-options
html.opt-#{nth($item, 1)} &
border-color: darken(nth($item, 2), 10%)
(function($){
function prettifyName(s) {
s = s.replace(/[-_]/g, ' '); // remove separator syntax
s = s.replace(/([a-z])([A-Z])/g, '$1 $2'); // split words at capitalization changes
// capitalize
s = s.replace( /(^|\s)([a-z])/g , function(m,p1,p2){ return p1+p2.toUpperCase(); } );
return $.trim(s);
}
function getOptions() {
var options = {};
$.each(document.styleSheets, function(index, stylesheet) {
var classes;
try {
classes = stylesheet.rules || stylesheet.cssRules;
} catch(error) {
// Firefox may throw SecurityError for external stylesheets
return;
}
if (!classes) return;
for (var x=0; x<classes.length; x++) {
if (!classes[x].selectorText) continue;
var sel = classes[x].selectorText;
var re = /(?:^|, )html\.(opt([^ ]+))/g;
while (match = re.exec(sel)) {
if (!(match[1] in options))
options[match[1]] = prettifyName(match[2]);
}
}
});
return options;
}
/**
* "Combos" provide buttons to enable a set of options in one go.
* The syntax is: {mycombo: ['fullnav', 'white']}
*/
var _instanceCount = 0;
function OptionSwitcher(combos, keyCode) {
this.switcher = null;
this.combos = combos;
this.options = getOptions();
this.id = 'cssoptions' + _instanceCount++;
// Show it when a certain key is pressed
// http://www.webonweboff.com/tips/js/event_key_codes.aspx
var self = this;
$(document).on('keyup.'+this.id, function(e) {
if (e.keyCode == (keyCode || 120)) // F9 key
self.toggle();
});
}
OptionSwitcher.prototype._generate = function() {
// Generate HTML for the switcher
var html = '<div>';
$.each(this.options, function(clazz, name) {
html += '<input type="checkbox" name="'+clazz+'"><label title="'+clazz+'" for="'+clazz+'">'+name+'</label><br>';
});
// Add predefined combos
if (this.combos && !$.isEmptyObject(this.combos)) {
html += '<hr>';
for (var key in this.combos) {
html += '<button name="'+key+'">'+key+'</button><br>';
}
}
html += '</div>';
// Convert to DOM, append styles
this.switcher = switcher = $(html);
switcher.css('position', 'fixed');
switcher.css('left', '0px');
switcher.css('top', '0px');
switcher.css('margin', '0');
switcher.css('z-index', '99999');
switcher.css('height', 'auto');
switcher.css('border', '1px solid black');
switcher.css('background-color', 'white');
switcher.css('padding', '10px');
switcher.find('label').css('cursor', 'pointer');
var self = this;
// Make functional
switcher.find('input').change(function() {
var clazz = $(this).attr('name');
var isChecked = $(this).attr('checked');
isChecked ? $('html').addClass(clazz) : $('html').removeClass(clazz);
});
// Allow clicking on the label to select a single option
// and automatically deselect all others.
switcher.find('label').click(function() {
var clazz = $(this).attr('for');
var clickedOne = switcher.find('input[name='+clazz+']');
var currentlyChecked = clickedOne.is(':checked');
self.disableAll();
clickedOne.attr('checked', !currentlyChecked).change();
});
// Make the combo buttons work.
switcher.find('button').click(function() {
var clazz = $(this).attr('name');
self.disableAll();
for (var idx in self.combos[clazz]) {
var opt = self.combos[clazz][idx];
var control = switcher.find('input[name='+opt+']');
if (control.length)
control.attr('checked', true).change();
else
alert('Unknown option: '+opt);
}
});
// Append to document, hidden
switcher.hide();
$('body').append(switcher);
}
/**
* Disable all options.
*/
OptionSwitcher.prototype.disableAll = function() {
this.switcher.find('input').attr('checked', false).change();
}
/**
* Show/hide the switcher.
*/
OptionSwitcher.prototype.show = function() {
if (!this.switcher)
this._generate();
this.switcher.show();
}
OptionSwitcher.prototype.hide = function() {
if (this.switcher)
this.switcher.hide();
}
OptionSwitcher.prototype.toggle = function() {
if (this.switcher && this.switcher.is(':visible'))
this.hide();
else
this.show();
}
/**
* Remove the switcher from the page.
*/
OptionSwitcher.prototype.remove = function() {
if (this.switcher)
this.switcher.remove();
$(document).off('keyup.'+this.id);
}
var GLOBAL_SWITCHER = false;
window.generateOptionSwitcher = function(combos, keyCode) {
if (GLOBAL_SWITCHER) {
GLOBAL_SWITCHER.remove();
GLOBAL_SWITCHER = undefined;
}
return new OptionSwitcher(combos, keyCode);
}
$(function() {
GLOBAL_SWITCHER = generateOptionSwitcher();
});
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment