Dynamic CSS Properties in Less

Dynamic CSS properties in LESS?

Below is the solution that lets you write your styles once using LESS, then compile them to be two different css stylesheets for both rtl, and ltr layouts.

basically we'll have three LESS files (they can be more!):

style-ltr.less  // this where we hold the rtl variables
style-rtl.less // rtl variables
main.less // here we'll write our styles

in style-ltr.less define the following variables:

@left: left;
@right: right;

@import "main.less";

while in style-rtl.less they will have the following values:

// reflect variables
@left: right;
@right: left;

@import "main.less";

now in main.less, we'll define the following mixins

.left(@distance) when (@left = left) {
left: @distance;
}
.left(@distance) when (@left = right) {
right: @distance;
}
.right(@distance) when (@right = right) {
right: @distance;
}
.right(@distance) when (@right = left) {
left: @distance;
}

// now we can style our elements using these mixins
div.something {
position: relative;
.left(10px);
float: @left;
}

now all we have to do is to include style-rtl.less in rtl pages include (or the compiled css version),
as well to include style-ltr.less in ltr pages, and div.something will be floated to the left on ltr pages, while it will be floated to the right on the rtl pages

Note that you can define padding, margin, border-radius ...etc. using the same way here.

UPDATE

I created two projects on github to help building a bi-directional applications

  • bi-app-less
  • bi-app-sass

Credits:

inspired by my dear friend Victor Zamfir

Best approach for dynamic properties in LESS compiled css

If you have preset color options, one possible method is to add a data- attribute to the body tag with the name of the preset color theme. Then use LESS to automatically generate the styles for all the color combinations.

The attribute is the only part that gets dynamically changed:

<body data-theme="blue">

In the LESS, first define your colors:

@theme-red:    #f00;
@theme-orange: #ffa500;
@theme-green: #080;
@theme-blue: #00f;
@theme-purple: #800080;
@theme-pink: #ff69b4;

Then create an array of the theme names so you can loop through the options. Make sure the strings match the color variable names above:

@theme-options: 'red', 'orange', 'green', 'blue', 'purple', 'pink';
@theme-count: length(@theme-options);

Then create a mixin that is used to generate the styles for all themes.

Note that there is a default option supplied in case there is no valid data-theme attribute. This way you can have one of your colors be the default and/or you can define other default styles easily. This part isn't totally necessary if you are already defining default styles, but I found it useful, so I included it just in case it can help you:

.theme-color (@property, @default: @theme-blue) {
& { @{property}: @default; }
.loop-themes();
}

.loop-themes (@i: @theme-count) when (@i > 0) {
.loop-themes((@i - 1));
@color: extract(@theme-options, @i);
@theme-var: 'theme-@{color}';

body[data-theme=@{color}] & { @{property}: @@theme-var; }
}

Anywhere in the rest of your CSS that you are defining a "dynamic" style, just use the mixin like this when you want to use the preset default:

a {
.theme-color(background-color);
}

... and like this when you want to use a custom value for the default:

a {
.theme-color(background-color, #000);
}

Of course, the one downside to this is that all of your styles for all the colors are loaded no matter which theme you're using, but it's up to you to decide if it's worth it or not.

Create dynamic less mixin setting property names

LESS does not currently support dynamic CSS properties. This lack of support for dynamic properties is one point of criticism which some argue is an advantage of SASS over LESS. There do exist pull requests on certain libraries (eg, less.js) which add this capability.

Otherwise, you are pretty much stuck doing what you didn't want to do, namely:

.margin (@px,@side,@abbr) when (@side = left) {
(~".m@{abbr}@{px}") { margin-left: ~"@{px}px"; }
}
.margin (@px,@side,@abbr) when (@side = right) {
(~".m@{abbr}@{px}") { margin-right: ~"@{px}px"; }
}

Can you use a variable as the CSS Property and Value with LESS?

Simple answer is not yet.

But seems like it might be soon (in the next LESS release perhaps). See this thread https://github.com/less/less.js/issues/36 and it seems like @seven-phases-max is working on it at the moment (see here)

So only a tiny bit more patience =)

Here I posted a possible workaround a while ago:

  • Using variables in property names in LESS (dynamic properties / property name interpolation) (a bit hacky but it works, while waiting for the official release of property interpolation in LESS)

Update:

As of LESS 1.6 (changelog) property name interpolation is possible.

Your mixin would look like this in LESS:

.browserPrefix(@property; @value){
-webkit-@{property}: @value;
-moz-@{property}: @value;
-ms-@{property}: @value;
-o-@{property}: @value;
@{property}: @value;
}

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 :

  1. create a new component and create a service to load dynamic css variables from API.
  2. Add style tag in template file and use variable values for properties.
  3. Load this template on all pages or on main template.
  4. 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

less css calling dynamic variables from a loop

I have just been trying todo the same thing today with LESS. The solution I came up with is to use a Parametric Mixin to create (define) the variable, see updated exmaple:

@color1:#06A1C0;
@color2:#8F4F9F;
@color3:#ED1D24;
@color4:#5A9283;
@color5:#B38C51;
@color6:#EC008C;
@color7:#8F4F9F;

@iterations: 7;

.define(@var) {
@colorSet: 'color@{var}';
}

.mixin-loop (@index) when (@index > 0) {
color@{index}:hover{
.define(@index);
color: @@colorSet;
}

.mixin-loop(@index - 1);
}
.mixin-loop (0) {}
.mixin-loop(@iterations);

Hope this helps.

How have dynamic class names in LESS CSS and use them as values in function

You have to create a list of colors first before creating a loop:

.make-classes(@prefix, @list) {
.iter(length(@list));
.iter(@i) when (@i > 0) {
.iter(@i - 1);
@pair: extract(@list, @i);
@key: extract(@pair, 1);
@value: extract(@pair, 2);
.@{prefix}.color-@{key} {
color: @value;
}
}
}

@colors:
~'blue' #7FB3D4,
~'gray' #767676,
~'green' #8CC079,
~'red' #b35d5d;

.make-classes(link, @colors);

Output:

.link.color-blue {
color: #7fb3d4;
}
.link.color-gray {
color: #767676;
}
.link.color-green {
color: #8cc079;
}
.link.color-red {
color: #b35d5d;
}


Related Topics



Leave a reply



Submit