Skip to content

Instantly share code, notes, and snippets.

@sammoore
Last active December 10, 2016 21:37
Show Gist options
  • Save sammoore/222023066b91db73cd0b0010efb21109 to your computer and use it in GitHub Desktop.
Save sammoore/222023066b91db73cd0b0010efb21109 to your computer and use it in GitHub Desktop.
Inject CSS properties on the current page based on pre-existing CSS. Tested with jQuery 1.12 for compatibility. Uses browser globals; no support for CommonJS/AMD.
/* Example usage; adds `#menu.hidden { left: -currentValue; }` to <head> in a <script>.
var sel = '#menu';
var source = { selector: sel, prop: 'width' };
var mapWidth = (function (value) { return "-" + value; });
var destination = { selector: sel + '.hidden', prop: 'left', mapping: mapWidth };
var injector = new CSSInjector('menu-css', source, [destination]);
injector.inject('head');
*/
(function ($) {
function CSSInjector(styleId, source, destinations) {
if (! this instanceof CSSInjector) {
return new CSSInjector(styleId, source, destinations);
}
function verifyDescriptor(argTitle, desc) {
['selector', 'prop'].forEach(function (key) {
if (typeof (desc || {})[key] !== 'string') {
var err = 'CSSInjector requires ' + argTitle + ' to contain a string value for ' + key;
throw new TypeError(err);
}
});
}
verifyDescriptor('source', source);
destinations.forEach(
verifyDescriptor.bind(null, "each destination")
);
this.styleId = styleId;
this.source = source;
this.destinations = destinations;
};
CSSInjector.prototype.inject = function (target) {
var css = generateCSS(this.source, this.destinations);
var el = document.getElementById(this.styleId);
if (!el) {
el = document.createElement('style');
el.rel = 'stylesheet';
} else {
$(el).detach();
}
el.innerHTML = css;
$(target).append(el);
};
function generateCSS(source, destinations) {
var sourceValue = $(source.selector).css(source.prop);
var reducer = function (css, destination) {
function identity(a) { return a; };
destination.mapping = destination.mapping ? destination.mapping : identity;
var innerCSS = destination.prop + ": " + destination.mapping(sourceValue) + ";";
var outerCSS = destination.selector + " { " + innerCSS + " }";
return css + outerCSS;
};
return destinations.reduce(reducer, "");
}
this.CSSInjector = CSSInjector;
}.call(this, jQuery));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment