Sometimes I'm forced to add CSS styles to the DOM programmatically (if you need a reason: imagine writing a small ui widget that comes with its own styling but is supposed to only consist of one single *.js file for easier handling). In this case I prefer defining the style in my script code with object notation instead of one large string that mixes rules, properties, and markup.
var thumbHoverStyle = {
"background-color": "rgba(211, 211, 211, 0.5)",
"cursor": "pointer"
};
versus
var thumbHoverStyle = "<style> .thumb:hover { background-color: rgba(211, 211, 211, 0.5); cursor: pointer; } </style>";
Such a css-object can easily be used with JQuery's .css() function, but the trouble starts as soon as I want to style a css pseudo-class (in my example :hover). In this case I can't use the JQuery .css()
function and I fall back to inserting a corresponding style tag into my DOM.
var thumbHoverStyleTag = toStyleTag( { ".thumb:hover": thumbHoverStyle } );
_root.append(thumbHoverStyleTag);
I googled and stackoverflowed but could not find a utility function that converts my css-object into a style tag. In the end I wrote my own function (and I will probably provide it as an answer to this question), but I still want to know if there is a library function for this. What is the most elegant method to accomplish this?
Edit
My implementation in TypeScript:
function appendPxIfNumber(value: any): string
{
return (typeof value === "number") ? "" + value + "px" : value;
}
function toStyleTag(rulesObj: any)
{
var combinedRules: string = "";
for (var selector in rulesObj)
{
var cssObject = rulesObj[selector];
var combinedProperties = "";
for (var prop in cssObject) {
var value = cssObject[prop];
combinedProperties += `${prop}: ${appendPxIfNumber(value)};` + "\n";
}
combinedRules += ` ${selector} {${combinedProperties}}` + "\n";
}
return $(`<style>${combinedRules}</style>`);
}
Usage example:
var styleTag = toStyleTag( { ".thumb": thumbStyle, ".thumb:hover": thumbHoverStyle } );
Here's a working example which works with the origin style object:
I'll convert the JSON
into CSS
. and define a target which should be styled Keep in mind there is no selector which should be styled... So I added a targetSelector
.
var targetSelector='.thumb:hover',
styleObj = {
"background-color": "rgba(211, 211, 211, 0.5)",
"cursor": "pointer"
},
// Convert the JSON into CSS
styleTagContent = JSON.stringify(styleObj,null,'\t')
.replace(/"/g,'')
.replace(/,\n/g,';')
.replace(/\}/g, ';}')
$('<style>'+targetSelector+styleTagContent+'</style>').appendTo('head');
Here's a working Plunk to see how it works.
The methodology behind my function toStyleTag()
is that it first iterates over styleTag
using a for...in statement and checking if styleTag
hasOwnProperty() of the selector
. I then reduce() the array returned by executing Object.keys() on the object, styleTag[selector]
, which I concat() the accumulator
by joining the currentValue
(the property) and the styleTag[selector][currentValue]]
(the rule) to be :
separated. Doing so lets styles
become an array of strings that are in the form of property: rule
. This is now the format we need to use insertRule(), which we use this to insert the new CSS rule into the current style sheet. Notice that I am grabbing length of the cssRules
to find the index + 1, so that we can insert this new rule at the very end of our style sheet to ensure it is not overwritten.
var styleSheet = document.styleSheets[0];
function toStyleTag(styleTag) {
for(var selector in styleTag) {
if(styleTag.hasOwnProperty(selector)) {
let styles = Object.keys(styleTag[selector]).reduce(function(accumulator, currentValue) {
return accumulator.concat([currentValue, styleTag[selector][currentValue]].join(':'));
}, []);
styleSheet.insertRule(selector + '{' + styles.join(';') + '}', styleSheet.cssRules.length);
}
}
}
var thumbHoverStyle = {
'background-color': 'rgba(211, 211, 211, 0.5)',
'cursor': 'pointer'
};
toStyleTag({ '.thumb:hover': thumbHoverStyle });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="thumb">
<img src="http://placehold.it/350x350">
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With