Skip to content

Instantly share code, notes, and snippets.

@potch
Last active June 30, 2018 16:56
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save potch/5141026 to your computer and use it in GitHub Desktop.
Save potch/5141026 to your computer and use it in GitHub Desktop.
JSON Style Sheets. Because why not.

JSS: JSON Style Sheets

“Wait, what?”

Sometimes you want to include some CSS in a JavaScript file. Maybe it's a standalone widget. A big ol' string is a pain to manage, and won't minify so pretty. Especially if you want your CSS safely namespaced. For example:

.widget {
    background: #abc123;
    width: 100px;
    /* ... */
}
.widget .doodad {
    background: #abc123;
    /* ... */
}
.widget .doodad:hover {
    background: red;
}
/* and so on */

Wouldn't it be neat if you could bundle up that CSS in a slightly more JS-friendly and compact way? And maybe get a hand with all that prefixing business?

“Actually, that doesn't really come up that often.”

But it does come up sometimes, right? JSS to the rescue!

“Fine, I'll bite. How do I write it?”

The JSS for the aforementioned widget would look like the following:

var style = {
    "&": "background: #abc123; width: 100px",
    ".doodad": {
        "&": "background: #abc123",
        "&:hover": "background: red"
    }
};

Next, we pass that object to the jss function with the parameter namespace:

var css = jss(style, '.widget');

Poof! css is the re-constituted style above! That's kind-of nifty. Drop that in a <style> and you're off to the races!

“Okay, that's kind of neat.”

But wait! There's more! Let's say we had some repeated values in the above (like our background color). If we write the JSS to look like this:

var style = {
    "&": "background: {bg}; width: 100px",
    ".doodad": {
        "&": "background: {bg}",
        "&:hover": "background: red"
    }
};

...we can now pass a third optional vars object to the jss function to do basic value replacement! It looks like this:

var css = jss(style, '.widget', { "bg": "#abc123" });

We can actually replace any arbitrary string in the style rules this way:

var style = {
    "&": "{bg}; width: 100px",
    ".doodad": {
        "&": "{bg}",
        "&:hover": "background: red"
    }
};

var css = jss(style, '.widget', { "bg": "background: #abc123" });

“I think this might be useful!”

Did I mention the jss inflater is 355 bytes minified?

“You truly are one of the great men of history.”

Aw, shucks. I do what I can.

No copyright intended.

// JSS - JSON Style Sheets. Use as directed.
function jss(o, namespace, vars) {
// Normalize optional parameters
namespace = namespace || '';
vars = vars || {};
var s = '';
// Regex used for variable interpolation.
var re = /\{([^}]+)\}/g;
for (sel in o) {
if (o.hasOwnProperty(sel)) {
var val = o[sel];
// Split on commas
var split = sel.split(/\s*,\s*/);
for (var i=0; i<split.length; i++) {
// child selector or chained selector?
var sub = split[i];
split[i] = namespace + (sub[0] === '&' ? '' + sub.substr(1) : ' ' + sub);
}
if (typeof val === 'object') {
// Recurse!
s += jss(val, split.join(','), vars);
} else {
// Substitute values from `vars`.
val = val.replace(re, function(_, m) {
return vars[m] || '';
});
// Write selector block
s += split.join(',') + '{' + val + '}';
}
}
}
return s;
}
@mythmon
Copy link

mythmon commented Mar 12, 2013

What's up with the spaces at the beginning of some of the selectors? Why not use '&' for the reference to the current selector, like in LESS and company?

Also, this is horrible. Good job.

@potch
Copy link
Author

potch commented Mar 12, 2013

I hated your suggestion so much that I implemented it. I hope you're happy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment