How can we do operations with :root variables (css vars) in LESS? - less

I´m trying to make operations with the root variables using less.
For example
:root{
--padding-md: 5px;
}
#padding-md: ~'var(--padding-md)'; // we get the CSS var
#padding-double: #padding-md + 5px; //we try to add 5px
Or this
#padding-md: calc(5px + 3px) + 5px; // we get the CSS var
But LESS just throw the op
Is this possible? How to do that?
there is a way to tell to LESS set the CSS CALC function instead make the operations without affect the default less operations?

Related

2 Less Parameter with one being null by default

Hey I have 2 sets of icon styles. Black and White
settings-icon-white.png or settings-icon.png
Now I am using a Less mixin which takes a text parameter:
//The mixin
.icon-finder(#url){
background-image: url("../images/icons/backend/#{url}-icon.png");
background-size: cover;
}
//generated class:login-icon.png
.icon-login{
.icon-finder(login);
}
Now the challenge is that I want to also have an option to select a white icon if the parameter gets passed a white. Is there a way to have a default null parameter, but can be used if need be?
So for example:
.icon-finder(#url,#white){
background-image: url("../images/icons/backend/#{url}-icon#{white}.png");
background-position: center center;
}
But I don't want white the whole time, so can this be null? #white = "" I did see this #_ being used before - is that right?
So the code would be like:
.icon-admin{
.icon-finder(admin);
}
.icon-admin-white{
.icon-finder(admin,white);
}
Am I missing something? Thanks in advance!
Yes, you can set a default value to a mixin argument by just specifying it in the mixin declaration like in the below code block. The #white: '' part means that the mixin will take the value for #white as an empty string when no value is provided in the call.
.icon-finder(#url,#white: ''){
background-image: url("../images/icons/backend/#{url}-icon#{white}.png");
background-position: center center;
}
.icon-admin{
.icon-finder(admin);
}
.icon-admin-white{
.icon-finder(admin,white);
}
There is no need to use the #_ syntax that is mentioned in the link.
Note that if you are writing something like a mixin library and want to restrict the values for the second parameter to white or nothing (the above mixin allows you to send any value for second param), then you could use one of the following options also:
Option 1: Two separate mixins, one with a hard-coded white value (note that it is not a variable) and another with only one parameter. This way if the user tries to pass any other value it will be rejected.
.icon-finder(#url,white) {
background-image: url("../images/icons/backend/#{url}-iconwhite.png");
background-position: center center;
}
.icon-finder(#url){
background-image: url("../images/icons/backend/#{url}-icon.png");
background-position: center center;
}
.icon-admin{
.icon-finder(admin);
}
.icon-admin-white{
.icon-finder(admin,white);
}
Option 2: Using guards and checking if the value is white or not. If it is then use the white background image, else use the default.
.icon-finder(#url,#white: '') {
& when (#white = white){
background-image: url("../images/icons/backend/#{url}-iconwhite.png");
background-position: center center;
}
& when not (#white = white){
background-image: url("../images/icons/backend/#{url}-icon.png");
background-position: center center;
}
}
.icon-admin{
.icon-finder(admin);
}
.icon-admin-white{
.icon-finder(admin,white);
}
The advantage of the first option is that if any value other than white is given, the compiler would throw an error and alert the user that a wrong value is provided whereas the second one will silently switch to the default.

Is it possible to manipulate css variables using LESS?

With preprocessor variables it's easy to set up one variable and manipulate it so that I can use it to set multiple properties. (demo)
While experimenting with native css variables, I noticed that I could combine them with preprocessor variables, so in the following example: (use firefox)
h1 {
--length: 40px;
#length: var(--length);
line-height: #length;
border: 5px solid tomato;
}
line-height was correctly rendered at 40px
But, when I tried to manipulate the preprocessor variable - like this:
h1 {
--length: 40px;
#length: var(--length);
#length2: #length*2;
line-height: #length;
padding: #length2;
border: 5px solid tomato;
}
... the code failed.
Is this possible somehow?
As mentioned in my comment, my understanding of CSS variables is that the variable is resolved into its actual value by the UA. This happens after the Less compiler compiles the file and thus it wouldn't be aware of what is the actual value contained by the CSS variable.
To the compiler, the value of #length is only var(--length). Since this is not a number, an error is thrown during compilation indicating that the math operation is being done on an invalid type.
OperationError: Operation on an invalid type on line 4, column 3:
One way to fix this would be to make the Less compiler output the variable name as it is and have the multiplier appended to it (like string concatenation). This would then leave the control to the UA.
But since all CSS math operations have to be given within calc() function, the entire thing has to be wrapped within it. So, the below code would work fine.
h1 {
--length: 40px;
#length: var(--length);
#length2: ~"calc(#{length} * 2)";
line-height: #length;
padding: #length2;
border: 5px solid tomato;
}
Or, even the below would be enough if --strict-math is enabled during compilation:
h1 {
--length: 40px;
#length: var(--length);
#length2: calc(#length * 2);
line-height: #length;
padding: #length2;
border: 5px solid tomato;
}
Above code when compiled produces an output similar to the one in Example 11 of the specs and so it should be a reasonably good way of doing this :)
... Note, though, that calc() can be used to validly achieve the same thing, like so:
.foo {
--gap: 20;
margin-top: calc(var(--gap) * 1px);
}
var() functions are substituted at computed-value time...

Is there a way to add a mixin into a variable in LESS

Can I add a mixin to a variable in LESS?
Something like this
#input-border-radius: .rounded();
or
#h1: .font-size(46) // This pulls from the rem calculator mixin.
Looked at the LESS Docs but can't see a way to do it.
There is a way.
You can define properties of a (possibly immaginary) class and recall the properties of that class in the style of a different class. For example:
.fontstyling {
font-weight: bold;
color: black;
}
h1 {
font-size: 46px;
.fontstyling;
}
h2 {
font-size: 38px;
.fontstyling;
}
(thats not the best way to format the headings - but for other exemples it is really useful!)

Include a less file and pass parameters

I have a common.less file, that implements the basic CSS for different skins:
#textColor: black;
#iconSize: 16px;
.container: {
color: #textColor;
background-color: white;
}
.icon: {
width: #iconSize;
height: #iconSize;
}
// note that #iconSize is also used in this file inside mixins
The plan is to use it like so skin_1.less:
#iconSize: 32px; // override the icon size
// but leave #textColor as default
#import "common.less";
.container: {
color: red;
}
// I would now have big icons and red text
So I would like to have a common style, that I can reuse and selectively override variables.
This does not ssem to work however. I think it's because imports are always moved to the top, so variables cannot be pre-defined.
(I also read that variables are rather constants, so that may be another problem.)
Anyway: is there a better pattern to solve my use case?
You don't need to split the files up, just override the variable after the import. Variables are always resolved as the last definition, even if it is after where it is used.

LESS CSS guards without mixin

I'm just getting into LESS and am trying to figure out how I can make conditional css statements without mixins. I find that I have a lot of single line css statements that only occur once but are dependent on some variable or condition and that using mixins is a bit pointless since it will never be reused.
Example.
#add-margin: true;
body {
margin-top: 20px; //I only want this if add-margin is true
}
So ideally I want this:
body when (#add-margin) {
margin-top: 20px;
}
But that doesn't work. Using a mixin works but seems silly to make one just for a one liner. Is there some alternative way I can do this?
Thanks
yes you can, it's similar to your code.
#add-margin: true;
.margin() when (#add-margin) {
margin-top: 20px;
}
body { .margin(); }
UPDATE: Using the latest versions of LESS (1.5+), usage of "guarded mixins" are not required to achieve this, and you could use "css gaurds" instead, therefore the OP's code will work out of the box
CSS Guards feature was introduced in Less v1.5.0 and hence now we can use guards the same way as mentioned in the question.
#add-margin: true;
body when (#add-margin){
margin-top: 20px;
}
If in case, you need to assign multiple such properties to different selectors based on the same variable, it can be implemented like below using the & selector.
& when (#add-margin){
body{
margin-top: 20px;
}
h1{
margin-top: 10px;
}
}
Note: As mentioned by memeLab in comments, any value for the #add-margin variable other than true are considered as falsy. This is because true is a keyword whereas 'true' is a String value. For example, the below would output nothing.
#add-margin: 'true';
body when (#add-margin){
margin-top: 20px;
}
However, the below would work because it does a String comparison.
#add-margin: 'true';
body when (#add-margin = 'true'){
margin-top: 20px;
}
If you are using Less compiler lower than v1.5.0 then the answer posted by Unicornist is the best bet.
no, it is not possible in that form.
you could use a variable equal to 0 or 1 and multiply by 20 and then always output a rule, or use JavaScript (i would advise you to avoid this) to convert true to 0 or 20 and always output a rule, but if you want the property added conditionally, you need guards.