Using a variable name as a function in LESS - less

Using LESS, is it possible to have a 'variable' function name? Say, for example, I have many elements that use the darken function, but I want (in another use instance of the same stylesheet) to use the lighten function. Is it possible to have the functions themselves defined as a single variable? Like one can in PHP?
For example
.element1 {color: darken(#color1, #percent);}
.element2 {color: darken(#color2, #percent);}
.element3 {color: darken(#color3, #percent);}
to become
.element1 {color: lighten(#color1, #percent);}
.element2 {color: lighten(#color2, #percent);}
.element3 {color: lighten(#color3, #percent);}
with the change of a single line of code?

You could use mix-ins as functions if you declare you're mix-in as follows...
.adjustLight(#c, #p){
color: darken(#c, #p);
}
and that mixing can be used as you'd expect...
.element1 {.adjustLight(#color1, #percent);}
.element2 {.adjustLight(#color2, #percent);}
.element3 {.adjustLight(#color3, #percent);}
This will allow you to change the adjustLight mixin without affecting the rest of your css declarations. There are good examples in the online documentation about Parametric Mixins and Mixins as functions

Related

How to use the default variable for only one of a few variables in less

Here is my mixin
.test(#color:black; #width:100px; #height:50px) {
width:#width;
height:#height;
background:#color;
}
Here is where it's called later
.mydiv {.test('use-mixin-color'; 300px; 150px);}
How can I override the size of .mydiv, while using the color defined in the mixin?
Everything I have tried overrides the mixin color.
To Use mixin in LESS, pass those parameter to override mixin default value :
Soluations :
.test(#color:black; #width:100px; #height:50px) {
width : #width;
height : #height;
background : #color;
}
.mydiv {
.test(#width : 300px; #height : 150px);
}
OUTPUT :
.mydiv {
width: 300px;
height: 150px;
background: black;
}
Helpful :)
In addition to the accepted answer. There're multiple methods (actually infinite) but if you want your mixin to be most easy for use you can provide a "specialization" for a specific argument value or number of arguments. Like this for example:
// usage:
.foo {.test(red, 1px, 2px)}
.bar {.test(3px, 4px)}
// impl.:
.test(#color, #width, #height) {
width: #width;
height: #height;
background: #color;
}
.test(#width, #height) { // <- "no color" specialization
.test(black, #width, #height);
}
Demo.
Also think twice before adding default parameter values for a mixin like:
.test(#color: black, #width: 100px, #height: 50px) { ...
People tend to overuse this feature while it's rarely really necessary (and only creates an extra code-noise) except some specific use-cases.
I.e. consider if you actually expect your mixin to be invoked as:
test;
test(blue, 4em);
// etc.
Do you?
It's usually a good idea to start without default parameter values (at least to protect the mixin against accidental misuse), i.e.:
.test(#color, #width, #height) { ...
and add them later only where and when they are necessary.

Eliminate need for & inside less wrapper to prepend to selector without adding space

Here is my code:
.html-default-tag-color {color: #99cdff}
.html_specific-tag-colors() {
.cm-m-xml.cm-tag- {
&img {color: #909}
&table, &th, &td, &tr {color: #099}
&form {color: orange; font-weight: bold}
}
}
... Above used latter in the following mixin ...
Only interested in eliminating "&" in ABOVE
#makeImportant()
{
.HTML {
&.cm-m-xml.cm-tag {.html-default-tag-color};
.html_specific-tag-colors();
}
// important required to override usage in code outside my control
} & { #makeImportant() !important}
Must be done in less -- runs inside Dreamweaver configured less environment.

LESS Variable Interpolation

I'm trying to simplify my CSS even further than I already have with LESS by using functions and variable interpolation. I was completely unaware of variable interpolation until I took a look at Hover.css' less files which is no surprise as to why I'm screwing up now.
I'm working on Reddit to make a flair system and I am encountering problems using variable interpolation.
I am currently using the below as a test:
.flair.flair-one { color: red; }
.flair.flair-two { color: green; }
.flair.flair-three { color: blue; }
.custom(#a; #b; #c) {
&::before { .flair.flair-#{a}; }
.flair.flair-#{b};
&::after { .flair.flair-#{c}; }
}
.this-flair {
.custom(one; two; three);
}
That's the basic structure of what I'm doing. While testing in online compilers, .this-flair isn't working.
Is someone able to tell me what I can do to resolve this? I'm looking through the LESS functions and it appears as though this is the correct way to do it.
As mentioned in comments above you can't interpolate either mixin or function calls. In a quick glance, parametric mixins (with pattern matching) are what you actually need to use for such snippets:
.flair-flair(one) {color: red}
.flair-flair(two) {color: green}
.flair-flair(three) {color: blue}
.custom(#a, #b, #c) {
.flair-flair(#b);
&::before {.flair-flair(#a)}
&::after {.flair-flair(#c)}
}
.this-flair {
.custom(one, two, three);
}

Convert SASS map to individual variables [duplicate]

This question already has answers here:
Creating or referencing variables dynamically in Sass
(7 answers)
Closed 7 years ago.
Edit: I've come up with a solution, see my answer below.
Is there a way to do this? It is becoming quite cumbersome typing map-get($myArray, myKey). I have an array with dozens of values in, it would be very helpful if I could export them.
So that this:
$map: (
width: 100px,
height: 200px,
color: red,
background: blue
);
.myselector {
width: map-get($map, width);
height: map-get($map, height);
color: map-get($map, color);
background: map-get($map, background);
}
Becomes this:
$map: (
width: 100px,
height: 200px,
color: red,
background: blue
);
/* some function to convert the map to vars */
.myselector {
width: $width;
height: $height;
color: $color;
background:$background;
}
Please note that the example I have given is purely arbitrary.
Update: Ok, I've come up with a crafty half-fix. (Although this will be obvious to any discerning SCSS journeyman...)
As long as the elements you are trying to get are from the same array, you can always take advantage of the javascript style scope inheritance, and write a function with a short name that will pluck the element with the specified key from your array.
In reference to the example I gave originally:
#function g($key) {
#return array-get($map, $key);
}
.myselector {
width: g(width);
height: g(height);
color: g(color);
background: g(background);
}
For a single array with dozens of elements that you have to access frequently, it has the desired effect, and actually gives a feeling of the more convenient PHP style array syntax. i.e. instead of $g['width'] you use g(width)
$map: (
width: 100px,
height: 200px,
color: red,
background: blue
);
.myselector {
#each $prop, $val in $map {
#{$prop} : $val;
}
}
You can use #each. In the above #each loop, i'm cycling over each key/value pair in $map, assigning the key to $prop and the value to $val.
If you want, you can make a mixin (for example):
#mixin create-props($array) {
#each $prop, $val in $array {
#{$prop} : $val;
}
}
.myselector {
#include create-props($map);
}

Is there any (good) way to extend a class within a mixin, and then use that mixin within a media query, using Less?

I've been working on building out some Less files to help speed up my CSS workflow, and also to help produce more efficient, cleaner CSS.
The way I see it:
Mixins are a great way to help speed up the workflow, but they have the drawback of potentially making the outputted CSS longer than necessary.
Extending classes is the ideal solution for ensuring the amount of duplicate style declarations is minimized, helping clean that up...
So, to help balance things out I wrote out a set of standard, commonly used styles, using dummy classes (they are stored in a file which is imported by reference, so the styles are only output if they get extended).
I set all of my Mixins to extend these classes wherever possible, which worked great for the most part.
However, I realized my pitfall once I got to my media queries... I can't extend those classes within the media query, which would be fine normally, I would just remember not to do so.. But since the Mixins also now use my extends, I can now no longer use them inside media queries either.
I'm not willing to avoid using the Mixins inside of the media queries because of this, but I'd really love to be able to find a way to keep extending classes within them to keep my output as clean as possible.
The only idea I've thought of so far is to add an extra parameter to every Mixin to specify wether it should extend or not, but that's less than ideal.
My hope is that someone can come up with a much more clever solution, that would allow me to maintain the benefit of Mixins which extend base style classes, but also maintain easy usability, without over complicating things. Might be a tall order, but here's hoping.
In case my explanation was hard to follow, this is what I would have hoped to be able to do, but is not currently possible:
Ideal Input
// extensions.less
.block {
display: block;
}
// mixins.less
#import (reference) "extensions";
.mixin {
&:extend(.block);
margin: auto;
}
// styles.less
#import "mixins";
.element1 {
.mixin();
}
.element2 {
.mixin();
}
#media only screen and (max-width: 768px) {
.element3 {
.mixin();
}
.element4 {
.mixin();
}
}
Ideal Output
// styles.css
.element1, .element2 {
display: block;
}
.element1 {
margin: auto;
}
.element2 {
margin: auto;
}
#media only screen and (max-width: 768px) {
.element3, .element4 {
display: block;
}
.element3 {
margin: auto;
}
.element4 {
margin: auto;
}
}
In short, yes, currently it is somewhat possible but requires some additional wrapping for a top level classes:
// extensions.less
.block {
display: block;
}
// mixins.less
#import (reference) "extensions";
.mixin() {
&:extend(.block);
margin: auto;
}
// styles.less
#media all { // !
#import "mixins";
.element1 {
.mixin();
}
.element2 {
.mixin();
}
}
#media only screen and (max-width: 768px) {
#import (multiple) "mixins";
.element3 {
.mixin();
}
.element4 {
.mixin();
}
}
.element1 and .element2 (and any other class to extend .block) have to be put into #media all because currently:
Top level extend matches everything including selectors inside nested media
So if .element1 and .element2 stay in the global scope they leak into every other #media .block declaration.
(Hmm, actually for me this "top level extend matches everything" thing looks questionable and contradicts another "extend inside a media declaration should match only selectors inside the same media declaration" rule (obviously because global scope = #media all thus they should work identically)).