Updating a Variable through a Mixin - css

So lets say I set the background of 10 elements on the page to #base, then a user lands on the "Foo" page which has the class on the body of the page.
How does one update the #base via a css declaration? I understand that variables are local to a function (or css declaration) but there must be a method to do this! (would make styling alternative pages so easy!)
#base: #00000;
body.foo{
#base = #FFF;
}

LESS is a Preprocessor so...
...it all has to be precompiled into CSS ahead of time. That means all possible class combinations need to be made into valid CSS ahead of time. If you wanted something like this, you would need to do something like the following in your LESS:
LESS
#base: #000000;
.setColorOptions(#className: ~'', #base: #base) {
#classDot: escape(`('#{className}' == '' ? '' : '.')`);
#class: escape(#className);
body#{classDot}#{class} {
someElement {color: #base;}
.someClass {color: #base;}
// etc.
}
}
.setColorOptions();
.setColorOptions(foo, #fff);
.setColorOptions(bar, #ccc);
CSS Output
body someElement {
color: #000000;
}
body .someClass {
color: #000000;
}
body.foo someElement {
color: #ffffff;
}
body.foo .someClass {
color: #ffffff;
}
body.bar someElement {
color: #cccccc;
}
body.bar .someClass {
color: #cccccc;
}
Obviously if there were many elements and a lot of color dependent things going on, this could get big fast. Imagine 100 elements under body with three color variations as above, and you have 300+ lines of CSS, 200+ (two-thirds) of which do not apply to any one page. And this doesn't account for other changes, like background colors, etc. In such a case, it is best to set up different LESS files that import a different set of values for #base and build different style sheets to be loaded on the pages that need it. However, if you are just doing a small subset of color changes to a page, this could be a valid way to go.

There is no way to do that.
LESS has no way to know whether the selector body.foo will apply at compile time.

Related

LESS mixins vs classes

I'm looking into LESS because I definitely see some of their benefits. For instance colour declaration.
One thing I don't understand tho, and maybe I'm not getting the flow right is - why use the following LESS snippet
.radius {
-webkit-border-radius:5px;
-moz-border-radius:5px;
border-radius:5px;
}
.btn-red{
background-color:red;
.radius;
}
.btn-green{
background-color:green;
.radius;
}
...
When we can use the .radius class in the html file right away. I'm left with the impression that LESS will add a ton of duplicate code once it gets compiled.
I'm using the following, which makes more sense. Same with font-size, margins, etc... Aren't classes used in such cases?
<div class="btn-red radius">Cancel</div>
<div class="btn-green radius">Go</div>
The snippet above does not benefit from SASS/LESS capabilities that much. Lets have a closer look and check this SCSS snippet.
// Abstract placeholder.
%radius {
border-radius: 5px;
}
// Put your global styling here.
// I'm assuming that you can alter the markup and have button.btn.btn-green
.btn {
// Color modifier.
&-red {
#extend %radius;
background-color: red;
}
&-green {
#extend %radius;
background-color: green;
}
}
The CSS output will be:
.btn-red, .btn-green {
border-radius: 5px;
}
.btn-red {
background-color: red;
}
.btn-green {
background-color: green;
}
And then you have to pick up Autoprefixer and vendor-prefixes issue is solved once and for all.
Because now, you can just specify the class btn_red or btn_green and all the buttons will automatically have a radius.
Your HTML should contain only the semantics, and styling or classes referring to styling should not be part of it.
That applies to the other classes as well. If for instance, you would rename btn_red to btn_cancel, you have a meaningful classname that you can apply to any kind of cancel button. And in the CSS you can specify that a cancel button is red and a 'Go' button is green, and both have a radius, without needing to modify the HTML at all.
So, the ultimate goal is to have the HTML describe the structure and the CSS describe how that structure should look. And a CSS preprocessor is only their to make a bulky spaghetti-like CSS file more structured.
There are several benefits.
You can use more semantic class names. Rather than encoding style information directly in your class names, (btn-red, radius) you could use a single class that conveys the usage of the style, rather than its contents.
You can avoid repeating yourself.
#radius-size: 5px;
-webkit-border-radius:#radius-size;
-moz-border-radius:#radius-size;
border-radius:#radius-size;
You can parameterize it so that you'd be able to use different radiuses (radii?) in different contexts.
.radius(#radius-size) { ... }
Because there are cases that developer has-no-access or don't-want to change the markup. and the only solution is to include all props from a predefined class.
for example:
you have bootstrap loaded (then you already have .has-success and .has-error classes) and if you want to use HTML5's native form validation using input's :valid and :invalid states, you have to use JavaScript to add/remove success/error classes based on input's states. but with this feature of LESS you can include all props of success/error class inside input's states. the code for this example could be something like this:
#myinput {
&:valid { .has-success; }
&:invalid { .has-error; }
}

LESS Declare variables using class names?

I have a button class that sets up padding etc for an element, followed by a class that defines a background colour.
.button {
padding: 0.5em 1em;
text-transform: uppercase;
color: #fff;
&.green {
background:#green; //declared previously
}
// ... more colours
}
Is it possible to declare the #green variable as the class name? This would save me having to copy/paste the &.green block for each colour I am wanting to use.
I've not been able to find anything the docs regarding this sort of selector, but something along the lines of:
&.(green|blue|red) {
background: #{$1};
}
which would generate the following:
.button.green{background:#00ff00;}
.button.blue{background:#0000ff;}
.button.red{background:#ff0000;}
You could achieve this by having a variable with the required list of colors, a loop to create the required rules and selector interpolation like shown below.
#colors: "green","blue","orange","red","yellow"; // the list of colors required
button {
padding: 0.5em 1em;
text-transform: uppercase;
.loop-colors(#index) when (#index > 0){ // loop to generate rules for each color
.loop-colors(#index - 1); // call for the next iteration
#color: e(extract(#colors, #index)); // pick the color value from the list one by one based on current index
&.#{color} {
background:#color;
}
}
.loop-colors(length(#colors));
}
Codepen Demo
Note: As mentioned in comments, LESS PHP is quite outdated and hence some of the new features offered by LESS (with respect to loops) are not supported by it. It could be overcome by doing the work-around mentioned in this answer.
You could also adopt an approach similar to the one mentioned by seven-phases-max in this answer (2nd option). That one achieves a similar effect without using loops.

less css variables with color name

I'm trying to create a few dynamics classes width Less css.
The idea is use in html this class:
.color-white{
color: white !important;
}
I created this sintaxis in Less:
.change-color(#which; #color){
.color-#{which}{
color:#color !important;
}
.background-#{which}{
background-color:#color !important;
}
}
So, with this I want to take my idea :D
.change-color(#which: white; #color: white);
But, that is the problem, I have this:
.color-#ffffff{
color:#fff!important
}
.background-#ffffff{
background-color:#fff!important
}
How can I use "white" as string and not as hex color.
Thanks.
Call this way instead:
.change-color(#which: ~'white'; #color: ~'white');
Though I think it would be better to just create a class called .color-red explicitly rather than make things more unreadable for little reason.

Dynamic Variable Names in LESS CSS

I have been trying this for a while, looking at other answers, but to no avail. Hopefully someone can help me.
I am trying to generate some dynamic variable names within a mixin.
The variables are already defined:
#horizontal-default-color: #fff;
#horizontal-inverse-color: #000;
etc..
The mixin I want would be something like this:
.horizontal-variant(#variant) {
color: #{horizontal-#{#variant}-color}
}
And the result I am expecting, when called:
.horizontal-default{
.horizontal-variant(~"default");
}
.horizontal-inverse{
.horizontal-variant(~"inverse");
}
is
.horizontal-default {color: #fff}
.horizontal-inverse {color: #000}
Unfortunately I run into errors every time.
I know this can be done, I have seen it being used in Font Awesome LESS where #{fa-css-prefix} is defined in variables. I am just having trouble transporting the same solution in my project.
You can try testing the code at http://lesstester.com/
You can use Variable Names. And I've tested the code at http://lesstester.com/, it works.
#horizontal-default-color: #fff;
#horizontal-inverse-color: #000;
.horizontal-variant(#variant) {
#color: "horizontal-#{variant}-color";
color: ##color;
}
.horizontal-default{
.horizontal-variant(default);
}
.horizontal-inverse{
.horizontal-variant(inverse);
}

Can I create Less color themes with variables that rely on other variables?

Does anyone know how to do what I am attempting to do here?
#theme (dark) {#primary: black;}
#theme (light) {#primary: white;}
#theme (#_) {#primary: yellow;}
#name: dark;
#theme(#name);
.rule {
color: #primary;
}
I am trying to define a few "themes" which will have colors and images (possibly) that will be used throughout the various Less files. I have made do in the past with defining them globally and commenting out those that are not in use, but I am trying to see if there are people who have found better strategies in Less than what I have.
I had at one point found a feature that used to be (?) a part of Less but it doesn't seem to work.
.theme {
#color: red;
}
.rule {
color: .theme > #color;
}
This would be great, if it worked.
After a bit of messing with LESSCSS, I've come up with a reasonable way to change all variables based on a single #theme variable.
The trick is to use variable interpolation to specify a variable reference to a variable.
//this can be either "dark" or "light"
#theme: dark;
#theme-primary: "#{theme}-primary"; //this will evaluate to "dark-primary"
#theme-secondary: "#{theme}-secondary"; //this will evaluate to "dark-secondary"
#dark-primary: #F00;
#dark-secondary: #000;
#light-primary: #333;
#light-secondary: #FFF;
body {
//#theme-secondary evaluates to "dark-secondary"
//#dark-secondary evalutates to #000
background-color: ##theme-secondary;
//#theme-primary evaluates to "dark-primary"
//#dark-primary evaluates to #F00
color: ##theme-primary;
}
Older version
While I don't know of an easy way to conditionally define variables, if you're going to change one word and change a color theme, you might as well change an import statement:
#import ’themes/dark.less’;
//#import ’themes/light.less’;

Resources