Return to Snippet

Revision: 13664
at May 1, 2009 11:30 by dom111


Initial Code
/** 
 * JSS
 * 
 * Nested CSS via JavaScript
 **/
var JSS = function(o, options) {
  // set up the base options
  this.options = {
    minified: true,
    apply: true
  }
  
  // set up the data hash
  this.data = {};
  
  // m()
  // 
  // Merges properties of s into o and returns o
  // 
  this.m = function(o, s) {
    for (var p in s) {
      o[p] = s[p];
    }
    
    return o;
  }
  
  // parse()
  // 
  // Parses the object o and stores the information in this.data{}
  // 
  this.parse = function(o, p) {
    if (typeof o != 'object') {
      throw new Error('CSS::parse: No valid CSS object passed.');
    }
    
    if (!p) {
      p = '';
    }
    
    for (var prop in o) {
      if (typeof o[prop] == 'object') {
        var rule = getPrefix(p) + prop;
        if (!this.data[rule]) {
          this.data[rule] = [];
        }

        this.parse(o[prop], this.getPrefix(p) + prop);

      } else {
        this.data[p][this.data[p].length] = (this.options.minified) ? prop + ':' + this.minify(o[prop]) + ';' : '  ' + prop + ': ' + o[prop] + ';\n';
      }
    }
  }
  
  // build()
  // 
  // Builds the information stored in this.data{} into valid CSS text
  // 
  this.build = function() {
    var css = '';
    
    for (var rule in this.data) {
      if (this.data[rule] != []) {
        css += (this.options.minified) ? rule + '{' : rule + ' {\n';

        css += this.data[rule].join('');

        css += (this.options.minified) ? '}' : '}\n\n';
      }
    }

    return css;
  }
  
  // getPrefix()
  // 
  // Shortcut to return the prefix for stacking
  // 
  this.getPrefix = function(p) {
    if (p) {
      return p + ' ';

    } else {
      return '';
    }
  }
  
  // minify()
  // 
  // Minifies the string passed
  // 
  this.minify = function(s) {
    // html/css colour names that can be replaced by shorter hex codes
    var colours = [
      [
        /black/,
        '#000'
      ],
      [
        /white/,
        '#fff'
      ],
      [
        /fuchsia/,
        '#f0f'
      ],
      [
        /yellow/,
        '#ff0'
      ]
    ];
    
    // loop through taking out any long colour names
    for (var i = colours.length - 1; i >= 0; i--){
      s = s.replace(colours[i][0], colours[i][1]);
    }
    
    // if we've got any 6 char hex codes
    if (s.match(/#[0-9a-f]{6}/)) {
      // see if we can shrink them
      var matches = s.match(/#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])/);
      
      if ((matches[1] == matches[2]) && (matches[3] == matches[4]) && (matches[5] == matches[6])) {
        s = s.replace(matches[0], '#' + matches[1] + matches[3] + matches[5]);
      }
    }
    
    return s;
  }
  
  // addToPage()
  // 
  // Applies the generated stylesheet to the page
  // 
  this.addToPage = function(s) {
    // create a style element
    var style = document.createElement('style');
    // set it to a text/css block
    style.setAttribute('type', 'text/css');

    // append the style to the body
    if (style.styleSheet) {
      // in IE
      style.styleSheet.cssText = s;

    } else {
      // in the other browsers
      style.appendChild(document.createTextNode(s));
    }

    // put it in the document
    document.getElementsByTagName('head')[0].appendChild(style);
  }
  
  // set the options
  this.options = this.m(this.options, options || {});
  
  // start parsing the object
  this.parse(o);
  
  if (this.options.apply) {
    // if we're supposed to apply the stylesheet, do it!
    this.addToPage(this.build());
    
  } else {
    // just return the text
    return this.build();
  }
}

Initial URL
http://www.dom111.co.uk/blog/coding/jss-nested-css-using-javascript/94

Initial Description
Ever wanted nested stylesheets?

I have!

Now you can have them! If you code your stylesheets as JSON and parse them using JSS 0.1. You could have the following:

      JSS({
        'html': {
          'body': {
            background: '#fff',
 
            'div#header': {
              height: '100px',
              background: '#00f'
            },
 
            'div#footer': {
              height: '40px',
 
              'span#copyright': {
                color: '#0f0'
              },
              'span#testing': {
                color: 'black',
                background: '#eeccff'
              }
            }
          },
          width: '800px'
        }
      });
Turned into:

      html {
        width: 800px;
      }
 
      html body {
        background: #fff;
      }
 
      html body div#header {
        height: 100px;
        background: #00f;
      }
 
      html body div#footer {
        height: 40px;
      }
 
      html body div#footer span#copyright {
        color: #0f0;
      }
 
      html body div#footer span#testing {
        color: black;
        background: #eeccff;
      }

Check out the blog post for a demo and a zip file containing the demo, full version and minified version.

Initial Title
JSS 0.1 - Nested CSS using Javascript

Initial Tags
css, javascript

Initial Language
JavaScript