Dynamically set a CSS property based on a template value
Answering my own question: The template needed to be expanded (from {{> projects}}
) to allow for conditional rendering.
<div class="board">
<div class="header">
<span class="name">Project</span>
<span class="status">Status</span>
</div>
{{#each projects}}
<div class="project">
<span class="name">{{name}}</span>
<span class="status" style="color:{{getStatusColor status}}">{{status}}</span>
</div>
{{/each}}
</div>
For completeness, the helper function getStatusColor looks like this:
Handlebars.registerHelper('getStatusColor', function(status) {
switch (status) {
case "GOOD" : {
return 'green';
}
break;
case "BAD" : {
return 'red';
}
break;
default : {
...etc.;
}
});
UPDATE:
In the interests of honesty, I should confess I totally missed that I already had this expanded template in my code and that {{> projects}}
was pointing to this. I should have just added the style="color:{{getStatusColor status}}"
attribute directly into the referenced project
template. So, as much for my benefit as others, the final, working, HTML:
<template name="foo">
<div class="board">
<div class="header">
<span class="name">Project</span>
<span class="status">Status</span>
</div>
{{#each projects}}
{{> project}}
{{/each}}
</div>
</template>
<template name="project">
<div class="project {{selected}}">
<span class="name">{{name}}</span>
<span class="status"style="color:{{getStatusColor status}}">{{status}}</span>
</div>
</template>
Generate dynamic css based on variables angular
Direct approach available in angular is using ngstyle as follows
<div [ngStyle]="{'color': style.colorVal ? style.colorVal : '#000', 'font-size' : style.fontSize ? style.fontSize : '16px' }"></div>
After going through different methods and approached to add dynamic css to all pages on angular app I ended up with following solutions.
Requirement : generate dynamic css based on values returned from and API to change design and styling.
Solution :
- create a new component and create a service to load dynamic css variables from API.
- Add style tag in template file and use variable values for properties.
- Load this template on all pages or on main template.
- On app build style will be moved to head tag.
Code sample
import { CssService} from './Css.service';
@Component({
selector: 'DynamicCss',
templateUrl: './DynamicCss.component.html',
styleUrls: ['./DynamicCss.component.scss']
})
export class ServiceProviderComponent implements OnInit {
cssVariables: any;
constructor(private cssService:CssService){
/* call the service/api to get the css variable values in cssVariables */
}
}
Now apply css using jquery or javascript to append css with help of function like following
appendCss(customData)
{
let text = '.custom-form-1 {
background-image: url("`+customData.background_image+`");
}';
$(document).ready(function(){
$("style").append(text);
});
}
and call this function after loading custom data from service or other variable like I did it ngOnInit
ngOnInit(){
this.appendCss(this.customizeFormData);
}
Its using jquery but can be done with javascript/typescript as well if you dont want to use jquery in your angular app
Other useful resource https://github.com/angular/angular/issues/9343#issuecomment-312035896
How to define css selector properties dynamically?
- Create a dynamic
style
in your top-most element in your template. - Assign the backend response of your properties to a computed function.
- Set style lang to
lang='scss'
then use CSS varialbe functionvar()
to set the values.
Example
<template>
<div :style="cssProps">
<div class="some-style">
Hello Mars
</div>
</div>
</template>
<script>
export default {
computed: {
cssProps() {
// backend response with your css values
let backendResponseObject = {
fontColor: "black", // you can use rgb or hex
backgroundColor: "White" // you can use rgb or hex
}
properties = {
"--brand-base": backendResponseObject.color,
"--brand-primary": backgroundColor.hex,
};
return properties;
}
}
}
</script>
<style lang="scss">
.some-style {
color: var(--brand-base);
background: var(--brand-primary);
}
</style>
Generate css dynamically via templates and placeholders
Wound up playing with this and CSS variables. I'm adding a second answer because it's very different method from my first answer and it better aligns with your original question (updating CSS variables with JS).
BUT... don't do this. :) Browser support in IE < Edge doesn't exist and it is almost certainly slower than updating an on-page <style>
element though I haven't tested it. This jsperf tests various style update methods. It doesn't include innerHTML
on a single style
element (likely the fastest) but you can see that the following CSS DOM methods are slower than the rest.
// get the stylesheet// array position depends on how many style sheets you're loading. // adjust as needed.var sheet = document.styleSheets[0];
// simplest method: insertRule()// setTimeout only for demo so you can see the changewindow.setTimeout(function(){ // @media all {} is a trick to insert more than one // selector and/or properties at once. Otherwise it's: // sheet.insertRule(":root", "--header-color: green"); ...repeat... sheet.insertRule("@media all { :root { --header-color: green; --main-color: orange; } }", 1);}, 1200);
// SAFER method via addCSSRule. // button and getAjaxStyles are just placeholders, obviouslyvar btn = document.querySelector('button');btn.addEventListener("click", getAjaxStyles);
function getAjaxStyles() { // success callback... break apart the json and update the CSS variables addCSSRule(sheet, ":root", "--header-color: orange"); addCSSRule(sheet, ":root", "--main-color: blue"); addCSSRule(sheet, ":root", "--alt-color: red"); addCSSRule(sheet, ":root", "--borderColorA: lavender"); // or go with a single big string. definitely faster: // addCSSRule(sheet, ":root", "--alt-color: red; --borderColorA: #0ff; ")}
// Credit for addCSSRule() goes to Diego Flórez in a comment on // https://davidwalsh.name/add-rules-stylesheetsvar addCSSRule = function(sheet, selector, rules) { //Backward searching of the selector matching cssRules var index = sheet.cssRules.length - 1; for (var i = index; i > 0; i--) { var current_style = sheet.cssRules[i]; if (current_style.selectorText === selector) { //Append the new rules to the current content of the cssRule; rules = current_style.style.cssText + rules; sheet.deleteRule(i); index = i; } } if (sheet.insertRule) { sheet.insertRule(selector + "{" + rules + "}", index); } else { sheet.addRule(selector, rules, index); } return sheet.cssRules[index].cssText;}
/* Set initial CSS variables */:root { --header-color: #333; --main-color: #888; --alt-color: #bbb; --borderColorA: #ccc;}h1 { color: var(--header-color);}p { border-bottom: 1px solid var(--borderColorA); color: var(--main-color);}p+p { color: var(--alt-color);}
<h1>header</h1><p>paragraph 1</p><p>paragraph 2</p><button>Update CSS Variables</button>
Dynamically setting value of `grid-template-columns` css property
If you follow the steps of the specification you see
setProperty
5. Let component value list be the result of parsing value for property property.
then
parsing
1.Let list be the value returned by invoking parse a list of component values from value.
then
parse a list of component values
1. Repeatedly consume a component value until an is returned, appending the returned values (except the final ) into a list. Return the list.
almost there
consume a component value
Otherwise, if the current input token is a <function-token>, consume a function and return it.
and finally
consume a function
Create a function with a name equal to the value of the current input token, and with a value which is initially an empty list.
Repeatedly consume the next input token and process it as follows:
<)-token>
Return the function.
<EOF-token> This is a parse error. Return the function.
anything else
Reconsume the current input token. Consume a component value and append the returned value to the function’s value.
in short, when it is a function it gets executed and its result is assigned.
How to dynamically set and modify CSS in JavaScript?
If I understand your question properly, it sounds like you're trying to set placeholder text in your css file, and then use javascript to parse out the text with the css value you want to set for that class. You can't do that in the way you're trying to do it. In order to do that, you'd have to grab the content of the CSS file out of the dom, manipulate the text, and then save it back to the DOM. But that's a really overly-complicated way to go about doing something that...
myElement.style.width = "400px";
...can do for you in a couple of seconds. I know it doesn't really address the issue of decoupling css from js, but there's not really a whole lot you can do about that. You're trying to set css dynamically, after all.
Depending on what you're trying to accomplish, you might want to try defining multiple classes and just changing the className property in your js.
Related Topics
Web Testing for Ie. How Accurate Is Ietester
Rails Asset Pipeline Solution for Ie 4096 Selector/Stylesheet Limit
How to Create a Box When Mouse Over Text in Pure CSS
How to Get a Three Column Layout with Twitter Bootstrap
Custom Svg Admin Menu Icon in Wordpress
Angular2: How to Manually Add CSS Files by Condition to Index.Html
How to Override "::-Webkit-Scrollbar" CSS Rule and Make Scrollbar Visible Again
CSS :Root Variables and SASS Functions
Viewport Units, Keeping Aspect Ratio
CSS Animate Circle Border Filling with Color
Easiest Way to Have a Bootstrap Layout Where the Burger Menu Is Always Visible
Is There User-Select for Opera 10.62 and IE9
How to Maintain Png Alpha Transparency When Using "-Ms-Filter" Property
Using Grunt Grunt-Contrib-Less) for Compiling Bootstrap 3.1 Less in Visual Studio 2013
Getting Inline-Block Element's Height to Fill the Parent
Set Color for Extra Page Parts Visible During Rubber Band Scroll