Posted By

dom111 on 05/01/09


Tagged

css javascript nested


Versions (?)

Who likes this?

1 person have marked this snippet as a favorite

necmettin


JSS 0.1 - Nested CSS using Javascript


 / Published in: JavaScript
 

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

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.

  1. /**
  2.  * JSS
  3.  *
  4.  * Nested CSS via JavaScript
  5.  **/
  6. var JSS = function(o, options) {
  7. // set up the base options
  8. this.options = {
  9. minified: true,
  10. apply: true
  11. }
  12.  
  13. // set up the data hash
  14. this.data = {};
  15.  
  16. // m()
  17. //
  18. // Merges properties of s into o and returns o
  19. //
  20. this.m = function(o, s) {
  21. for (var p in s) {
  22. o[p] = s[p];
  23. }
  24.  
  25. return o;
  26. }
  27.  
  28. // parse()
  29. //
  30. // Parses the object o and stores the information in this.data{}
  31. //
  32. this.parse = function(o, p) {
  33. if (typeof o != 'object') {
  34. throw new Error('CSS::parse: No valid CSS object passed.');
  35. }
  36.  
  37. if (!p) {
  38. p = '';
  39. }
  40.  
  41. for (var prop in o) {
  42. if (typeof o[prop] == 'object') {
  43. var rule = getPrefix(p) + prop;
  44. if (!this.data[rule]) {
  45. this.data[rule] = [];
  46. }
  47.  
  48. this.parse(o[prop], this.getPrefix(p) + prop);
  49.  
  50. } else {
  51. this.data[p][this.data[p].length] = (this.options.minified) ? prop + ':' + this.minify(o[prop]) + ';' : ' ' + prop + ': ' + o[prop] + ';\n';
  52. }
  53. }
  54. }
  55.  
  56. // build()
  57. //
  58. // Builds the information stored in this.data{} into valid CSS text
  59. //
  60. this.build = function() {
  61. var css = '';
  62.  
  63. for (var rule in this.data) {
  64. if (this.data[rule] != []) {
  65. css += (this.options.minified) ? rule + '{' : rule + ' {\n';
  66.  
  67. css += this.data[rule].join('');
  68.  
  69. css += (this.options.minified) ? '}' : '}\n\n';
  70. }
  71. }
  72.  
  73. return css;
  74. }
  75.  
  76. // getPrefix()
  77. //
  78. // Shortcut to return the prefix for stacking
  79. //
  80. this.getPrefix = function(p) {
  81. if (p) {
  82. return p + ' ';
  83.  
  84. } else {
  85. return '';
  86. }
  87. }
  88.  
  89. // minify()
  90. //
  91. // Minifies the string passed
  92. //
  93. this.minify = function(s) {
  94. // html/css colour names that can be replaced by shorter hex codes
  95. var colours = [
  96. [
  97. /black/,
  98. '#000'
  99. ],
  100. [
  101. /white/,
  102. '#fff'
  103. ],
  104. [
  105. /fuchsia/,
  106. '#f0f'
  107. ],
  108. [
  109. /yellow/,
  110. '#ff0'
  111. ]
  112. ];
  113.  
  114. // loop through taking out any long colour names
  115. for (var i = colours.length - 1; i >= 0; i--){
  116. s = s.replace(colours[i][0], colours[i][1]);
  117. }
  118.  
  119. // if we've got any 6 char hex codes
  120. if (s.match(/#[0-9a-f]{6}/)) {
  121. // see if we can shrink them
  122. var matches = s.match(/#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])/);
  123.  
  124. if ((matches[1] == matches[2]) && (matches[3] == matches[4]) && (matches[5] == matches[6])) {
  125. s = s.replace(matches[0], '#' + matches[1] + matches[3] + matches[5]);
  126. }
  127. }
  128.  
  129. return s;
  130. }
  131.  
  132. // addToPage()
  133. //
  134. // Applies the generated stylesheet to the page
  135. //
  136. this.addToPage = function(s) {
  137. // create a style element
  138. var style = document.createElement('style');
  139. // set it to a text/css block
  140. style.setAttribute('type', 'text/css');
  141.  
  142. // append the style to the body
  143. if (style.styleSheet) {
  144. // in IE
  145. style.styleSheet.cssText = s;
  146.  
  147. } else {
  148. // in the other browsers
  149. style.appendChild(document.createTextNode(s));
  150. }
  151.  
  152. // put it in the document
  153. document.getElementsByTagName('head')[0].appendChild(style);
  154. }
  155.  
  156. // set the options
  157. this.options = this.m(this.options, options || {});
  158.  
  159. // start parsing the object
  160. this.parse(o);
  161.  
  162. if (this.options.apply) {
  163. // if we're supposed to apply the stylesheet, do it!
  164. this.addToPage(this.build());
  165.  
  166. } else {
  167. // just return the text
  168. return this.build();
  169. }
  170. }

Report this snippet  

You need to login to post a comment.